From 7e6735c3578e76c270a2797225a4214176ba13ef Mon Sep 17 00:00:00 2001 From: Cyril Chemparathy Date: Wed, 12 Sep 2012 14:05:58 -0400 Subject: /dev/mem: use phys_addr_t for physical addresses This patch fixes the /dev/mem driver to use phys_addr_t for physical addresses. This is required on PAE systems, especially those that run entirely out of >4G physical memory space. Signed-off-by: Cyril Chemparathy Signed-off-by: Greg Kroah-Hartman diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h index 35c1ed8..f52a93d 100644 --- a/arch/arm/include/asm/io.h +++ b/arch/arm/include/asm/io.h @@ -374,7 +374,7 @@ extern void pci_iounmap(struct pci_dev *dev, void __iomem *addr); #ifdef CONFIG_MMU #define ARCH_HAS_VALID_PHYS_ADDR_RANGE -extern int valid_phys_addr_range(unsigned long addr, size_t size); +extern int valid_phys_addr_range(phys_addr_t addr, size_t size); extern int valid_mmap_phys_addr_range(unsigned long pfn, size_t size); extern int devmem_is_allowed(unsigned long pfn); #endif diff --git a/arch/arm/mm/mmap.c b/arch/arm/mm/mmap.c index ce8cb19..89f2b7f 100644 --- a/arch/arm/mm/mmap.c +++ b/arch/arm/mm/mmap.c @@ -279,7 +279,7 @@ void arch_pick_mmap_layout(struct mm_struct *mm) * You really shouldn't be using read() or write() on /dev/mem. This * might go away in the future. */ -int valid_phys_addr_range(unsigned long addr, size_t size) +int valid_phys_addr_range(phys_addr_t addr, size_t size) { if (addr < PHYS_OFFSET) return 0; diff --git a/arch/ia64/include/asm/io.h b/arch/ia64/include/asm/io.h index 2c26321..74a7cc3 100644 --- a/arch/ia64/include/asm/io.h +++ b/arch/ia64/include/asm/io.h @@ -90,7 +90,7 @@ phys_to_virt (unsigned long address) #define ARCH_HAS_VALID_PHYS_ADDR_RANGE extern u64 kern_mem_attribute (unsigned long phys_addr, unsigned long size); -extern int valid_phys_addr_range (unsigned long addr, size_t count); /* efi.c */ +extern int valid_phys_addr_range (phys_addr_t addr, size_t count); /* efi.c */ extern int valid_mmap_phys_addr_range (unsigned long pfn, size_t count); /* diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c index d37bbd4..f034563 100644 --- a/arch/ia64/kernel/efi.c +++ b/arch/ia64/kernel/efi.c @@ -870,7 +870,7 @@ kern_mem_attribute (unsigned long phys_addr, unsigned long size) EXPORT_SYMBOL(kern_mem_attribute); int -valid_phys_addr_range (unsigned long phys_addr, unsigned long size) +valid_phys_addr_range (phys_addr_t phys_addr, unsigned long size) { u64 attr; diff --git a/arch/sh/include/asm/io.h b/arch/sh/include/asm/io.h index 73a23f4..629db2a 100644 --- a/arch/sh/include/asm/io.h +++ b/arch/sh/include/asm/io.h @@ -382,7 +382,7 @@ static inline int iounmap_fixed(void __iomem *addr) { return -EINVAL; } #define xlate_dev_kmem_ptr(p) p #define ARCH_HAS_VALID_PHYS_ADDR_RANGE -int valid_phys_addr_range(unsigned long addr, size_t size); +int valid_phys_addr_range(phys_addr_t addr, size_t size); int valid_mmap_phys_addr_range(unsigned long pfn, size_t size); #endif /* __KERNEL__ */ diff --git a/arch/sh/mm/mmap.c b/arch/sh/mm/mmap.c index afeb710..80bf494 100644 --- a/arch/sh/mm/mmap.c +++ b/arch/sh/mm/mmap.c @@ -238,7 +238,7 @@ bottomup: * You really shouldn't be using read() or write() on /dev/mem. This * might go away in the future. */ -int valid_phys_addr_range(unsigned long addr, size_t count) +int valid_phys_addr_range(phys_addr_t addr, size_t count) { if (addr < __MEMORY_START) return 0; diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 0537903..c6fa3bc 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -48,7 +48,7 @@ static inline unsigned long size_inside_page(unsigned long start, } #ifndef ARCH_HAS_VALID_PHYS_ADDR_RANGE -static inline int valid_phys_addr_range(unsigned long addr, size_t count) +static inline int valid_phys_addr_range(phys_addr_t addr, size_t count) { return addr + count <= __pa(high_memory); } @@ -96,7 +96,7 @@ void __weak unxlate_dev_mem_ptr(unsigned long phys, void *addr) static ssize_t read_mem(struct file *file, char __user *buf, size_t count, loff_t *ppos) { - unsigned long p = *ppos; + phys_addr_t p = *ppos; ssize_t read, sz; char *ptr; @@ -153,7 +153,7 @@ static ssize_t read_mem(struct file *file, char __user *buf, static ssize_t write_mem(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - unsigned long p = *ppos; + phys_addr_t p = *ppos; ssize_t written, sz; unsigned long copied; void *ptr; @@ -226,7 +226,7 @@ int __weak phys_mem_access_prot_allowed(struct file *file, * */ #ifdef pgprot_noncached -static int uncached_access(struct file *file, unsigned long addr) +static int uncached_access(struct file *file, phys_addr_t addr) { #if defined(CONFIG_IA64) /* @@ -258,7 +258,7 @@ static pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, unsigned long size, pgprot_t vma_prot) { #ifdef pgprot_noncached - unsigned long offset = pfn << PAGE_SHIFT; + phys_addr_t offset = pfn << PAGE_SHIFT; if (uncached_access(file, offset)) return pgprot_noncached(vma_prot); -- cgit v0.10.2 From ebb108ef93605a68f6f38d5eb407e7d5138e8028 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 9 Oct 2012 16:50:16 +0200 Subject: mei: rename mei_cl_cb.information to mei_cl_cb.buf_idx rename 'information' member of the struct mei_cl_cb to more self-descriptive 'buf_idx' Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 3533edd..320ebd2 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -149,7 +149,7 @@ static int mei_irq_thread_read_amthi_message(struct mei_io_list *complete_list, return -ENODEV; dev->iamthif_stall_timer = 0; - cb->information = dev->iamthif_msg_buf_index; + cb->buf_idx = dev->iamthif_msg_buf_index; cb->read_time = jiffies; if (dev->iamthif_ioctl && cl == &dev->iamthif_cl) { /* found the iamthif cb */ @@ -205,10 +205,10 @@ static int mei_irq_thread_read_client_message(struct mei_io_list *complete_list, cl = (struct mei_cl *)cb_pos->file_private; if (cl && _mei_irq_thread_state_ok(cl, mei_hdr)) { cl->reading_state = MEI_READING; - buffer = cb_pos->response_buffer.data + cb_pos->information; + buffer = cb_pos->response_buffer.data + cb_pos->buf_idx; if (cb_pos->response_buffer.size < - mei_hdr->length + cb_pos->information) { + mei_hdr->length + cb_pos->buf_idx) { dev_dbg(&dev->pdev->dev, "message overflow.\n"); list_del(&cb_pos->cb_list); return -ENOMEM; @@ -216,7 +216,7 @@ static int mei_irq_thread_read_client_message(struct mei_io_list *complete_list, if (buffer) mei_read_slots(dev, buffer, mei_hdr->length); - cb_pos->information += mei_hdr->length; + cb_pos->buf_idx += mei_hdr->length; if (mei_hdr->msg_complete) { cl->status = 0; list_del(&cb_pos->cb_list); @@ -224,7 +224,8 @@ static int mei_irq_thread_read_client_message(struct mei_io_list *complete_list, "completed read H cl = %d, ME cl = %d, length = %lu\n", cl->host_client_id, cl->me_client_id, - cb_pos->information); + cb_pos->buf_idx); + list_add_tail(&cb_pos->cb_list, &complete_list->mei_cb.cb_list); } @@ -300,14 +301,14 @@ static int _mei_irq_thread_close(struct mei_device *dev, s32 *slots, if (mei_disconnect(dev, cl)) { cl->status = 0; - cb_pos->information = 0; + cb_pos->buf_idx = 0; list_move_tail(&cb_pos->cb_list, &cmpl_list->mei_cb.cb_list); return -EMSGSIZE; } else { cl->state = MEI_FILE_DISCONNECTING; cl->status = 0; - cb_pos->information = 0; + cb_pos->buf_idx = 0; list_move_tail(&cb_pos->cb_list, &dev->ctrl_rd_list.mei_cb.cb_list); cl->timer_count = MEI_CONNECT_TIMEOUT; @@ -834,7 +835,7 @@ static int _mei_irq_thread_read(struct mei_device *dev, s32 *slots, if (mei_send_flow_control(dev, cl)) { cl->status = -ENODEV; - cb_pos->information = 0; + cb_pos->buf_idx = 0; list_move_tail(&cb_pos->cb_list, &cmpl_list->mei_cb.cb_list); return -ENODEV; } @@ -871,7 +872,7 @@ static int _mei_irq_thread_ioctl(struct mei_device *dev, s32 *slots, *slots -= mei_data2slots(sizeof(struct hbm_client_connect_request)); if (mei_connect(dev, cl)) { cl->status = -ENODEV; - cb_pos->information = 0; + cb_pos->buf_idx = 0; list_del(&cb_pos->cb_list); return -ENODEV; } else { @@ -901,28 +902,26 @@ static int _mei_irq_thread_cmpl(struct mei_device *dev, s32 *slots, struct mei_msg_hdr *mei_hdr; if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) + - (cb_pos->request_buffer.size - - cb_pos->information))) { + (cb_pos->request_buffer.size - cb_pos->buf_idx))) { mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; mei_hdr->host_addr = cl->host_client_id; mei_hdr->me_addr = cl->me_client_id; - mei_hdr->length = cb_pos->request_buffer.size - - cb_pos->information; + mei_hdr->length = cb_pos->request_buffer.size - cb_pos->buf_idx; mei_hdr->msg_complete = 1; mei_hdr->reserved = 0; dev_dbg(&dev->pdev->dev, "cb_pos->request_buffer.size =%d" "mei_hdr->msg_complete = %d\n", cb_pos->request_buffer.size, mei_hdr->msg_complete); - dev_dbg(&dev->pdev->dev, "cb_pos->information =%lu\n", - cb_pos->information); + dev_dbg(&dev->pdev->dev, "cb_pos->buf_idx =%lu\n", + cb_pos->buf_idx); dev_dbg(&dev->pdev->dev, "mei_hdr->length =%d\n", mei_hdr->length); *slots -= mei_data2slots(mei_hdr->length); if (mei_write_message(dev, mei_hdr, (unsigned char *) (cb_pos->request_buffer.data + - cb_pos->information), + cb_pos->buf_idx), mei_hdr->length)) { cl->status = -ENODEV; list_move_tail(&cb_pos->cb_list, @@ -932,7 +931,7 @@ static int _mei_irq_thread_cmpl(struct mei_device *dev, s32 *slots, if (mei_flow_ctrl_reduce(dev, cl)) return -ENODEV; cl->status = 0; - cb_pos->information += mei_hdr->length; + cb_pos->buf_idx += mei_hdr->length; list_move_tail(&cb_pos->cb_list, &dev->write_waiting_list.mei_cb.cb_list); } @@ -949,21 +948,21 @@ static int _mei_irq_thread_cmpl(struct mei_device *dev, s32 *slots, if (mei_write_message(dev, mei_hdr, (unsigned char *) (cb_pos->request_buffer.data + - cb_pos->information), + cb_pos->buf_idx), mei_hdr->length)) { cl->status = -ENODEV; list_move_tail(&cb_pos->cb_list, &cmpl_list->mei_cb.cb_list); return -ENODEV; } else { - cb_pos->information += mei_hdr->length; + cb_pos->buf_idx += mei_hdr->length; dev_dbg(&dev->pdev->dev, "cb_pos->request_buffer.size =%d" " mei_hdr->msg_complete = %d\n", cb_pos->request_buffer.size, mei_hdr->msg_complete); - dev_dbg(&dev->pdev->dev, "cb_pos->information =%lu\n", - cb_pos->information); + dev_dbg(&dev->pdev->dev, "cb_pos->buf_idx =%lu\n", + cb_pos->buf_idx); dev_dbg(&dev->pdev->dev, "mei_hdr->length =%d\n", mei_hdr->length); } @@ -1018,7 +1017,7 @@ static int _mei_irq_thread_cmpl_iamthif(struct mei_device *dev, s32 *slots, if (mei_flow_ctrl_reduce(dev, cl)) return -ENODEV; dev->iamthif_msg_buf_index += mei_hdr->length; - cb_pos->information = dev->iamthif_msg_buf_index; + cb_pos->buf_idx = dev->iamthif_msg_buf_index; cl->status = 0; dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL; dev->iamthif_flow_control_pending = true; diff --git a/drivers/misc/mei/iorw.c b/drivers/misc/mei/iorw.c index fcba98e..20652e1 100644 --- a/drivers/misc/mei/iorw.c +++ b/drivers/misc/mei/iorw.c @@ -346,9 +346,9 @@ int amthi_read(struct mei_device *dev, struct file *file, } } /* if the whole message will fit remove it from the list */ - if (cb->information >= *offset && length >= (cb->information - *offset)) + if (cb->buf_idx >= *offset && length >= (cb->buf_idx - *offset)) list_del(&cb->cb_list); - else if (cb->information > 0 && cb->information <= *offset) { + else if (cb->buf_idx > 0 && cb->buf_idx <= *offset) { /* end of the message has been reached */ list_del(&cb->cb_list); rets = 0; @@ -360,18 +360,17 @@ int amthi_read(struct mei_device *dev, struct file *file, dev_dbg(&dev->pdev->dev, "amthi cb->response_buffer size - %d\n", cb->response_buffer.size); - dev_dbg(&dev->pdev->dev, "amthi cb->information - %lu\n", - cb->information); + dev_dbg(&dev->pdev->dev, "amthi cb->buf_idx - %lu\n", cb->buf_idx); /* length is being turncated to PAGE_SIZE, however, - * the information may be longer */ - length = min_t(size_t, length, (cb->information - *offset)); + * the buf_idx may point beyond */ + length = min_t(size_t, length, (cb->buf_idx - *offset)); if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length)) rets = -EFAULT; else { rets = length; - if ((*offset + length) < cb->information) { + if ((*offset + length) < cb->buf_idx) { *offset += length; goto out; } @@ -432,8 +431,8 @@ int mei_start_read(struct mei_device *dev, struct mei_cl *cl) } dev_dbg(&dev->pdev->dev, "allocation call back data success.\n"); cb->major_file_operations = MEI_READ; - /* make sure information is zero before we start */ - cb->information = 0; + /* make sure buffer index is zero before we start */ + cb->buf_idx = 0; cb->file_private = (void *) cl; cl->read_cb = cb; if (dev->mei_host_buffer_is_empty) { diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index e8b0858..3d4f6d1 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -415,16 +415,15 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, goto out; } - if (cl->read_cb && cl->read_cb->information > *offset) { + if (cl->read_cb && cl->read_cb->buf_idx > *offset) { cb = cl->read_cb; goto copy_buffer; - } else if (cl->read_cb && cl->read_cb->information > 0 && - cl->read_cb->information <= *offset) { + } else if (cl->read_cb && cl->read_cb->buf_idx > 0 && + cl->read_cb->buf_idx <= *offset) { cb = cl->read_cb; rets = 0; goto free; - } else if ((!cl->read_cb || !cl->read_cb->information) && - *offset > 0) { + } else if ((!cl->read_cb || !cl->read_cb->buf_idx) && *offset > 0) { /*Offset needs to be cleaned for contiguous reads*/ *offset = 0; rets = 0; @@ -481,16 +480,15 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, copy_buffer: dev_dbg(&dev->pdev->dev, "cb->response_buffer size - %d\n", cb->response_buffer.size); - dev_dbg(&dev->pdev->dev, "cb->information - %lu\n", - cb->information); - if (length == 0 || ubuf == NULL || *offset > cb->information) { + dev_dbg(&dev->pdev->dev, "cb->buf_idx - %lu\n", cb->buf_idx); + if (length == 0 || ubuf == NULL || *offset > cb->buf_idx) { rets = -EMSGSIZE; goto free; } - /* length is being truncated to PAGE_SIZE, however, */ - /* information size may be longer */ - length = min_t(size_t, length, (cb->information - *offset)); + /* length is being truncated to PAGE_SIZE, + * however buf_idx may point beyond that */ + length = min_t(size_t, length, cb->buf_idx - *offset); if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length)) { rets = -EFAULT; @@ -499,7 +497,7 @@ copy_buffer: rets = length; *offset += length; - if ((unsigned long)*offset < cb->information) + if ((unsigned long)*offset < cb->buf_idx) goto out; free: @@ -637,7 +635,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, write_cb->response_buffer.size = dev->iamthif_mtu; write_cb->major_file_operations = MEI_IOCTL; - write_cb->information = 0; + write_cb->buf_idx = 0; write_cb->request_buffer.size = length; if (dev->iamthif_cl.state != MEI_FILE_CONNECTED) { rets = -ENODEV; @@ -668,9 +666,8 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, } write_cb->major_file_operations = MEI_WRITE; - /* make sure information is zero before we start */ - - write_cb->information = 0; + /* make sure buffer index is zero before we start */ + write_cb->buf_idx = 0; write_cb->request_buffer.size = length; dev_dbg(&dev->pdev->dev, "host client = %d, ME client = %d\n", @@ -719,7 +716,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, goto unlock_dev; } cl->writing_state = MEI_WRITING; - write_cb->information = mei_hdr.length; + write_cb->buf_idx = mei_hdr.length; if (mei_hdr.msg_complete) { if (mei_flow_ctrl_reduce(dev, cl)) { rets = -ENODEV; @@ -734,7 +731,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, } else { - write_cb->information = 0; + write_cb->buf_idx = 0; cl->writing_state = MEI_WRITING; list_add_tail(&write_cb->cb_list, &dev->write_list.mei_cb.cb_list); diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index adb35fb..c58b6fa 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -149,7 +149,7 @@ struct mei_cl_cb { void *file_private; struct mei_message_data request_buffer; struct mei_message_data response_buffer; - unsigned long information; + unsigned long buf_idx; unsigned long read_time; struct file *file_object; }; -- cgit v0.10.2 From 33d28c9205257479be540a31b03339817cf2d62c Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 9 Oct 2012 16:50:17 +0200 Subject: mei: add allocation and initialization wrappers for io callback mei_io_cb_init - allocat and initializate mei_cl_cb mei_io_cb_alloc_req/resp_buf are separate function as buffers are not always needed Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 3d4f6d1..15de4b1 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -516,6 +516,83 @@ out: } /** + * mei_io_cb_init - allocate and initialize io callback + * + * @cl - mei client + * @file: pointer to file structure + * + * returns mei_cl_cb pointer or NULL; + */ +static struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp) +{ + struct mei_cl_cb *cb; + struct mei_device *dev; + + dev = cl->dev; + + cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL); + if (!cb) + return NULL; + + INIT_LIST_HEAD(&cb->cb_list); + + cb->file_object = fp; + cb->file_private = cl; + cb->buf_idx = 0; + return cb; +} + + +/** + * mei_io_cb_alloc_req_buf - allocate request buffer + * + * @cb - io callback structure + * @size: size of the buffer + * + * returns 0 on success + * -EINVAL if cb is NULL + * -ENOMEM if allocation failed + */ +static int mei_io_cb_alloc_req_buf(struct mei_cl_cb *cb, size_t length) +{ + if (!cb) + return -EINVAL; + + if (length == 0) + return 0; + + cb->request_buffer.data = kmalloc(length, GFP_KERNEL); + if (!cb->request_buffer.data) + return -ENOMEM; + cb->request_buffer.size = length; + return 0; +} +/** + * mei_io_cb_alloc_req_buf - allocate respose buffer + * + * @cb - io callback structure + * @size: size of the buffer + * + * returns 0 on success + * -EINVAL if cb is NULL + * -ENOMEM if allocation failed + */ +static int mei_io_cb_alloc_resp_buf(struct mei_cl_cb *cb, size_t length) +{ + if (!cb) + return -EINVAL; + + if (length == 0) + return 0; + + cb->response_buffer.data = kmalloc(length, GFP_KERNEL); + if (!cb->response_buffer.data) + return -ENOMEM; + cb->response_buffer.size = length; + return 0; +} + +/** * mei_write - the write function. * * @file: pointer to file structure @@ -581,20 +658,17 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, *offset = 0; - write_cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL); + write_cb = mei_io_cb_init(cl, file); if (!write_cb) { - mutex_unlock(&dev->device_lock); - return -ENOMEM; + dev_err(&dev->pdev->dev, "write cb allocation failed\n"); + rets = -ENOMEM; + goto unlock_dev; } - - write_cb->file_object = file; - write_cb->file_private = cl; - write_cb->request_buffer.data = kmalloc(length, GFP_KERNEL); - rets = -ENOMEM; - if (!write_cb->request_buffer.data) + rets = mei_io_cb_alloc_req_buf(write_cb, length); + if (rets) goto unlock_dev; - dev_dbg(&dev->pdev->dev, "length =%d\n", (int) length); + dev_dbg(&dev->pdev->dev, "cb request size = %zd\n", length); rets = -EFAULT; if (copy_from_user(write_cb->request_buffer.data, ubuf, length)) @@ -610,14 +684,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, write_cb->request_buffer.data, 4) == 0))) cl->sm_state |= MEI_WD_STATE_INDEPENDENCE_MSG_SENT; - INIT_LIST_HEAD(&write_cb->cb_list); if (cl == &dev->iamthif_cl) { - write_cb->response_buffer.data = - kmalloc(dev->iamthif_mtu, GFP_KERNEL); - if (!write_cb->response_buffer.data) { - rets = -ENOMEM; - goto unlock_dev; - } if (dev->dev_state != MEI_DEV_ENABLED) { rets = -ENODEV; goto unlock_dev; @@ -632,11 +699,11 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, rets = -EMSGSIZE; goto unlock_dev; } + rets = mei_io_cb_alloc_resp_buf(write_cb, dev->iamthif_mtu); + if (rets) + goto unlock_dev; - write_cb->response_buffer.size = dev->iamthif_mtu; write_cb->major_file_operations = MEI_IOCTL; - write_cb->buf_idx = 0; - write_cb->request_buffer.size = length; if (dev->iamthif_cl.state != MEI_FILE_CONNECTED) { rets = -ENODEV; goto unlock_dev; @@ -666,9 +733,6 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, } write_cb->major_file_operations = MEI_WRITE; - /* make sure buffer index is zero before we start */ - write_cb->buf_idx = 0; - write_cb->request_buffer.size = length; dev_dbg(&dev->pdev->dev, "host client = %d, ME client = %d\n", cl->host_client_id, cl->me_client_id); @@ -688,7 +752,6 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, rets = -EINVAL; goto unlock_dev; } - write_cb->file_private = cl; rets = mei_flow_ctrl_creds(dev, cl); if (rets < 0) -- cgit v0.10.2 From 75f0ee1559c5d51948e029041a9b722b3e3f0b83 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 9 Oct 2012 16:50:18 +0200 Subject: mei: mei_write: revamp error path handling 1. unify common amt and regular error path and use it early in the function 2. fix indentation 3. propagate error code directly from copy_from_user 4. print out errors using dev_err instead of dev_dbg Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 15de4b1..8dcf59d 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -621,10 +621,26 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, mutex_lock(&dev->device_lock); if (dev->dev_state != MEI_DEV_ENABLED) { - mutex_unlock(&dev->device_lock); - return -ENODEV; + rets = -ENODEV; + goto unlock_dev; } + i = mei_me_cl_by_id(dev, cl->me_client_id); + if (i < 0) { + rets = -ENODEV; + goto unlock_dev; + } + if (length > dev->me_clients[i].props.max_msg_length || length <= 0) { + rets = -EMSGSIZE; + goto unlock_dev; + } + + if (cl->state != MEI_FILE_CONNECTED) { + rets = -ENODEV; + dev_err(&dev->pdev->dev, "host client = %d, is not connected to ME client = %d", + cl->host_client_id, cl->me_client_id); + goto unlock_dev; + } if (cl == &dev->iamthif_cl) { write_cb = find_amthi_read_list_entry(dev, file); @@ -633,11 +649,11 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, msecs_to_jiffies(IAMTHIF_READ_TIMER); if (time_after(jiffies, timeout) || - cl->reading_state == MEI_READ_COMPLETE) { - *offset = 0; - list_del(&write_cb->cb_list); - mei_free_cb_private(write_cb); - write_cb = NULL; + cl->reading_state == MEI_READ_COMPLETE) { + *offset = 0; + list_del(&write_cb->cb_list); + mei_free_cb_private(write_cb); + write_cb = NULL; } } } @@ -670,8 +686,8 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, dev_dbg(&dev->pdev->dev, "cb request size = %zd\n", length); - rets = -EFAULT; - if (copy_from_user(write_cb->request_buffer.data, ubuf, length)) + rets = copy_from_user(write_cb->request_buffer.data, ubuf, length); + if (rets) goto unlock_dev; cl->sm_state = 0; @@ -685,29 +701,11 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, cl->sm_state |= MEI_WD_STATE_INDEPENDENCE_MSG_SENT; if (cl == &dev->iamthif_cl) { - if (dev->dev_state != MEI_DEV_ENABLED) { - rets = -ENODEV; - goto unlock_dev; - } - i = mei_me_cl_by_id(dev, dev->iamthif_cl.me_client_id); - if (i < 0) { - rets = -ENODEV; - goto unlock_dev; - } - if (length > dev->me_clients[i].props.max_msg_length || - length <= 0) { - rets = -EMSGSIZE; - goto unlock_dev; - } rets = mei_io_cb_alloc_resp_buf(write_cb, dev->iamthif_mtu); if (rets) goto unlock_dev; write_cb->major_file_operations = MEI_IOCTL; - if (dev->iamthif_cl.state != MEI_FILE_CONNECTED) { - rets = -ENODEV; - goto unlock_dev; - } if (!list_empty(&dev->amthi_cmd_list.mei_cb.cb_list) || dev->iamthif_state != MEI_IAMTHIF_IDLE) { @@ -716,43 +714,24 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, dev_dbg(&dev->pdev->dev, "add amthi cb to amthi cmd waiting list\n"); list_add_tail(&write_cb->cb_list, &dev->amthi_cmd_list.mei_cb.cb_list); - rets = length; } else { dev_dbg(&dev->pdev->dev, "call amthi write\n"); rets = amthi_write(dev, write_cb); if (rets) { - dev_dbg(&dev->pdev->dev, "amthi write failed with status = %d\n", + dev_err(&dev->pdev->dev, "amthi write failed with status = %d\n", rets); goto unlock_dev; } - rets = length; } mutex_unlock(&dev->device_lock); - return rets; + return length; } write_cb->major_file_operations = MEI_WRITE; dev_dbg(&dev->pdev->dev, "host client = %d, ME client = %d\n", cl->host_client_id, cl->me_client_id); - if (cl->state != MEI_FILE_CONNECTED) { - rets = -ENODEV; - dev_dbg(&dev->pdev->dev, "host client = %d, is not connected to ME client = %d", - cl->host_client_id, - cl->me_client_id); - goto unlock_dev; - } - i = mei_me_cl_by_id(dev, cl->me_client_id); - if (i < 0) { - rets = -ENODEV; - goto unlock_dev; - } - if (length > dev->me_clients[i].props.max_msg_length || length <= 0) { - rets = -EINVAL; - goto unlock_dev; - } - rets = mei_flow_ctrl_creds(dev, cl); if (rets < 0) goto unlock_dev; -- cgit v0.10.2 From fb601adb350f82738210c0a1dc6af928a15391db Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Mon, 15 Oct 2012 12:06:48 +0200 Subject: mei: kill usless struct mei_io_list kill useless mei_io_list list wrapper and use directly struct mei_cl_cb mei_cb which was its only member for managing io queues Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index 98f1430..2275cf0 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c @@ -48,34 +48,22 @@ const uuid_le mei_amthi_guid = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, 0xac, 0x81, 0x4c); /** - * mei_io_list_init - Sets up a queue list. - * - * @list: An instance io list structure - * @dev: the device structure - */ -void mei_io_list_init(struct mei_io_list *list) -{ - /* initialize our queue list */ - INIT_LIST_HEAD(&list->mei_cb.cb_list); -} - -/** * mei_io_list_flush - removes list entry belonging to cl. * * @list: An instance of our list structure * @cl: private data of the file object */ -void mei_io_list_flush(struct mei_io_list *list, struct mei_cl *cl) +void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl) { struct mei_cl_cb *pos; struct mei_cl_cb *next; - list_for_each_entry_safe(pos, next, &list->mei_cb.cb_list, cb_list) { + list_for_each_entry_safe(pos, next, &list->list, list) { if (pos->file_private) { struct mei_cl *cl_tmp; cl_tmp = (struct mei_cl *)pos->file_private; if (mei_cl_cmp_id(cl, cl_tmp)) - list_del(&pos->cb_list); + list_del(&pos->list); } } } @@ -351,9 +339,8 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled) } } /* remove all waiting requests */ - list_for_each_entry_safe(cb_pos, cb_next, - &dev->write_list.mei_cb.cb_list, cb_list) { - list_del(&cb_pos->cb_list); + list_for_each_entry_safe(cb_pos, cb_next, &dev->write_list.list, list) { + list_del(&cb_pos->list); mei_free_cb_private(cb_pos); } } @@ -685,7 +672,7 @@ int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl) if (!cb) return -ENOMEM; - INIT_LIST_HEAD(&cb->cb_list); + mei_io_list_init(cb); cb->file_private = cl; cb->major_file_operations = MEI_CLOSE; if (dev->mei_host_buffer_is_empty) { @@ -696,11 +683,11 @@ int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl) goto free; } mdelay(10); /* Wait for hardware disconnection ready */ - list_add_tail(&cb->cb_list, &dev->ctrl_rd_list.mei_cb.cb_list); + list_add_tail(&cb->list, &dev->ctrl_rd_list.list); } else { dev_dbg(&dev->pdev->dev, "add disconnect cb to control write list\n"); - list_add_tail(&cb->cb_list, - &dev->ctrl_wr_list.mei_cb.cb_list); + list_add_tail(&cb->list, &dev->ctrl_wr_list.list); + } mutex_unlock(&dev->device_lock); diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 320ebd2..54d6f1a 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -87,9 +87,8 @@ static void _mei_cmpl_iamthif(struct mei_device *dev, struct mei_cl_cb *cb_pos) memcpy(cb_pos->response_buffer.data, dev->iamthif_msg_buf, dev->iamthif_msg_buf_index); - list_add_tail(&cb_pos->cb_list, - &dev->amthi_read_complete_list.mei_cb.cb_list); - dev_dbg(&dev->pdev->dev, "amthi read completed.\n"); + list_add_tail(&cb_pos->list, &dev->amthi_read_complete_list.list); + dev_dbg(&dev->pdev->dev, "amthi read completed\n"); dev->iamthif_timer = jiffies; dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n", dev->iamthif_timer); @@ -112,7 +111,7 @@ static void _mei_cmpl_iamthif(struct mei_device *dev, struct mei_cl_cb *cb_pos) * * returns 0 on success, <0 on failure. */ -static int mei_irq_thread_read_amthi_message(struct mei_io_list *complete_list, +static int mei_irq_thread_read_amthi_message(struct mei_cl_cb *complete_list, struct mei_device *dev, struct mei_msg_hdr *mei_hdr) { @@ -155,8 +154,7 @@ static int mei_irq_thread_read_amthi_message(struct mei_io_list *complete_list, /* found the iamthif cb */ dev_dbg(&dev->pdev->dev, "complete the amthi read cb.\n "); dev_dbg(&dev->pdev->dev, "add the amthi read cb to complete.\n "); - list_add_tail(&cb->cb_list, - &complete_list->mei_cb.cb_list); + list_add_tail(&cb->list, &complete_list->list); } return 0; } @@ -188,7 +186,7 @@ static int _mei_irq_thread_state_ok(struct mei_cl *cl, * * returns 0 on success, <0 on failure. */ -static int mei_irq_thread_read_client_message(struct mei_io_list *complete_list, +static int mei_irq_thread_read_client_message(struct mei_cl_cb *complete_list, struct mei_device *dev, struct mei_msg_hdr *mei_hdr) { @@ -197,11 +195,10 @@ static int mei_irq_thread_read_client_message(struct mei_io_list *complete_list, unsigned char *buffer = NULL; dev_dbg(&dev->pdev->dev, "start client msg\n"); - if (list_empty(&dev->read_list.mei_cb.cb_list)) + if (list_empty(&dev->read_list.list)) goto quit; - list_for_each_entry_safe(cb_pos, cb_next, - &dev->read_list.mei_cb.cb_list, cb_list) { + list_for_each_entry_safe(cb_pos, cb_next, &dev->read_list.list, list) { cl = (struct mei_cl *)cb_pos->file_private; if (cl && _mei_irq_thread_state_ok(cl, mei_hdr)) { cl->reading_state = MEI_READING; @@ -210,7 +207,7 @@ static int mei_irq_thread_read_client_message(struct mei_io_list *complete_list, if (cb_pos->response_buffer.size < mei_hdr->length + cb_pos->buf_idx) { dev_dbg(&dev->pdev->dev, "message overflow.\n"); - list_del(&cb_pos->cb_list); + list_del(&cb_pos->list); return -ENOMEM; } if (buffer) @@ -219,15 +216,15 @@ static int mei_irq_thread_read_client_message(struct mei_io_list *complete_list, cb_pos->buf_idx += mei_hdr->length; if (mei_hdr->msg_complete) { cl->status = 0; - list_del(&cb_pos->cb_list); + list_del(&cb_pos->list); dev_dbg(&dev->pdev->dev, "completed read H cl = %d, ME cl = %d, length = %lu\n", cl->host_client_id, cl->me_client_id, cb_pos->buf_idx); - list_add_tail(&cb_pos->cb_list, - &complete_list->mei_cb.cb_list); + list_add_tail(&cb_pos->list, + &complete_list->list); } break; @@ -291,7 +288,7 @@ static int _mei_irq_thread_iamthif_read(struct mei_device *dev, s32 *slots) static int _mei_irq_thread_close(struct mei_device *dev, s32 *slots, struct mei_cl_cb *cb_pos, struct mei_cl *cl, - struct mei_io_list *cmpl_list) + struct mei_cl_cb *cmpl_list) { if ((*slots * sizeof(u32)) < (sizeof(struct mei_msg_hdr) + sizeof(struct hbm_client_disconnect_request))) @@ -302,15 +299,13 @@ static int _mei_irq_thread_close(struct mei_device *dev, s32 *slots, if (mei_disconnect(dev, cl)) { cl->status = 0; cb_pos->buf_idx = 0; - list_move_tail(&cb_pos->cb_list, - &cmpl_list->mei_cb.cb_list); + list_move_tail(&cb_pos->list, &cmpl_list->list); return -EMSGSIZE; } else { cl->state = MEI_FILE_DISCONNECTING; cl->status = 0; cb_pos->buf_idx = 0; - list_move_tail(&cb_pos->cb_list, - &dev->ctrl_rd_list.mei_cb.cb_list); + list_move_tail(&cb_pos->list, &dev->ctrl_rd_list.list); cl->timer_count = MEI_CONNECT_TIMEOUT; } @@ -357,7 +352,7 @@ static void mei_client_connect_response(struct mei_device *dev, { struct mei_cl *cl; - struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL; + struct mei_cl_cb *pos = NULL, *next = NULL; dev_dbg(&dev->pdev->dev, "connect_response:\n" @@ -383,17 +378,16 @@ static void mei_client_connect_response(struct mei_device *dev, dev->iamthif_state = MEI_IAMTHIF_IDLE; return; } - list_for_each_entry_safe(cb_pos, cb_next, - &dev->ctrl_rd_list.mei_cb.cb_list, cb_list) { + list_for_each_entry_safe(pos, next, &dev->ctrl_rd_list.list, list) { - cl = (struct mei_cl *)cb_pos->file_private; + cl = (struct mei_cl *)pos->file_private; if (!cl) { - list_del(&cb_pos->cb_list); + list_del(&pos->list); return; } - if (MEI_IOCTL == cb_pos->major_file_operations) { + if (MEI_IOCTL == pos->major_file_operations) { if (is_treat_specially_client(cl, rs)) { - list_del(&cb_pos->cb_list); + list_del(&pos->list); cl->status = 0; cl->timer_count = 0; break; @@ -412,7 +406,7 @@ static void mei_client_disconnect_response(struct mei_device *dev, struct hbm_client_connect_response *rs) { struct mei_cl *cl; - struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL; + struct mei_cl_cb *pos = NULL, *next = NULL; dev_dbg(&dev->pdev->dev, "disconnect_response:\n" @@ -423,12 +417,11 @@ static void mei_client_disconnect_response(struct mei_device *dev, rs->host_addr, rs->status); - list_for_each_entry_safe(cb_pos, cb_next, - &dev->ctrl_rd_list.mei_cb.cb_list, cb_list) { - cl = (struct mei_cl *)cb_pos->file_private; + list_for_each_entry_safe(pos, next, &dev->ctrl_rd_list.list, list) { + cl = (struct mei_cl *)pos->file_private; if (!cl) { - list_del(&cb_pos->cb_list); + list_del(&pos->list); return; } @@ -436,7 +429,7 @@ static void mei_client_disconnect_response(struct mei_device *dev, if (cl->host_client_id == rs->host_addr && cl->me_client_id == rs->me_addr) { - list_del(&cb_pos->cb_list); + list_del(&pos->list); if (!rs->status) cl->state = MEI_FILE_DISCONNECTED; @@ -822,12 +815,12 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, static int _mei_irq_thread_read(struct mei_device *dev, s32 *slots, struct mei_cl_cb *cb_pos, struct mei_cl *cl, - struct mei_io_list *cmpl_list) + struct mei_cl_cb *cmpl_list) { if ((*slots * sizeof(u32)) < (sizeof(struct mei_msg_hdr) + sizeof(struct hbm_flow_control))) { /* return the cancel routine */ - list_del(&cb_pos->cb_list); + list_del(&cb_pos->list); return -EBADMSG; } @@ -836,10 +829,10 @@ static int _mei_irq_thread_read(struct mei_device *dev, s32 *slots, if (mei_send_flow_control(dev, cl)) { cl->status = -ENODEV; cb_pos->buf_idx = 0; - list_move_tail(&cb_pos->cb_list, &cmpl_list->mei_cb.cb_list); + list_move_tail(&cb_pos->list, &cmpl_list->list); return -ENODEV; } - list_move_tail(&cb_pos->cb_list, &dev->read_list.mei_cb.cb_list); + list_move_tail(&cb_pos->list, &dev->read_list.list); return 0; } @@ -859,12 +852,12 @@ static int _mei_irq_thread_read(struct mei_device *dev, s32 *slots, static int _mei_irq_thread_ioctl(struct mei_device *dev, s32 *slots, struct mei_cl_cb *cb_pos, struct mei_cl *cl, - struct mei_io_list *cmpl_list) + struct mei_cl_cb *cmpl_list) { if ((*slots * sizeof(u32)) < (sizeof(struct mei_msg_hdr) + sizeof(struct hbm_client_connect_request))) { /* return the cancel routine */ - list_del(&cb_pos->cb_list); + list_del(&cb_pos->list); return -EBADMSG; } @@ -873,11 +866,10 @@ static int _mei_irq_thread_ioctl(struct mei_device *dev, s32 *slots, if (mei_connect(dev, cl)) { cl->status = -ENODEV; cb_pos->buf_idx = 0; - list_del(&cb_pos->cb_list); + list_del(&cb_pos->list); return -ENODEV; } else { - list_move_tail(&cb_pos->cb_list, - &dev->ctrl_rd_list.mei_cb.cb_list); + list_move_tail(&cb_pos->list, &dev->ctrl_rd_list.list); cl->timer_count = MEI_CONNECT_TIMEOUT; } return 0; @@ -897,7 +889,7 @@ static int _mei_irq_thread_ioctl(struct mei_device *dev, s32 *slots, static int _mei_irq_thread_cmpl(struct mei_device *dev, s32 *slots, struct mei_cl_cb *cb_pos, struct mei_cl *cl, - struct mei_io_list *cmpl_list) + struct mei_cl_cb *cmpl_list) { struct mei_msg_hdr *mei_hdr; @@ -924,16 +916,14 @@ static int _mei_irq_thread_cmpl(struct mei_device *dev, s32 *slots, cb_pos->buf_idx), mei_hdr->length)) { cl->status = -ENODEV; - list_move_tail(&cb_pos->cb_list, - &cmpl_list->mei_cb.cb_list); + list_move_tail(&cb_pos->list, &cmpl_list->list); return -ENODEV; } else { if (mei_flow_ctrl_reduce(dev, cl)) return -ENODEV; cl->status = 0; cb_pos->buf_idx += mei_hdr->length; - list_move_tail(&cb_pos->cb_list, - &dev->write_waiting_list.mei_cb.cb_list); + list_move_tail(&cb_pos->list, &dev->write_waiting_list.list); } } else if (*slots == dev->hbuf_depth) { /* buffer is still empty */ @@ -951,8 +941,7 @@ static int _mei_irq_thread_cmpl(struct mei_device *dev, s32 *slots, cb_pos->buf_idx), mei_hdr->length)) { cl->status = -ENODEV; - list_move_tail(&cb_pos->cb_list, - &cmpl_list->mei_cb.cb_list); + list_move_tail(&cb_pos->list, &cmpl_list->list); return -ENODEV; } else { cb_pos->buf_idx += mei_hdr->length; @@ -988,7 +977,7 @@ static int _mei_irq_thread_cmpl(struct mei_device *dev, s32 *slots, static int _mei_irq_thread_cmpl_iamthif(struct mei_device *dev, s32 *slots, struct mei_cl_cb *cb_pos, struct mei_cl *cl, - struct mei_io_list *cmpl_list) + struct mei_cl_cb *cmpl_list) { struct mei_msg_hdr *mei_hdr; @@ -1011,7 +1000,7 @@ static int _mei_irq_thread_cmpl_iamthif(struct mei_device *dev, s32 *slots, mei_hdr->length)) { dev->iamthif_state = MEI_IAMTHIF_IDLE; cl->status = -ENODEV; - list_del(&cb_pos->cb_list); + list_del(&cb_pos->list); return -ENODEV; } else { if (mei_flow_ctrl_reduce(dev, cl)) @@ -1023,8 +1012,7 @@ static int _mei_irq_thread_cmpl_iamthif(struct mei_device *dev, s32 *slots, dev->iamthif_flow_control_pending = true; /* save iamthif cb sent to amthi client */ dev->iamthif_current_cb = cb_pos; - list_move_tail(&cb_pos->cb_list, - &dev->write_waiting_list.mei_cb.cb_list); + list_move_tail(&cb_pos->list, &dev->write_waiting_list.list); } } else if (*slots == dev->hbuf_depth) { @@ -1044,7 +1032,7 @@ static int _mei_irq_thread_cmpl_iamthif(struct mei_device *dev, s32 *slots, dev->iamthif_msg_buf_index), mei_hdr->length)) { cl->status = -ENODEV; - list_del(&cb_pos->cb_list); + list_del(&cb_pos->list); } else { dev->iamthif_msg_buf_index += mei_hdr->length; } @@ -1066,7 +1054,7 @@ static int _mei_irq_thread_cmpl_iamthif(struct mei_device *dev, s32 *slots, * * returns 0 on success, <0 on failure. */ -static int mei_irq_thread_read_handler(struct mei_io_list *cmpl_list, +static int mei_irq_thread_read_handler(struct mei_cl_cb *cmpl_list, struct mei_device *dev, s32 *slots) { @@ -1169,14 +1157,13 @@ end: * * returns 0 on success, <0 on failure. */ -static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list, - struct mei_device *dev, - s32 *slots) +static int mei_irq_thread_write_handler(struct mei_cl_cb *cmpl_list, + struct mei_device *dev, s32 *slots) { struct mei_cl *cl; struct mei_cl_cb *pos = NULL, *next = NULL; - struct mei_io_list *list; + struct mei_cl_cb *list; int ret; if (!mei_hbuf_is_empty(dev)) { @@ -1191,20 +1178,19 @@ static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list, dev_dbg(&dev->pdev->dev, "complete all waiting for write cb.\n"); list = &dev->write_waiting_list; - list_for_each_entry_safe(pos, next, &list->mei_cb.cb_list, cb_list) { + list_for_each_entry_safe(pos, next, &list->list, list) { cl = (struct mei_cl *)pos->file_private; if (cl == NULL) continue; cl->status = 0; - list_del(&pos->cb_list); + list_del(&pos->list); if (MEI_WRITING == cl->writing_state && (pos->major_file_operations == MEI_WRITE) && (cl != &dev->iamthif_cl)) { dev_dbg(&dev->pdev->dev, "MEI WRITE COMPLETE\n"); cl->writing_state = MEI_WRITE_COMPLETE; - list_add_tail(&pos->cb_list, - &cmpl_list->mei_cb.cb_list); + list_add_tail(&pos->list, &cmpl_list->list); } if (cl == &dev->iamthif_cl) { dev_dbg(&dev->pdev->dev, "check iamthif flow control.\n"); @@ -1250,11 +1236,10 @@ static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list, /* complete control write list CB */ dev_dbg(&dev->pdev->dev, "complete control write list cb.\n"); - list_for_each_entry_safe(pos, next, - &dev->ctrl_wr_list.mei_cb.cb_list, cb_list) { + list_for_each_entry_safe(pos, next, &dev->ctrl_wr_list.list, list) { cl = (struct mei_cl *) pos->file_private; if (!cl) { - list_del(&pos->cb_list); + list_del(&pos->list); return -ENODEV; } switch (pos->major_file_operations) { @@ -1289,8 +1274,7 @@ static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list, } /* complete write list CB */ dev_dbg(&dev->pdev->dev, "complete write list cb.\n"); - list_for_each_entry_safe(pos, next, - &dev->write_list.mei_cb.cb_list, cb_list) { + list_for_each_entry_safe(pos, next, &dev->write_list.list, list) { cl = (struct mei_cl *)pos->file_private; if (cl == NULL) continue; @@ -1410,16 +1394,15 @@ void mei_timer(struct work_struct *work) dev_dbg(&dev->pdev->dev, "freeing AMTHI for other requests\n"); - amthi_complete_list = &dev->amthi_read_complete_list. - mei_cb.cb_list; + amthi_complete_list = &dev->amthi_read_complete_list.list; - list_for_each_entry_safe(cb_pos, cb_next, amthi_complete_list, cb_list) { + list_for_each_entry_safe(cb_pos, cb_next, amthi_complete_list, list) { cl_pos = cb_pos->file_object->private_data; /* Finding the AMTHI entry. */ if (cl_pos == &dev->iamthif_cl) - list_del(&cb_pos->cb_list); + list_del(&cb_pos->list); } if (dev->iamthif_current_cb) mei_free_cb_private(dev->iamthif_current_cb); @@ -1450,7 +1433,7 @@ out: irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id) { struct mei_device *dev = (struct mei_device *) dev_id; - struct mei_io_list complete_list; + struct mei_cl_cb complete_list; struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL; struct mei_cl *cl; s32 slots; @@ -1530,14 +1513,13 @@ end: wake_up_interruptible(&dev->wait_recvd_msg); bus_message_received = false; } - if (list_empty(&complete_list.mei_cb.cb_list)) + if (list_empty(&complete_list.list)) return IRQ_HANDLED; - list_for_each_entry_safe(cb_pos, cb_next, - &complete_list.mei_cb.cb_list, cb_list) { + list_for_each_entry_safe(cb_pos, cb_next, &complete_list.list, list) { cl = (struct mei_cl *)cb_pos->file_private; - list_del(&cb_pos->cb_list); + list_del(&cb_pos->list); if (cl) { if (cl != &dev->iamthif_cl) { dev_dbg(&dev->pdev->dev, "completing call back.\n"); diff --git a/drivers/misc/mei/iorw.c b/drivers/misc/mei/iorw.c index 20652e1..4ff9eaf 100644 --- a/drivers/misc/mei/iorw.c +++ b/drivers/misc/mei/iorw.c @@ -104,7 +104,7 @@ int mei_ioctl_connect_client(struct file *file, rets = -ENOMEM; goto end; } - INIT_LIST_HEAD(&cb->cb_list); + mei_io_list_init(cb); cb->major_file_operations = MEI_IOCTL; @@ -193,9 +193,7 @@ int mei_ioctl_connect_client(struct file *file, dev_dbg(&dev->pdev->dev, "Sending connect message - succeeded\n"); cl->timer_count = MEI_CONNECT_TIMEOUT; cb->file_private = cl; - list_add_tail(&cb->cb_list, - &dev->ctrl_rd_list.mei_cb. - cb_list); + list_add_tail(&cb->list, &dev->ctrl_rd_list.list); } @@ -203,8 +201,7 @@ int mei_ioctl_connect_client(struct file *file, dev_dbg(&dev->pdev->dev, "Queuing the connect request due to device busy\n"); cb->file_private = cl; dev_dbg(&dev->pdev->dev, "add connect cb to control write list.\n"); - list_add_tail(&cb->cb_list, - &dev->ctrl_wr_list.mei_cb.cb_list); + list_add_tail(&cb->list, &dev->ctrl_wr_list.list); } mutex_unlock(&dev->device_lock); err = wait_event_timeout(dev->wait_recvd_msg, @@ -255,7 +252,7 @@ struct mei_cl_cb *find_amthi_read_list_entry( struct mei_cl_cb *next = NULL; list_for_each_entry_safe(pos, next, - &dev->amthi_read_complete_list.mei_cb.cb_list, cb_list) { + &dev->amthi_read_complete_list.list, list) { cl_temp = (struct mei_cl *)pos->file_private; if (cl_temp && cl_temp == &dev->iamthif_cl && pos->file_object == file) @@ -340,17 +337,17 @@ int amthi_read(struct mei_device *dev, struct file *file, if (time_after(jiffies, timeout)) { dev_dbg(&dev->pdev->dev, "amthi Time out\n"); /* 15 sec for the message has expired */ - list_del(&cb->cb_list); + list_del(&cb->list); rets = -ETIMEDOUT; goto free; } } /* if the whole message will fit remove it from the list */ if (cb->buf_idx >= *offset && length >= (cb->buf_idx - *offset)) - list_del(&cb->cb_list); + list_del(&cb->list); else if (cb->buf_idx > 0 && cb->buf_idx <= *offset) { /* end of the message has been reached */ - list_del(&cb->cb_list); + list_del(&cb->list); rets = 0; goto free; } @@ -441,9 +438,9 @@ int mei_start_read(struct mei_device *dev, struct mei_cl *cl) rets = -ENODEV; goto unlock; } - list_add_tail(&cb->cb_list, &dev->read_list.mei_cb.cb_list); + list_add_tail(&cb->list, &dev->read_list.list); } else { - list_add_tail(&cb->cb_list, &dev->ctrl_wr_list.mei_cb.cb_list); + list_add_tail(&cb->list, &dev->ctrl_wr_list.list); } return rets; unlock: @@ -510,13 +507,11 @@ int amthi_write(struct mei_device *dev, struct mei_cl_cb *cb) dev_dbg(&dev->pdev->dev, "add amthi cb to write waiting list\n"); dev->iamthif_current_cb = cb; dev->iamthif_file_object = cb->file_object; - list_add_tail(&cb->cb_list, - &dev->write_waiting_list.mei_cb.cb_list); + list_add_tail(&cb->list, &dev->write_waiting_list.list); } else { dev_dbg(&dev->pdev->dev, "message does not complete, " "so add amthi cb to write list.\n"); - list_add_tail(&cb->cb_list, - &dev->write_list.mei_cb.cb_list); + list_add_tail(&cb->list, &dev->write_list.list); } } else { if (!(dev->mei_host_buffer_is_empty)) @@ -524,7 +519,7 @@ int amthi_write(struct mei_device *dev, struct mei_cl_cb *cb) dev_dbg(&dev->pdev->dev, "No flow control credentials, " "so add iamthif cb to write list.\n"); - list_add_tail(&cb->cb_list, &dev->write_list.mei_cb.cb_list); + list_add_tail(&cb->list, &dev->write_list.list); } return 0; } @@ -556,9 +551,8 @@ void mei_run_next_iamthif_cmd(struct mei_device *dev) dev_dbg(&dev->pdev->dev, "complete amthi cmd_list cb.\n"); - list_for_each_entry_safe(pos, next, - &dev->amthi_cmd_list.mei_cb.cb_list, cb_list) { - list_del(&pos->cb_list); + list_for_each_entry_safe(pos, next, &dev->amthi_cmd_list.list, list) { + list_del(&pos->list); cl_tmp = (struct mei_cl *)pos->file_private; if (cl_tmp && cl_tmp == &dev->iamthif_cl) { diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 8dcf59d..2e46291 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -111,12 +111,12 @@ static bool mei_clear_list(struct mei_device *dev, bool removed = false; /* list all list member */ - list_for_each_entry_safe(cb_pos, cb_next, mei_cb_list, cb_list) { + list_for_each_entry_safe(cb_pos, cb_next, mei_cb_list, list) { file_temp = (struct file *)cb_pos->file_object; /* check if list member associated with a file */ if (file_temp == file) { /* remove member from the list */ - list_del(&cb_pos->cb_list); + list_del(&cb_pos->list); /* check if cb equal to current iamthif cb */ if (dev->iamthif_current_cb == cb_pos) { dev->iamthif_current_cb = NULL; @@ -148,20 +148,20 @@ static bool mei_clear_lists(struct mei_device *dev, struct file *file) bool removed = false; /* remove callbacks associated with a file */ - mei_clear_list(dev, file, &dev->amthi_cmd_list.mei_cb.cb_list); + mei_clear_list(dev, file, &dev->amthi_cmd_list.list); if (mei_clear_list(dev, file, - &dev->amthi_read_complete_list.mei_cb.cb_list)) + &dev->amthi_read_complete_list.list)) removed = true; - mei_clear_list(dev, file, &dev->ctrl_rd_list.mei_cb.cb_list); + mei_clear_list(dev, file, &dev->ctrl_rd_list.list); - if (mei_clear_list(dev, file, &dev->ctrl_wr_list.mei_cb.cb_list)) + if (mei_clear_list(dev, file, &dev->ctrl_wr_list.list)) removed = true; - if (mei_clear_list(dev, file, &dev->write_waiting_list.mei_cb.cb_list)) + if (mei_clear_list(dev, file, &dev->write_waiting_list.list)) removed = true; - if (mei_clear_list(dev, file, &dev->write_list.mei_cb.cb_list)) + if (mei_clear_list(dev, file, &dev->write_list.list)) removed = true; /* check if iamthif_current_cb not NULL */ @@ -192,8 +192,7 @@ static struct mei_cl_cb *find_read_list_entry( struct mei_cl_cb *next = NULL; dev_dbg(&dev->pdev->dev, "remove read_list CB\n"); - list_for_each_entry_safe(pos, next, - &dev->read_list.mei_cb.cb_list, cb_list) { + list_for_each_entry_safe(pos, next, &dev->read_list.list, list) { struct mei_cl *cl_temp; cl_temp = (struct mei_cl *)pos->file_private; @@ -324,7 +323,7 @@ static int mei_release(struct inode *inode, struct file *file) cb = find_read_list_entry(dev, cl); /* Remove entry from read list */ if (cb) - list_del(&cb->cb_list); + list_del(&cb->list); cb = cl->read_cb; cl->read_cb = NULL; @@ -504,7 +503,7 @@ free: cb_pos = find_read_list_entry(dev, cl); /* Remove entry from read list */ if (cb_pos) - list_del(&cb_pos->cb_list); + list_del(&cb_pos->list); mei_free_cb_private(cb); cl->reading_state = MEI_IDLE; cl->read_cb = NULL; @@ -534,7 +533,7 @@ static struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp) if (!cb) return NULL; - INIT_LIST_HEAD(&cb->cb_list); + mei_io_list_init(cb); cb->file_object = fp; cb->file_private = cl; @@ -651,7 +650,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, if (time_after(jiffies, timeout) || cl->reading_state == MEI_READ_COMPLETE) { *offset = 0; - list_del(&write_cb->cb_list); + list_del(&write_cb->list); mei_free_cb_private(write_cb); write_cb = NULL; } @@ -663,7 +662,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, *offset = 0; write_cb = find_read_list_entry(dev, cl); if (write_cb) { - list_del(&write_cb->cb_list); + list_del(&write_cb->list); mei_free_cb_private(write_cb); write_cb = NULL; cl->reading_state = MEI_IDLE; @@ -707,13 +706,12 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, write_cb->major_file_operations = MEI_IOCTL; - if (!list_empty(&dev->amthi_cmd_list.mei_cb.cb_list) || + if (!list_empty(&dev->amthi_cmd_list.list) || dev->iamthif_state != MEI_IAMTHIF_IDLE) { dev_dbg(&dev->pdev->dev, "amthi_state = %d\n", (int) dev->iamthif_state); dev_dbg(&dev->pdev->dev, "add amthi cb to amthi cmd waiting list\n"); - list_add_tail(&write_cb->cb_list, - &dev->amthi_cmd_list.mei_cb.cb_list); + list_add_tail(&write_cb->list, &dev->amthi_cmd_list.list); } else { dev_dbg(&dev->pdev->dev, "call amthi write\n"); rets = amthi_write(dev, write_cb); @@ -764,19 +762,16 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, rets = -ENODEV; goto unlock_dev; } - list_add_tail(&write_cb->cb_list, - &dev->write_waiting_list.mei_cb.cb_list); + list_add_tail(&write_cb->list, &dev->write_waiting_list.list); } else { - list_add_tail(&write_cb->cb_list, - &dev->write_list.mei_cb.cb_list); + list_add_tail(&write_cb->list, &dev->write_list.list); } } else { write_cb->buf_idx = 0; cl->writing_state = MEI_WRITING; - list_add_tail(&write_cb->cb_list, - &dev->write_list.mei_cb.cb_list); + list_add_tail(&write_cb->list, &dev->write_list.list); } mutex_unlock(&dev->device_lock); return length; diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index c58b6fa..de5babc 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -144,7 +144,7 @@ struct mei_message_data { struct mei_cl_cb { - struct list_head cb_list; + struct list_head list; enum mei_cb_major_types major_file_operations; void *file_private; struct mei_message_data request_buffer; @@ -175,10 +175,6 @@ struct mei_cl { struct mei_cl_cb *read_cb; }; -struct mei_io_list { - struct mei_cl_cb mei_cb; -}; - /** * struct mei_deive - MEI private device struct * @hbuf_depth - depth of host(write) buffer @@ -189,15 +185,15 @@ struct mei_device { * lists of queues */ /* array of pointers to aio lists */ - struct mei_io_list read_list; /* driver read queue */ - struct mei_io_list write_list; /* driver write queue */ - struct mei_io_list write_waiting_list; /* write waiting queue */ - struct mei_io_list ctrl_wr_list; /* managed write IOCTL list */ - struct mei_io_list ctrl_rd_list; /* managed read IOCTL list */ - struct mei_io_list amthi_cmd_list; /* amthi list for cmd waiting */ + struct mei_cl_cb read_list; /* driver read queue */ + struct mei_cl_cb write_list; /* driver write queue */ + struct mei_cl_cb write_waiting_list; /* write waiting queue */ + struct mei_cl_cb ctrl_wr_list; /* managed write IOCTL list */ + struct mei_cl_cb ctrl_rd_list; /* managed read IOCTL list */ + struct mei_cl_cb amthi_cmd_list; /* amthi list for cmd waiting */ /* driver managed amthi list for reading completed amthi cmd data */ - struct mei_io_list amthi_read_complete_list; + struct mei_cl_cb amthi_read_complete_list; /* * list of files */ @@ -297,8 +293,16 @@ int mei_me_cl_by_id(struct mei_device *dev, u8 client_id); /* * MEI IO List Functions */ -void mei_io_list_init(struct mei_io_list *list); -void mei_io_list_flush(struct mei_io_list *list, struct mei_cl *cl); +/** + * mei_io_list_init - Sets up a queue list. + * + * @list: An instance cl callback structure + */ +static inline void mei_io_list_init(struct mei_cl_cb *list) +{ + INIT_LIST_HEAD(&list->list); +} +void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl); /* * MEI ME Client Functions -- cgit v0.10.2 From 601a1efa630aab0ca72bf8d638c441a09654b250 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 9 Oct 2012 16:50:20 +0200 Subject: mei: rename mei_free_cb_private to mei_io_cb_free 1. cb_private was an old name that we depriacated in earlier cleanups 2. we also group the funcion declaration with other _io_ functions 3. Don't check cb for NULL as mei_io_cb_free is NULL safe Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index 2275cf0..4666f0b 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c @@ -341,7 +341,7 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled) /* remove all waiting requests */ list_for_each_entry_safe(cb_pos, cb_next, &dev->write_list.list, list) { list_del(&cb_pos->list); - mei_free_cb_private(cb_pos); + mei_io_cb_free(cb_pos); } } @@ -715,7 +715,7 @@ int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl) mei_io_list_flush(&dev->ctrl_rd_list, cl); mei_io_list_flush(&dev->ctrl_wr_list, cl); free: - mei_free_cb_private(cb); + mei_io_cb_free(cb); return rets; } diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 54d6f1a..5c65bac 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -58,7 +58,7 @@ irqreturn_t mei_interrupt_quick_handler(int irq, void *dev_id) static void _mei_cmpl(struct mei_cl *cl, struct mei_cl_cb *cb_pos) { if (cb_pos->major_file_operations == MEI_WRITE) { - mei_free_cb_private(cb_pos); + mei_io_cb_free(cb_pos); cb_pos = NULL; cl->writing_state = MEI_WRITE_COMPLETE; if (waitqueue_active(&cl->tx_wait)) @@ -1368,11 +1368,10 @@ void mei_timer(struct work_struct *work) dev->iamthif_state = MEI_IAMTHIF_IDLE; dev->iamthif_timer = 0; - if (dev->iamthif_current_cb) - mei_free_cb_private(dev->iamthif_current_cb); + mei_io_cb_free(dev->iamthif_current_cb); + dev->iamthif_current_cb = NULL; dev->iamthif_file_object = NULL; - dev->iamthif_current_cb = NULL; mei_run_next_iamthif_cmd(dev); } } @@ -1404,12 +1403,11 @@ void mei_timer(struct work_struct *work) if (cl_pos == &dev->iamthif_cl) list_del(&cb_pos->list); } - if (dev->iamthif_current_cb) - mei_free_cb_private(dev->iamthif_current_cb); + mei_io_cb_free(dev->iamthif_current_cb); + dev->iamthif_current_cb = NULL; dev->iamthif_file_object->private_data = NULL; dev->iamthif_file_object = NULL; - dev->iamthif_current_cb = NULL; dev->iamthif_timer = 0; mei_run_next_iamthif_cmd(dev); diff --git a/drivers/misc/mei/iorw.c b/drivers/misc/mei/iorw.c index 4ff9eaf..2891bc4 100644 --- a/drivers/misc/mei/iorw.c +++ b/drivers/misc/mei/iorw.c @@ -39,6 +39,21 @@ #include "interface.h" /** + * mei_io_cb_free - free mei_cb_private related memory + * + * @cb: mei callback struct + */ +void mei_io_cb_free(struct mei_cl_cb *cb) +{ + if (cb == NULL) + return; + + kfree(cb->request_buffer.data); + kfree(cb->response_buffer.data); + kfree(cb); +} + +/** * mei_me_cl_by_id return index to me_clients for client_id * * @dev: the device structure @@ -231,7 +246,7 @@ int mei_ioctl_connect_client(struct file *file, rets = 0; end: dev_dbg(&dev->pdev->dev, "free connect cb memory."); - kfree(cb); + mei_io_cb_free(cb); return rets; } @@ -375,7 +390,7 @@ int amthi_read(struct mei_device *dev, struct file *file, free: dev_dbg(&dev->pdev->dev, "free amthi cb memory.\n"); *offset = 0; - mei_free_cb_private(cb); + mei_io_cb_free(cb); out: return rets; } @@ -444,7 +459,7 @@ int mei_start_read(struct mei_device *dev, struct mei_cl *cl) } return rets; unlock: - mei_free_cb_private(cb); + mei_io_cb_free(cb); return rets; } @@ -568,17 +583,3 @@ void mei_run_next_iamthif_cmd(struct mei_device *dev) } } -/** - * mei_free_cb_private - free mei_cb_private related memory - * - * @cb: mei callback struct - */ -void mei_free_cb_private(struct mei_cl_cb *cb) -{ - if (cb == NULL) - return; - - kfree(cb->request_buffer.data); - kfree(cb->response_buffer.data); - kfree(cb); -} diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 2e46291..518e07e 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -124,7 +124,7 @@ static bool mei_clear_list(struct mei_device *dev, mei_send_flow_control(dev, &dev->iamthif_cl); } /* free all allocated buffers */ - mei_free_cb_private(cb_pos); + mei_io_cb_free(cb_pos); cb_pos = NULL; removed = true; } @@ -169,7 +169,7 @@ static bool mei_clear_lists(struct mei_device *dev, struct file *file) /* check file and iamthif current cb association */ if (dev->iamthif_current_cb->file_object == file) { /* remove cb */ - mei_free_cb_private(dev->iamthif_current_cb); + mei_io_cb_free(dev->iamthif_current_cb); dev->iamthif_current_cb = NULL; removed = true; } @@ -332,7 +332,7 @@ static int mei_release(struct inode *inode, struct file *file) file->private_data = NULL; if (cb) { - mei_free_cb_private(cb); + mei_io_cb_free(cb); cb = NULL; } @@ -504,7 +504,7 @@ free: /* Remove entry from read list */ if (cb_pos) list_del(&cb_pos->list); - mei_free_cb_private(cb); + mei_io_cb_free(cb); cl->reading_state = MEI_IDLE; cl->read_cb = NULL; cl->read_pending = 0; @@ -651,7 +651,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, cl->reading_state == MEI_READ_COMPLETE) { *offset = 0; list_del(&write_cb->list); - mei_free_cb_private(write_cb); + mei_io_cb_free(write_cb); write_cb = NULL; } } @@ -663,7 +663,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, write_cb = find_read_list_entry(dev, cl); if (write_cb) { list_del(&write_cb->list); - mei_free_cb_private(write_cb); + mei_io_cb_free(write_cb); write_cb = NULL; cl->reading_state = MEI_IDLE; cl->read_cb = NULL; @@ -778,7 +778,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, unlock_dev: mutex_unlock(&dev->device_lock); - mei_free_cb_private(write_cb); + mei_io_cb_free(write_cb); return rets; } diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index de5babc..4545a9e 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -291,8 +291,10 @@ int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *cuuid); int mei_me_cl_by_id(struct mei_device *dev, u8 client_id); /* - * MEI IO List Functions + * MEI IO Functions */ +void mei_io_cb_free(struct mei_cl_cb *priv_cb); + /** * mei_io_list_init - Sets up a queue list. * @@ -361,7 +363,6 @@ struct mei_cl_cb *find_amthi_read_list_entry(struct mei_device *dev, void mei_run_next_iamthif_cmd(struct mei_device *dev); -void mei_free_cb_private(struct mei_cl_cb *priv_cb); /* -- cgit v0.10.2 From 664df38b3c74656261d4227b4dd380cfa453f78f Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 11 Oct 2012 16:35:08 +0200 Subject: mei: use mei_io_cb_ warppers also for control flows move the mei_io_cb_ wrappers to to iorw.c for global use and use them also for handling control flows Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index 4666f0b..1f13eb9 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c @@ -668,12 +668,10 @@ int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl) if (cl->state != MEI_FILE_DISCONNECTING) return 0; - cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL); + cb = mei_io_cb_init(cl, NULL); if (!cb) return -ENOMEM; - mei_io_list_init(cb); - cb->file_private = cl; cb->major_file_operations = MEI_CLOSE; if (dev->mei_host_buffer_is_empty) { dev->mei_host_buffer_is_empty = false; diff --git a/drivers/misc/mei/iorw.c b/drivers/misc/mei/iorw.c index 2891bc4..541c157 100644 --- a/drivers/misc/mei/iorw.c +++ b/drivers/misc/mei/iorw.c @@ -52,6 +52,80 @@ void mei_io_cb_free(struct mei_cl_cb *cb) kfree(cb->response_buffer.data); kfree(cb); } +/** + * mei_io_cb_init - allocate and initialize io callback + * + * @cl - mei client + * @file: pointer to file structure + * + * returns mei_cl_cb pointer or NULL; + */ +struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp) +{ + struct mei_cl_cb *cb; + + cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL); + if (!cb) + return NULL; + + mei_io_list_init(cb); + + cb->file_object = fp; + cb->file_private = cl; + cb->buf_idx = 0; + return cb; +} + + +/** + * mei_io_cb_alloc_req_buf - allocate request buffer + * + * @cb - io callback structure + * @size: size of the buffer + * + * returns 0 on success + * -EINVAL if cb is NULL + * -ENOMEM if allocation failed + */ +int mei_io_cb_alloc_req_buf(struct mei_cl_cb *cb, size_t length) +{ + if (!cb) + return -EINVAL; + + if (length == 0) + return 0; + + cb->request_buffer.data = kmalloc(length, GFP_KERNEL); + if (!cb->request_buffer.data) + return -ENOMEM; + cb->request_buffer.size = length; + return 0; +} +/** + * mei_io_cb_alloc_req_buf - allocate respose buffer + * + * @cb - io callback structure + * @size: size of the buffer + * + * returns 0 on success + * -EINVAL if cb is NULL + * -ENOMEM if allocation failed + */ +int mei_io_cb_alloc_resp_buf(struct mei_cl_cb *cb, size_t length) +{ + if (!cb) + return -EINVAL; + + if (length == 0) + return 0; + + cb->response_buffer.data = kmalloc(length, GFP_KERNEL); + if (!cb->response_buffer.data) + return -ENOMEM; + cb->response_buffer.size = length; + return 0; +} + /** * mei_me_cl_by_id return index to me_clients for client_id @@ -112,14 +186,12 @@ int mei_ioctl_connect_client(struct file *file, dev_dbg(&dev->pdev->dev, "mei_ioctl_connect_client() Entry\n"); - /* buffered ioctl cb */ - cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL); + cb = mei_io_cb_init(cl, file); if (!cb) { rets = -ENOMEM; goto end; } - mei_io_list_init(cb); cb->major_file_operations = MEI_IOCTL; @@ -207,14 +279,12 @@ int mei_ioctl_connect_client(struct file *file, } else { dev_dbg(&dev->pdev->dev, "Sending connect message - succeeded\n"); cl->timer_count = MEI_CONNECT_TIMEOUT; - cb->file_private = cl; list_add_tail(&cb->list, &dev->ctrl_rd_list.list); } } else { dev_dbg(&dev->pdev->dev, "Queuing the connect request due to device busy\n"); - cb->file_private = cl; dev_dbg(&dev->pdev->dev, "add connect cb to control write list.\n"); list_add_tail(&cb->list, &dev->ctrl_wr_list.list); } @@ -407,7 +477,7 @@ out: int mei_start_read(struct mei_device *dev, struct mei_cl *cl) { struct mei_cl_cb *cb; - int rets = 0; + int rets; int i; if (cl->state != MEI_FILE_CONNECTED) @@ -416,49 +486,40 @@ int mei_start_read(struct mei_device *dev, struct mei_cl *cl) if (dev->dev_state != MEI_DEV_ENABLED) return -ENODEV; - dev_dbg(&dev->pdev->dev, "check if read is pending.\n"); if (cl->read_pending || cl->read_cb) { dev_dbg(&dev->pdev->dev, "read is pending.\n"); return -EBUSY; } + i = mei_me_cl_by_id(dev, cl->me_client_id); + if (i < 0) { + dev_err(&dev->pdev->dev, "no such me client %d\n", + cl->me_client_id); + return -ENODEV; + } - cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL); + cb = mei_io_cb_init(cl, NULL); if (!cb) return -ENOMEM; - dev_dbg(&dev->pdev->dev, "allocation call back successful. host client = %d, ME client = %d\n", - cl->host_client_id, cl->me_client_id); - i = mei_me_cl_by_id(dev, cl->me_client_id); - if (i < 0) { - rets = -ENODEV; - goto unlock; - } + rets = mei_io_cb_alloc_resp_buf(cb, + dev->me_clients[i].props.max_msg_length); + if (rets) + goto err; - cb->response_buffer.size = dev->me_clients[i].props.max_msg_length; - cb->response_buffer.data = - kmalloc(cb->response_buffer.size, GFP_KERNEL); - if (!cb->response_buffer.data) { - rets = -ENOMEM; - goto unlock; - } - dev_dbg(&dev->pdev->dev, "allocation call back data success.\n"); cb->major_file_operations = MEI_READ; - /* make sure buffer index is zero before we start */ - cb->buf_idx = 0; - cb->file_private = (void *) cl; cl->read_cb = cb; if (dev->mei_host_buffer_is_empty) { dev->mei_host_buffer_is_empty = false; if (mei_send_flow_control(dev, cl)) { rets = -ENODEV; - goto unlock; + goto err; } list_add_tail(&cb->list, &dev->read_list.list); } else { list_add_tail(&cb->list, &dev->ctrl_wr_list.list); } return rets; -unlock: +err: mei_io_cb_free(cb); return rets; } diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 518e07e..ed4943f 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -513,84 +513,6 @@ out: mutex_unlock(&dev->device_lock); return rets; } - -/** - * mei_io_cb_init - allocate and initialize io callback - * - * @cl - mei client - * @file: pointer to file structure - * - * returns mei_cl_cb pointer or NULL; - */ -static struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp) -{ - struct mei_cl_cb *cb; - struct mei_device *dev; - - dev = cl->dev; - - cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL); - if (!cb) - return NULL; - - mei_io_list_init(cb); - - cb->file_object = fp; - cb->file_private = cl; - cb->buf_idx = 0; - return cb; -} - - -/** - * mei_io_cb_alloc_req_buf - allocate request buffer - * - * @cb - io callback structure - * @size: size of the buffer - * - * returns 0 on success - * -EINVAL if cb is NULL - * -ENOMEM if allocation failed - */ -static int mei_io_cb_alloc_req_buf(struct mei_cl_cb *cb, size_t length) -{ - if (!cb) - return -EINVAL; - - if (length == 0) - return 0; - - cb->request_buffer.data = kmalloc(length, GFP_KERNEL); - if (!cb->request_buffer.data) - return -ENOMEM; - cb->request_buffer.size = length; - return 0; -} -/** - * mei_io_cb_alloc_req_buf - allocate respose buffer - * - * @cb - io callback structure - * @size: size of the buffer - * - * returns 0 on success - * -EINVAL if cb is NULL - * -ENOMEM if allocation failed - */ -static int mei_io_cb_alloc_resp_buf(struct mei_cl_cb *cb, size_t length) -{ - if (!cb) - return -EINVAL; - - if (length == 0) - return 0; - - cb->response_buffer.data = kmalloc(length, GFP_KERNEL); - if (!cb->response_buffer.data) - return -ENOMEM; - cb->response_buffer.size = length; - return 0; -} - /** * mei_write - the write function. * diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 4545a9e..6adcb3f 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -293,7 +293,11 @@ int mei_me_cl_by_id(struct mei_device *dev, u8 client_id); /* * MEI IO Functions */ +struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp); void mei_io_cb_free(struct mei_cl_cb *priv_cb); +int mei_io_cb_alloc_req_buf(struct mei_cl_cb *cb, size_t length); +int mei_io_cb_alloc_resp_buf(struct mei_cl_cb *cb, size_t length); + /** * mei_io_list_init - Sets up a queue list. -- cgit v0.10.2 From 0a0c3b5a24bd802b1ebbf99e0b01296647b8199b Mon Sep 17 00:00:00 2001 From: Damian Hobson-Garcia Date: Tue, 25 Sep 2012 15:09:11 +0900 Subject: Add new uio device for dynamic memory allocation This device extends the uio_pdrv_genirq driver to provide limited dynamic memory allocation for UIO devices. This allows UIO devices to use CMA and IOMMU allocated memory regions. This driver is based on the uio_pdrv_genirq driver and provides the same generic interrupt handling capabilities. Like uio_prdv_genirq, a fixed number of memory regions, defined in the platform device's .resources field are exported to userpace. This driver adds the ability to export additional regions whose number and size are known at boot time, but whose memory is not allocated until the uio device file is opened for the first time. When the device file is closed, the allocated memory block is freed. Physical (DMA) addresses for the dynamic regions are provided to the userspace via /sys/class/uio/uioX/maps/mapY/addr in the same way as static addresses are when the uio device file is open, when no processes are holding the device file open, the address returned to userspace is DMA_ERROR_CODE. Signed-off-by: Damian Hobson-Garcia Signed-off-by: "Hans J. Koch" Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig index 6f3ea9b..82e2b89 100644 --- a/drivers/uio/Kconfig +++ b/drivers/uio/Kconfig @@ -44,6 +44,22 @@ config UIO_PDRV_GENIRQ If you don't know what to do here, say N. +config UIO_DMEM_GENIRQ + tristate "Userspace platform driver with generic irq and dynamic memory" + help + Platform driver for Userspace I/O devices, including generic + interrupt handling code. Shared interrupts are not supported. + + Memory regions can be specified with the same platform device + resources as the UIO_PDRV drivers, but dynamic regions can also + be specified. + The number and size of these regions is static, + but the memory allocation is not performed until + the associated device file is opened. The + memory is freed once the uio device is closed. + + If you don't know what to do here, say N. + config UIO_AEC tristate "AEC video timestamp device" depends on PCI diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile index d4dd9a5..b354c53 100644 --- a/drivers/uio/Makefile +++ b/drivers/uio/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_UIO) += uio.o obj-$(CONFIG_UIO_CIF) += uio_cif.o obj-$(CONFIG_UIO_PDRV) += uio_pdrv.o obj-$(CONFIG_UIO_PDRV_GENIRQ) += uio_pdrv_genirq.o +obj-$(CONFIG_UIO_DMEM_GENIRQ) += uio_dmem_genirq.o obj-$(CONFIG_UIO_AEC) += uio_aec.o obj-$(CONFIG_UIO_SERCOS3) += uio_sercos3.o obj-$(CONFIG_UIO_PCI_GENERIC) += uio_pci_generic.o diff --git a/drivers/uio/uio_dmem_genirq.c b/drivers/uio/uio_dmem_genirq.c new file mode 100644 index 0000000..4d4dd00 --- /dev/null +++ b/drivers/uio/uio_dmem_genirq.c @@ -0,0 +1,354 @@ +/* + * drivers/uio/uio_dmem_genirq.c + * + * Userspace I/O platform driver with generic IRQ handling code. + * + * Copyright (C) 2012 Damian Hobson-Garcia + * + * Based on uio_pdrv_genirq.c by Magnus Damm + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define DRIVER_NAME "uio_dmem_genirq" + +struct uio_dmem_genirq_platdata { + struct uio_info *uioinfo; + spinlock_t lock; + unsigned long flags; + struct platform_device *pdev; + unsigned int dmem_region_start; + unsigned int num_dmem_regions; + struct mutex alloc_lock; + unsigned int refcnt; +}; + +static int uio_dmem_genirq_open(struct uio_info *info, struct inode *inode) +{ + struct uio_dmem_genirq_platdata *priv = info->priv; + struct uio_mem *uiomem; + int ret = 0; + + uiomem = &priv->uioinfo->mem[priv->dmem_region_start]; + + mutex_lock(&priv->alloc_lock); + while (!priv->refcnt && uiomem < &priv->uioinfo->mem[MAX_UIO_MAPS]) { + void *addr; + if (!uiomem->size) + break; + + addr = dma_alloc_coherent(&priv->pdev->dev, uiomem->size, + (dma_addr_t *)&uiomem->addr, GFP_KERNEL); + if (!addr) { + ret = -ENOMEM; + break; + } + + uiomem->internal_addr = addr; + ++uiomem; + } + priv->refcnt++; + + mutex_unlock(&priv->alloc_lock); + /* Wait until the Runtime PM code has woken up the device */ + pm_runtime_get_sync(&priv->pdev->dev); + return ret; +} + +static int uio_dmem_genirq_release(struct uio_info *info, struct inode *inode) +{ + struct uio_dmem_genirq_platdata *priv = info->priv; + struct uio_mem *uiomem; + + /* Tell the Runtime PM code that the device has become idle */ + pm_runtime_put_sync(&priv->pdev->dev); + + uiomem = &priv->uioinfo->mem[priv->dmem_region_start]; + + mutex_lock(&priv->alloc_lock); + + priv->refcnt--; + while (!priv->refcnt && uiomem < &priv->uioinfo->mem[MAX_UIO_MAPS]) { + if (!uiomem->size) + break; + + dma_free_coherent(&priv->pdev->dev, uiomem->size, + uiomem->internal_addr, uiomem->addr); + uiomem->addr = DMA_ERROR_CODE; + ++uiomem; + } + + mutex_unlock(&priv->alloc_lock); + return 0; +} + +static irqreturn_t uio_dmem_genirq_handler(int irq, struct uio_info *dev_info) +{ + struct uio_dmem_genirq_platdata *priv = dev_info->priv; + + /* Just disable the interrupt in the interrupt controller, and + * remember the state so we can allow user space to enable it later. + */ + + if (!test_and_set_bit(0, &priv->flags)) + disable_irq_nosync(irq); + + return IRQ_HANDLED; +} + +static int uio_dmem_genirq_irqcontrol(struct uio_info *dev_info, s32 irq_on) +{ + struct uio_dmem_genirq_platdata *priv = dev_info->priv; + unsigned long flags; + + /* Allow user space to enable and disable the interrupt + * in the interrupt controller, but keep track of the + * state to prevent per-irq depth damage. + * + * Serialize this operation to support multiple tasks. + */ + + spin_lock_irqsave(&priv->lock, flags); + if (irq_on) { + if (test_and_clear_bit(0, &priv->flags)) + enable_irq(dev_info->irq); + } else { + if (!test_and_set_bit(0, &priv->flags)) + disable_irq(dev_info->irq); + } + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +static int uio_dmem_genirq_probe(struct platform_device *pdev) +{ + struct uio_dmem_genirq_pdata *pdata = pdev->dev.platform_data; + struct uio_info *uioinfo = &pdata->uioinfo; + struct uio_dmem_genirq_platdata *priv; + struct uio_mem *uiomem; + int ret = -EINVAL; + int i; + + if (!uioinfo) { + int irq; + + /* alloc uioinfo for one device */ + uioinfo = kzalloc(sizeof(*uioinfo), GFP_KERNEL); + if (!uioinfo) { + ret = -ENOMEM; + dev_err(&pdev->dev, "unable to kmalloc\n"); + goto bad2; + } + uioinfo->name = pdev->dev.of_node->name; + uioinfo->version = "devicetree"; + + /* Multiple IRQs are not supported */ + irq = platform_get_irq(pdev, 0); + if (irq == -ENXIO) + uioinfo->irq = UIO_IRQ_NONE; + else + uioinfo->irq = irq; + } + + if (!uioinfo || !uioinfo->name || !uioinfo->version) { + dev_err(&pdev->dev, "missing platform_data\n"); + goto bad0; + } + + if (uioinfo->handler || uioinfo->irqcontrol || + uioinfo->irq_flags & IRQF_SHARED) { + dev_err(&pdev->dev, "interrupt configuration error\n"); + goto bad0; + } + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) { + ret = -ENOMEM; + dev_err(&pdev->dev, "unable to kmalloc\n"); + goto bad0; + } + + dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); + + priv->uioinfo = uioinfo; + spin_lock_init(&priv->lock); + priv->flags = 0; /* interrupt is enabled to begin with */ + priv->pdev = pdev; + mutex_init(&priv->alloc_lock); + + if (!uioinfo->irq) { + ret = platform_get_irq(pdev, 0); + if (ret < 0) { + dev_err(&pdev->dev, "failed to get IRQ\n"); + goto bad0; + } + uioinfo->irq = ret; + } + uiomem = &uioinfo->mem[0]; + + for (i = 0; i < pdev->num_resources; ++i) { + struct resource *r = &pdev->resource[i]; + + if (r->flags != IORESOURCE_MEM) + continue; + + if (uiomem >= &uioinfo->mem[MAX_UIO_MAPS]) { + dev_warn(&pdev->dev, "device has more than " + __stringify(MAX_UIO_MAPS) + " I/O memory resources.\n"); + break; + } + + uiomem->memtype = UIO_MEM_PHYS; + uiomem->addr = r->start; + uiomem->size = resource_size(r); + ++uiomem; + } + + priv->dmem_region_start = i; + priv->num_dmem_regions = pdata->num_dynamic_regions; + + for (i = 0; i < pdata->num_dynamic_regions; ++i) { + if (uiomem >= &uioinfo->mem[MAX_UIO_MAPS]) { + dev_warn(&pdev->dev, "device has more than " + __stringify(MAX_UIO_MAPS) + " dynamic and fixed memory regions.\n"); + break; + } + uiomem->memtype = UIO_MEM_PHYS; + uiomem->addr = DMA_ERROR_CODE; + uiomem->size = pdata->dynamic_region_sizes[i]; + ++uiomem; + } + + while (uiomem < &uioinfo->mem[MAX_UIO_MAPS]) { + uiomem->size = 0; + ++uiomem; + } + + /* This driver requires no hardware specific kernel code to handle + * interrupts. Instead, the interrupt handler simply disables the + * interrupt in the interrupt controller. User space is responsible + * for performing hardware specific acknowledge and re-enabling of + * the interrupt in the interrupt controller. + * + * Interrupt sharing is not supported. + */ + + uioinfo->handler = uio_dmem_genirq_handler; + uioinfo->irqcontrol = uio_dmem_genirq_irqcontrol; + uioinfo->open = uio_dmem_genirq_open; + uioinfo->release = uio_dmem_genirq_release; + uioinfo->priv = priv; + + /* Enable Runtime PM for this device: + * The device starts in suspended state to allow the hardware to be + * turned off by default. The Runtime PM bus code should power on the + * hardware and enable clocks at open(). + */ + pm_runtime_enable(&pdev->dev); + + ret = uio_register_device(&pdev->dev, priv->uioinfo); + if (ret) { + dev_err(&pdev->dev, "unable to register uio device\n"); + goto bad1; + } + + platform_set_drvdata(pdev, priv); + return 0; + bad1: + kfree(priv); + pm_runtime_disable(&pdev->dev); + bad0: + /* kfree uioinfo for OF */ + if (pdev->dev.of_node) + kfree(uioinfo); + bad2: + return ret; +} + +static int uio_dmem_genirq_remove(struct platform_device *pdev) +{ + struct uio_dmem_genirq_platdata *priv = platform_get_drvdata(pdev); + + uio_unregister_device(priv->uioinfo); + pm_runtime_disable(&pdev->dev); + + priv->uioinfo->handler = NULL; + priv->uioinfo->irqcontrol = NULL; + + /* kfree uioinfo for OF */ + if (pdev->dev.of_node) + kfree(priv->uioinfo); + + kfree(priv); + return 0; +} + +static int uio_dmem_genirq_runtime_nop(struct device *dev) +{ + /* Runtime PM callback shared between ->runtime_suspend() + * and ->runtime_resume(). Simply returns success. + * + * In this driver pm_runtime_get_sync() and pm_runtime_put_sync() + * are used at open() and release() time. This allows the + * Runtime PM code to turn off power to the device while the + * device is unused, ie before open() and after release(). + * + * This Runtime PM callback does not need to save or restore + * any registers since user space is responsbile for hardware + * register reinitialization after open(). + */ + return 0; +} + +static const struct dev_pm_ops uio_dmem_genirq_dev_pm_ops = { + .runtime_suspend = uio_dmem_genirq_runtime_nop, + .runtime_resume = uio_dmem_genirq_runtime_nop, +}; + +#ifdef CONFIG_OF +static const struct of_device_id uio_of_genirq_match[] = { + { /* empty for now */ }, +}; +MODULE_DEVICE_TABLE(of, uio_of_genirq_match); +#else +# define uio_of_genirq_match NULL +#endif + +static struct platform_driver uio_dmem_genirq = { + .probe = uio_dmem_genirq_probe, + .remove = uio_dmem_genirq_remove, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .pm = &uio_dmem_genirq_dev_pm_ops, + .of_match_table = uio_of_genirq_match, + }, +}; + +module_platform_driver(uio_dmem_genirq); + +MODULE_AUTHOR("Damian Hobson-Garcia"); +MODULE_DESCRIPTION("Userspace I/O platform driver with dynamic memory."); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/include/linux/platform_data/uio_dmem_genirq.h b/include/linux/platform_data/uio_dmem_genirq.h new file mode 100644 index 0000000..973c1bb --- /dev/null +++ b/include/linux/platform_data/uio_dmem_genirq.h @@ -0,0 +1,26 @@ +/* + * include/linux/platform_data/uio_dmem_genirq.h + * + * Copyright (C) 2012 Damian Hobson-Garcia + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _UIO_DMEM_GENIRQ_H +#define _UIO_DMEM_GENIRQ_H + +#include + +struct uio_dmem_genirq_pdata { + struct uio_info uioinfo; + unsigned int *dynamic_region_sizes; + unsigned int num_dynamic_regions; +}; +#endif /* _UIO_DMEM_GENIRQ_H */ -- cgit v0.10.2 From b533a83008c3fb4983c1213276790cacd39b518f Mon Sep 17 00:00:00 2001 From: Damian Hobson-Garcia Date: Tue, 25 Sep 2012 15:09:12 +0900 Subject: Add uio_dmem_genirq description to UIO documentation Signed-off-by: Damian Hobson-Garcia Signed-off-by: "Hans J. Koch" Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/DocBook/uio-howto.tmpl b/Documentation/DocBook/uio-howto.tmpl index ac3d001..fdbf86f 100644 --- a/Documentation/DocBook/uio-howto.tmpl +++ b/Documentation/DocBook/uio-howto.tmpl @@ -719,6 +719,62 @@ framework to set up sysfs files for this region. Simply leave it alone. + +Using uio_dmem_genirq for platform devices + + In addition to statically allocated memory ranges, they may also be + a desire to use dynamically allocated regions in a user space driver. + In particular, being able to access memory made available through the + dma-mapping API, may be particularly useful. The + uio_dmem_genirq driver provides a way to accomplish + this. + + + This driver is used in a similar manner to the + "uio_pdrv_genirq" driver with respect to interrupt + configuration and handling. + + + Set the .name element of + struct platform_device to + "uio_dmem_genirq" to use this driver. + + + When using this driver, fill in the .platform_data + element of struct platform_device, which is of type + struct uio_dmem_genirq_pdata and which contains the + following elements: + + + struct uio_info uioinfo: The same + structure used as the uio_pdrv_genirq platform + data + unsigned int *dynamic_region_sizes: + Pointer to list of sizes of dynamic memory regions to be mapped into + user space. + + unsigned int num_dynamic_regions: + Number of elements in dynamic_region_sizes array. + + + + The dynamic regions defined in the platform data will be appended to + the mem[] array after the platform device + resources, which implies that the total number of static and dynamic + memory regions cannot exceed MAX_UIO_MAPS. + + + The dynamic memory regions will be allocated when the UIO device file, + /dev/uioX is opened. + Simiar to static memory resources, the memory region information for + dynamic regions is then visible via sysfs at + /sys/class/uio/uioX/maps/mapY/*. + The dynmaic memory regions will be freed when the UIO device file is + closed. When no processes are holding the device file open, the address + returned to userspace is DMA_ERROR_CODE. + + + -- cgit v0.10.2 From 8b5c8b6396bc008fc23ade51a260594d59db4749 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Fri, 12 Oct 2012 13:22:41 -0700 Subject: Drivers: hv: Get rid of unnecessary forward declarations Get rid of unnecessary forward declarations. Signed-off-by: K. Y. Srinivasan Reviewed-by: Haiyang Zhang Reported-by: Jason Wang Acked-by: Jason Wang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index 4065374..1bb1a80 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -33,14 +33,6 @@ #define NUM_PAGES_SPANNED(addr, len) \ ((PAGE_ALIGN(addr + len) >> PAGE_SHIFT) - (addr >> PAGE_SHIFT)) -/* Internal routines */ -static int create_gpadl_header( - void *kbuffer, /* must be phys and virt contiguous */ - u32 size, /* page-size multiple */ - struct vmbus_channel_msginfo **msginfo, - u32 *messagecount); -static void vmbus_setevent(struct vmbus_channel *channel); - /* * vmbus_setevent- Trigger an event notification on the specified * channel. -- cgit v0.10.2 From b45635542ede4ffeecb8fc4a1033ac5511ec2439 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 22 Oct 2012 17:20:20 +0800 Subject: Drivers: hv: remove unused variable from channel_mgmt.c The variables guidtype, guidinstance and initiate are initialized but never used otherwise, so remove the unused variables. dpatch engine is used to auto generate this patch. (https://github.com/weiyj/dpatch) Signed-off-by: Wei Yongjun Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index 2b8b8d4..2f84c5c 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -265,14 +265,9 @@ static void vmbus_onoffer(struct vmbus_channel_message_header *hdr) { struct vmbus_channel_offer_channel *offer; struct vmbus_channel *newchannel; - uuid_le *guidtype; - uuid_le *guidinstance; offer = (struct vmbus_channel_offer_channel *)hdr; - guidtype = &offer->offer.if_type; - guidinstance = &offer->offer.if_instance; - /* Allocate the channel object and save this offer. */ newchannel = alloc_channel(); if (!newchannel) { @@ -470,7 +465,6 @@ static void vmbus_onversion_response( { struct vmbus_channel_msginfo *msginfo; struct vmbus_channel_message_header *requestheader; - struct vmbus_channel_initiate_contact *initiate; struct vmbus_channel_version_response *version_response; unsigned long flags; @@ -484,8 +478,6 @@ static void vmbus_onversion_response( if (requestheader->msgtype == CHANNELMSG_INITIATE_CONTACT) { - initiate = - (struct vmbus_channel_initiate_contact *)requestheader; memcpy(&msginfo->response.version_response, version_response, sizeof(struct vmbus_channel_version_response)); -- cgit v0.10.2 From 12b9f8a20d6596c8ea7786532a4a55dacf71020c Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 23 Oct 2012 13:03:27 -0700 Subject: drivers/w1/masters: remove CONFIG_EXPERIMENTAL This config item has not carried much meaning for a while now and is almost always enabled by default. As agreed during the Linux kernel summit, remove it. CC: Andrew Morton CC: Paul Walmsley CC: Felipe Balbi Signed-off-by: Kees Cook Acked-by: Evgeniy Polyakov Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/w1/masters/Kconfig b/drivers/w1/masters/Kconfig index 7e98403..c433a74 100644 --- a/drivers/w1/masters/Kconfig +++ b/drivers/w1/masters/Kconfig @@ -26,7 +26,7 @@ config W1_MASTER_DS2490 config W1_MASTER_DS2482 tristate "Maxim DS2482 I2C to 1-Wire bridge" - depends on I2C && EXPERIMENTAL + depends on I2C help If you say yes here you get support for the Maxim DS2482 I2C to 1-Wire bridge. -- cgit v0.10.2 From 1b3c16556a386fa019c48783f0f615fb416cb53b Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 23 Oct 2012 13:24:09 +0800 Subject: pc8736x_gpio: use platform_device_unregister in pc8736x_gpio_cleanup() platform_device_unregister() only calls platform_device_del() and platform_device_put(), thus use platform_device_unregister() to simplify the code. Also the documents in platform.c shows that platform_device_del and platform_device_put must _only_ be externally called in error cases. All other usage is a bug. dpatch engine is used to auto generate this patch. (https://github.com/weiyj/dpatch) Signed-off-by: Wei Yongjun Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/char/pc8736x_gpio.c b/drivers/char/pc8736x_gpio.c index b304ec0..3f79a9f 100644 --- a/drivers/char/pc8736x_gpio.c +++ b/drivers/char/pc8736x_gpio.c @@ -345,8 +345,7 @@ static void __exit pc8736x_gpio_cleanup(void) unregister_chrdev_region(MKDEV(major,0), PC8736X_GPIO_CT); release_region(pc8736x_gpio_base, PC8736X_GPIO_RANGE); - platform_device_del(pdev); - platform_device_put(pdev); + platform_device_unregister(pdev); } module_init(pc8736x_gpio_init); -- cgit v0.10.2 From 35299f884aa301deefb0881096e6d88d0964c94b Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 8 Oct 2012 10:44:47 +0800 Subject: drivers:misc: ti-st: fix potential NULL pointer dereference in st_register() Remove the pointless NULL dereference above the NULL test. dpatch engine is used to auto generate this patch. (https://github.com/weiyj/dpatch) Signed-off-by: Wei Yongjun Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c index 46937b1..b90a224 100644 --- a/drivers/misc/ti-st/st_core.c +++ b/drivers/misc/ti-st/st_core.c @@ -511,7 +511,6 @@ long st_register(struct st_proto_s *new_proto) unsigned long flags = 0; st_kim_ref(&st_gdata, 0); - pr_info("%s(%d) ", __func__, new_proto->chnl_id); if (st_gdata == NULL || new_proto == NULL || new_proto->recv == NULL || new_proto->reg_complete_cb == NULL) { pr_err("gdata/new_proto/recv or reg_complete_cb not ready"); -- cgit v0.10.2 From dbfd5ccc057fbefb7247614741efbf96be0258c5 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 8 Oct 2012 22:06:07 +0800 Subject: w1/ds2482: use module_i2c_driver to simplify the code Use the module_i2c_driver() macro to make the code smaller and a bit simpler. dpatch engine is used to auto generate this patch. (https://github.com/weiyj/dpatch) Signed-off-by: Wei Yongjun Acked-by: Evgeniy Polyakov Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/w1/masters/ds2482.c b/drivers/w1/masters/ds2482.c index e5f7441..6429b9e 100644 --- a/drivers/w1/masters/ds2482.c +++ b/drivers/w1/masters/ds2482.c @@ -505,19 +505,8 @@ static int ds2482_remove(struct i2c_client *client) return 0; } -static int __init sensors_ds2482_init(void) -{ - return i2c_add_driver(&ds2482_driver); -} - -static void __exit sensors_ds2482_exit(void) -{ - i2c_del_driver(&ds2482_driver); -} +module_i2c_driver(ds2482_driver); MODULE_AUTHOR("Ben Gardner "); MODULE_DESCRIPTION("DS2482 driver"); MODULE_LICENSE("GPL"); - -module_init(sensors_ds2482_init); -module_exit(sensors_ds2482_exit); -- cgit v0.10.2 From f426a36cecfea2cfd69c28ca5ba4f4bfae913f63 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Thu, 25 Oct 2012 14:15:49 -0700 Subject: tools: hv: Return the full kernel version Currently, we are returning the same string for both OSBuildNumber and OSVersion keys. Return the full uts string for the OSBuild key since Windows does not impose any restrictions on this. Signed-off-by: K. Y. Srinivasan Reviewed-by: Haiyang Zhang Reported-by: Claudio Latini Signed-off-by: Greg Kroah-Hartman diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index 5959aff..6c7bcb9 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c @@ -88,6 +88,7 @@ static char *os_major = ""; static char *os_minor = ""; static char *processor_arch; static char *os_build; +static char *os_version; static char *lic_version = "Unknown version"; static struct utsname uts_buf; @@ -453,7 +454,9 @@ void kvp_get_os_info(void) char *p, buf[512]; uname(&uts_buf); - os_build = uts_buf.release; + os_version = uts_buf.release; + os_build = strdup(uts_buf.release); + os_name = uts_buf.sysname; processor_arch = uts_buf.machine; @@ -462,7 +465,7 @@ void kvp_get_os_info(void) * string to be of the form: x.y.z * Strip additional information we may have. */ - p = strchr(os_build, '-'); + p = strchr(os_version, '-'); if (p) *p = '\0'; @@ -1649,7 +1652,7 @@ int main(void) strcpy(key_name, "OSMinorVersion"); break; case OSVersion: - strcpy(key_value, os_build); + strcpy(key_value, os_version); strcpy(key_name, "OSVersion"); break; case ProcessorArchitecture: -- cgit v0.10.2 From 3321e738d6f0a82b2c19f9d5890f304dab1e5357 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Thu, 25 Oct 2012 14:15:50 -0700 Subject: Tools: hv: Don't return loopback addresses Don't return loopback addresses and further don't terminate the IP address strings with a semicolon. This is the current behavior of Windows guests. Signed-off-by: K. Y. Srinivasan Reviewed-by: Haiyang Zhang Reported-by: Claudio Latini Signed-off-by: Greg Kroah-Hartman diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index 6c7bcb9..13c2a14 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c @@ -43,6 +43,7 @@ #include #include #include +#include /* * KVP protocol: The user mode component first registers with the @@ -882,7 +883,7 @@ static int kvp_process_ip_address(void *addrp, addr_length = INET6_ADDRSTRLEN; } - if ((length - *offset) < addr_length + 1) + if ((length - *offset) < addr_length + 2) return HV_E_FAIL; if (str == NULL) { strcpy(buffer, "inet_ntop failed\n"); @@ -890,11 +891,13 @@ static int kvp_process_ip_address(void *addrp, } if (*offset == 0) strcpy(buffer, tmp); - else + else { + strcat(buffer, ";"); strcat(buffer, tmp); - strcat(buffer, ";"); + } *offset += strlen(str) + 1; + return 0; } @@ -956,7 +959,9 @@ kvp_get_ip_info(int family, char *if_name, int op, * supported address families; if not we gather info on * the specified address family. */ - if ((family != 0) && (curp->ifa_addr->sa_family != family)) { + if ((((family != 0) && + (curp->ifa_addr->sa_family != family))) || + (curp->ifa_flags & IFF_LOOPBACK)) { curp = curp->ifa_next; continue; } -- cgit v0.10.2 From b0d0cf77e72a9d233015f8f21e9dfc9d9b5d0711 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 1 Nov 2012 21:17:13 +0200 Subject: mei: mei_write: revamp function flow Use goto statement for error handling instead of deeper if constructs and rename label 'unlock_dev' to more appropriate 'err' Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index ed4943f..7a03d77 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -543,24 +543,24 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, if (dev->dev_state != MEI_DEV_ENABLED) { rets = -ENODEV; - goto unlock_dev; + goto err; } i = mei_me_cl_by_id(dev, cl->me_client_id); if (i < 0) { rets = -ENODEV; - goto unlock_dev; + goto err; } if (length > dev->me_clients[i].props.max_msg_length || length <= 0) { rets = -EMSGSIZE; - goto unlock_dev; + goto err; } if (cl->state != MEI_FILE_CONNECTED) { rets = -ENODEV; dev_err(&dev->pdev->dev, "host client = %d, is not connected to ME client = %d", cl->host_client_id, cl->me_client_id); - goto unlock_dev; + goto err; } if (cl == &dev->iamthif_cl) { write_cb = find_amthi_read_list_entry(dev, file); @@ -599,17 +599,17 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, if (!write_cb) { dev_err(&dev->pdev->dev, "write cb allocation failed\n"); rets = -ENOMEM; - goto unlock_dev; + goto err; } rets = mei_io_cb_alloc_req_buf(write_cb, length); if (rets) - goto unlock_dev; + goto err; dev_dbg(&dev->pdev->dev, "cb request size = %zd\n", length); rets = copy_from_user(write_cb->request_buffer.data, ubuf, length); if (rets) - goto unlock_dev; + goto err; cl->sm_state = 0; if (length == 4 && @@ -624,7 +624,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, if (cl == &dev->iamthif_cl) { rets = mei_io_cb_alloc_resp_buf(write_cb, dev->iamthif_mtu); if (rets) - goto unlock_dev; + goto err; write_cb->major_file_operations = MEI_IOCTL; @@ -641,7 +641,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, if (rets) { dev_err(&dev->pdev->dev, "amthi write failed with status = %d\n", rets); - goto unlock_dev; + goto err; } } mutex_unlock(&dev->device_lock); @@ -654,51 +654,51 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, cl->host_client_id, cl->me_client_id); rets = mei_flow_ctrl_creds(dev, cl); if (rets < 0) - goto unlock_dev; + goto err; - if (rets && dev->mei_host_buffer_is_empty) { - rets = 0; - dev->mei_host_buffer_is_empty = false; - if (length > mei_hbuf_max_data(dev)) { - mei_hdr.length = mei_hbuf_max_data(dev); - mei_hdr.msg_complete = 0; - } else { - mei_hdr.length = length; - mei_hdr.msg_complete = 1; - } - mei_hdr.host_addr = cl->host_client_id; - mei_hdr.me_addr = cl->me_client_id; - mei_hdr.reserved = 0; - dev_dbg(&dev->pdev->dev, "call mei_write_message header=%08x.\n", - *((u32 *) &mei_hdr)); - if (mei_write_message(dev, &mei_hdr, - (unsigned char *) (write_cb->request_buffer.data), - mei_hdr.length)) { - rets = -ENODEV; - goto unlock_dev; - } + if (rets == 0 || dev->mei_host_buffer_is_empty == false) { + write_cb->buf_idx = 0; + mei_hdr.msg_complete = 0; cl->writing_state = MEI_WRITING; - write_cb->buf_idx = mei_hdr.length; - if (mei_hdr.msg_complete) { - if (mei_flow_ctrl_reduce(dev, cl)) { - rets = -ENODEV; - goto unlock_dev; - } - list_add_tail(&write_cb->list, &dev->write_waiting_list.list); - } else { - list_add_tail(&write_cb->list, &dev->write_list.list); - } + goto out; + } + dev->mei_host_buffer_is_empty = false; + if (length > mei_hbuf_max_data(dev)) { + mei_hdr.length = mei_hbuf_max_data(dev); + mei_hdr.msg_complete = 0; } else { + mei_hdr.length = length; + mei_hdr.msg_complete = 1; + } + mei_hdr.host_addr = cl->host_client_id; + mei_hdr.me_addr = cl->me_client_id; + mei_hdr.reserved = 0; + dev_dbg(&dev->pdev->dev, "call mei_write_message header=%08x.\n", + *((u32 *) &mei_hdr)); + if (mei_write_message(dev, &mei_hdr, + write_cb->request_buffer.data, mei_hdr.length)) { + rets = -ENODEV; + goto err; + } + cl->writing_state = MEI_WRITING; + write_cb->buf_idx = mei_hdr.length; - write_cb->buf_idx = 0; - cl->writing_state = MEI_WRITING; +out: + if (mei_hdr.msg_complete) { + if (mei_flow_ctrl_reduce(dev, cl)) { + rets = -ENODEV; + goto err; + } + list_add_tail(&write_cb->list, &dev->write_waiting_list.list); + } else { list_add_tail(&write_cb->list, &dev->write_list.list); } + mutex_unlock(&dev->device_lock); return length; -unlock_dev: +err: mutex_unlock(&dev->device_lock); mei_io_cb_free(write_cb); return rets; -- cgit v0.10.2 From 3870c3206b96c900ce29c8068bd5ad46fae71f5b Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 1 Nov 2012 21:17:14 +0200 Subject: mei: normalize timeouts definitions 1. The hardware book defines timeouts in seconds so we stick to this and define the wrapper function mei_secs_to_jiffies around msecs_to_jiffies to use be used instead multiplying by HZ 2. We add name space prefix MEI_ to all timer defines Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h index 9700532..f21721a 100644 --- a/drivers/misc/mei/hw.h +++ b/drivers/misc/mei/hw.h @@ -20,16 +20,16 @@ #include /* - * Timeouts + * Timeouts in Seconds */ -#define MEI_INTEROP_TIMEOUT (HZ * 7) -#define MEI_CONNECT_TIMEOUT 3 /* at least 2 seconds */ +#define MEI_INTEROP_TIMEOUT 7 /* Timeout on ready message */ +#define MEI_CONNECT_TIMEOUT 3 /* HPS: at least 2 seconds */ -#define CONNECT_TIMEOUT 15 /* HPS definition */ -#define INIT_CLIENTS_TIMEOUT 15 /* HPS definition */ +#define MEI_CL_CONNECT_TIMEOUT 15 /* HPS: Client Connect Timeout */ +#define MEI_CLIENTS_INIT_TIMEOUT 15 /* HPS: Clients Enumeration Timeout */ -#define IAMTHIF_STALL_TIMER 12 /* seconds */ -#define IAMTHIF_READ_TIMER 10000 /* ms */ +#define MEI_IAMTHIF_STALL_TIMER 12 /* HPS */ +#define MEI_IAMTHIF_READ_TIMER 10 /* HPS */ /* * Internal Clients Number diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index 1f13eb9..e6951ec 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c @@ -184,7 +184,8 @@ int mei_hw_init(struct mei_device *dev) if (!dev->recvd_msg) { mutex_unlock(&dev->device_lock); err = wait_event_interruptible_timeout(dev->wait_recvd_msg, - dev->recvd_msg, MEI_INTEROP_TIMEOUT); + dev->recvd_msg, + mei_secs_to_jiffies(MEI_INTEROP_TIMEOUT)); mutex_lock(&dev->device_lock); } @@ -381,7 +382,7 @@ void mei_host_start_message(struct mei_device *dev) mei_reset(dev, 1); } dev->init_clients_state = MEI_START_MESSAGE; - dev->init_clients_timer = INIT_CLIENTS_TIMEOUT; + dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; return ; } @@ -414,7 +415,7 @@ void mei_host_enum_clients_message(struct mei_device *dev) mei_reset(dev, 1); } dev->init_clients_state = MEI_ENUM_CLIENTS_MESSAGE; - dev->init_clients_timer = INIT_CLIENTS_TIMEOUT; + dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; return; } @@ -502,7 +503,7 @@ int mei_host_client_properties(struct mei_device *dev) return -EIO; } - dev->init_clients_timer = INIT_CLIENTS_TIMEOUT; + dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; dev->me_client_index = b; return 1; } @@ -621,7 +622,7 @@ void mei_host_init_iamthif(struct mei_device *dev) dev->iamthif_cl.state = MEI_FILE_DISCONNECTED; dev->iamthif_cl.host_client_id = 0; } else { - dev->iamthif_cl.timer_count = CONNECT_TIMEOUT; + dev->iamthif_cl.timer_count = MEI_CONNECT_TIMEOUT; } } @@ -658,9 +659,8 @@ struct mei_cl *mei_cl_allocate(struct mei_device *dev) */ int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl) { - int rets, err; - long timeout = 15; /* 15 seconds */ struct mei_cl_cb *cb; + int rets, err; if (!dev || !cl) return -ENODEV; @@ -690,8 +690,8 @@ int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl) mutex_unlock(&dev->device_lock); err = wait_event_timeout(dev->wait_recvd_msg, - (MEI_FILE_DISCONNECTED == cl->state), - timeout * HZ); + MEI_FILE_DISCONNECTED == cl->state, + mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT)); mutex_lock(&dev->device_lock); if (MEI_FILE_DISCONNECTED == cl->state) { diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 5c65bac..248f581 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -269,7 +269,7 @@ static int _mei_irq_thread_iamthif_read(struct mei_device *dev, s32 *slots) dev->iamthif_flow_control_pending = false; dev->iamthif_msg_buf_index = 0; dev->iamthif_msg_buf_size = 0; - dev->iamthif_stall_timer = IAMTHIF_STALL_TIMER; + dev->iamthif_stall_timer = MEI_IAMTHIF_STALL_TIMER; dev->mei_host_buffer_is_empty = mei_hbuf_is_empty(dev); return 0; } @@ -1379,7 +1379,7 @@ void mei_timer(struct work_struct *work) if (dev->iamthif_timer) { timeout = dev->iamthif_timer + - msecs_to_jiffies(IAMTHIF_READ_TIMER); + mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER); dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n", dev->iamthif_timer); diff --git a/drivers/misc/mei/iorw.c b/drivers/misc/mei/iorw.c index 541c157..8026cbf 100644 --- a/drivers/misc/mei/iorw.c +++ b/drivers/misc/mei/iorw.c @@ -173,7 +173,7 @@ int mei_ioctl_connect_client(struct file *file, struct mei_cl *cl; struct mei_cl *cl_pos = NULL; struct mei_cl *cl_next = NULL; - long timeout = CONNECT_TIMEOUT; + long timeout = mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT); int i; int err; int rets; @@ -291,8 +291,7 @@ int mei_ioctl_connect_client(struct file *file, mutex_unlock(&dev->device_lock); err = wait_event_timeout(dev->wait_recvd_msg, (MEI_FILE_CONNECTED == cl->state || - MEI_FILE_DISCONNECTED == cl->state), - timeout * HZ); + MEI_FILE_DISCONNECTED == cl->state), timeout); mutex_lock(&dev->device_lock); if (MEI_FILE_CONNECTED == cl->state) { @@ -415,7 +414,8 @@ int amthi_read(struct mei_device *dev, struct file *file, dev->iamthif_timer = 0; if (cb) { - timeout = cb->read_time + msecs_to_jiffies(IAMTHIF_READ_TIMER); + timeout = cb->read_time + + mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER); dev_dbg(&dev->pdev->dev, "amthi timeout = %lud\n", timeout); diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 7a03d77..659727a 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -567,7 +567,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, if (write_cb) { timeout = write_cb->read_time + - msecs_to_jiffies(IAMTHIF_READ_TIMER); + mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER); if (time_after(jiffies, timeout) || cl->reading_state == MEI_READ_COMPLETE) { diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 6adcb3f..32c951a 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -270,6 +270,11 @@ struct mei_device { bool iamthif_canceled; }; +static inline unsigned long mei_secs_to_jiffies(unsigned long sec) +{ + return msecs_to_jiffies(sec * MSEC_PER_SEC); +} + /* * mei init function prototypes diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c index d96c537..8edb054 100644 --- a/drivers/misc/mei/wd.c +++ b/drivers/misc/mei/wd.c @@ -85,7 +85,7 @@ int mei_wd_host_init(struct mei_device *dev) dev->wd_cl.host_client_id = 0; return -EIO; } - dev->wd_cl.timer_count = CONNECT_TIMEOUT; + dev->wd_cl.timer_count = MEI_CONNECT_TIMEOUT; return 0; } -- cgit v0.10.2 From 19838fb85306905a373b6449c1428791d653fc21 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 1 Nov 2012 21:17:15 +0200 Subject: mei: extract AMTHI functions into the amthif.c file Move AMT Host Interface functions into the new amthif.c file. All functions has now common prefix: mei_amthif_ Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/mei/Makefile b/drivers/misc/mei/Makefile index 57168db..0017842 100644 --- a/drivers/misc/mei/Makefile +++ b/drivers/misc/mei/Makefile @@ -8,4 +8,5 @@ mei-objs += interrupt.o mei-objs += interface.o mei-objs += iorw.o mei-objs += main.o +mei-objs += amthif.o mei-objs += wd.o diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c new file mode 100644 index 0000000..392203d --- /dev/null +++ b/drivers/misc/mei/amthif.c @@ -0,0 +1,572 @@ +/* + * + * Intel Management Engine Interface (Intel MEI) Linux driver + * Copyright (c) 2003-2012, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "mei_dev.h" +#include "hw.h" +#include +#include "interface.h" + +const uuid_le mei_amthi_guid = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, 0xac, + 0xa8, 0x46, 0xe0, 0xff, 0x65, + 0x81, 0x4c); + +/** + * mei_amthif_reset_params - initializes mei device iamthif + * + * @dev: the device structure + */ +void mei_amthif_reset_params(struct mei_device *dev) +{ + /* reset iamthif parameters. */ + dev->iamthif_current_cb = NULL; + dev->iamthif_msg_buf_size = 0; + dev->iamthif_msg_buf_index = 0; + dev->iamthif_canceled = false; + dev->iamthif_ioctl = false; + dev->iamthif_state = MEI_IAMTHIF_IDLE; + dev->iamthif_timer = 0; +} + +/** + * mei_amthif_host_init_ - mei initialization amthif client. + * + * @dev: the device structure + * + */ +void mei_amthif_host_init(struct mei_device *dev) +{ + int i; + unsigned char *msg_buf; + + mei_cl_init(&dev->iamthif_cl, dev); + dev->iamthif_cl.state = MEI_FILE_DISCONNECTED; + + /* find ME amthi client */ + i = mei_me_cl_update_filext(dev, &dev->iamthif_cl, + &mei_amthi_guid, MEI_IAMTHIF_HOST_CLIENT_ID); + if (i < 0) { + dev_dbg(&dev->pdev->dev, "failed to find iamthif client.\n"); + return; + } + + /* Assign iamthif_mtu to the value received from ME */ + + dev->iamthif_mtu = dev->me_clients[i].props.max_msg_length; + dev_dbg(&dev->pdev->dev, "IAMTHIF_MTU = %d\n", + dev->me_clients[i].props.max_msg_length); + + kfree(dev->iamthif_msg_buf); + dev->iamthif_msg_buf = NULL; + + /* allocate storage for ME message buffer */ + msg_buf = kcalloc(dev->iamthif_mtu, + sizeof(unsigned char), GFP_KERNEL); + if (!msg_buf) { + dev_dbg(&dev->pdev->dev, "memory allocation for ME message buffer failed.\n"); + return; + } + + dev->iamthif_msg_buf = msg_buf; + + if (mei_connect(dev, &dev->iamthif_cl)) { + dev_dbg(&dev->pdev->dev, "Failed to connect to AMTHI client\n"); + dev->iamthif_cl.state = MEI_FILE_DISCONNECTED; + dev->iamthif_cl.host_client_id = 0; + } else { + dev->iamthif_cl.timer_count = MEI_CONNECT_TIMEOUT; + } +} + +/** + * mei_amthif_find_read_list_entry - finds a amthilist entry for current file + * + * @dev: the device structure + * @file: pointer to file object + * + * returns returned a list entry on success, NULL on failure. + */ +struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev, + struct file *file) +{ + struct mei_cl *cl_temp; + struct mei_cl_cb *pos = NULL; + struct mei_cl_cb *next = NULL; + + list_for_each_entry_safe(pos, next, + &dev->amthi_read_complete_list.list, list) { + cl_temp = (struct mei_cl *)pos->file_private; + if (cl_temp && cl_temp == &dev->iamthif_cl && + pos->file_object == file) + return pos; + } + return NULL; +} + + +/** + * mei_amthif_read - read data from AMTHIF client + * + * @dev: the device structure + * @if_num: minor number + * @file: pointer to file object + * @*ubuf: pointer to user data in user space + * @length: data length to read + * @offset: data read offset + * + * Locking: called under "dev->device_lock" lock + * + * returns + * returned data length on success, + * zero if no data to read, + * negative on failure. + */ +int mei_amthif_read(struct mei_device *dev, struct file *file, + char __user *ubuf, size_t length, loff_t *offset) +{ + int rets; + int wait_ret; + struct mei_cl_cb *cb = NULL; + struct mei_cl *cl = file->private_data; + unsigned long timeout; + int i; + + /* Only Posible if we are in timeout */ + if (!cl || cl != &dev->iamthif_cl) { + dev_dbg(&dev->pdev->dev, "bad file ext.\n"); + return -ETIMEDOUT; + } + + i = mei_me_cl_by_id(dev, dev->iamthif_cl.me_client_id); + + if (i < 0) { + dev_dbg(&dev->pdev->dev, "amthi client not found.\n"); + return -ENODEV; + } + dev_dbg(&dev->pdev->dev, "checking amthi data\n"); + cb = mei_amthif_find_read_list_entry(dev, file); + + /* Check for if we can block or not*/ + if (cb == NULL && file->f_flags & O_NONBLOCK) + return -EAGAIN; + + + dev_dbg(&dev->pdev->dev, "waiting for amthi data\n"); + while (cb == NULL) { + /* unlock the Mutex */ + mutex_unlock(&dev->device_lock); + + wait_ret = wait_event_interruptible(dev->iamthif_cl.wait, + (cb = mei_amthif_find_read_list_entry(dev, file))); + + if (wait_ret) + return -ERESTARTSYS; + + dev_dbg(&dev->pdev->dev, "woke up from sleep\n"); + + /* Locking again the Mutex */ + mutex_lock(&dev->device_lock); + } + + + dev_dbg(&dev->pdev->dev, "Got amthi data\n"); + dev->iamthif_timer = 0; + + if (cb) { + timeout = cb->read_time + + mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER); + dev_dbg(&dev->pdev->dev, "amthi timeout = %lud\n", + timeout); + + if (time_after(jiffies, timeout)) { + dev_dbg(&dev->pdev->dev, "amthi Time out\n"); + /* 15 sec for the message has expired */ + list_del(&cb->list); + rets = -ETIMEDOUT; + goto free; + } + } + /* if the whole message will fit remove it from the list */ + if (cb->buf_idx >= *offset && length >= (cb->buf_idx - *offset)) + list_del(&cb->list); + else if (cb->buf_idx > 0 && cb->buf_idx <= *offset) { + /* end of the message has been reached */ + list_del(&cb->list); + rets = 0; + goto free; + } + /* else means that not full buffer will be read and do not + * remove message from deletion list + */ + + dev_dbg(&dev->pdev->dev, "amthi cb->response_buffer size - %d\n", + cb->response_buffer.size); + dev_dbg(&dev->pdev->dev, "amthi cb->buf_idx - %lu\n", cb->buf_idx); + + /* length is being turncated to PAGE_SIZE, however, + * the buf_idx may point beyond */ + length = min_t(size_t, length, (cb->buf_idx - *offset)); + + if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length)) + rets = -EFAULT; + else { + rets = length; + if ((*offset + length) < cb->buf_idx) { + *offset += length; + goto out; + } + } +free: + dev_dbg(&dev->pdev->dev, "free amthi cb memory.\n"); + *offset = 0; + mei_io_cb_free(cb); +out: + return rets; +} + +/** + * mei_amthif_write - write amthif data to amthif client + * + * @dev: the device structure + * @cb: mei call back struct + * + * returns 0 on success, <0 on failure. + */ +int mei_amthif_write(struct mei_device *dev, struct mei_cl_cb *cb) +{ + struct mei_msg_hdr mei_hdr; + int ret; + + if (!dev || !cb) + return -ENODEV; + + dev_dbg(&dev->pdev->dev, "write data to amthi client.\n"); + + dev->iamthif_state = MEI_IAMTHIF_WRITING; + dev->iamthif_current_cb = cb; + dev->iamthif_file_object = cb->file_object; + dev->iamthif_canceled = false; + dev->iamthif_ioctl = true; + dev->iamthif_msg_buf_size = cb->request_buffer.size; + memcpy(dev->iamthif_msg_buf, cb->request_buffer.data, + cb->request_buffer.size); + + ret = mei_flow_ctrl_creds(dev, &dev->iamthif_cl); + if (ret < 0) + return ret; + + if (ret && dev->mei_host_buffer_is_empty) { + ret = 0; + dev->mei_host_buffer_is_empty = false; + if (cb->request_buffer.size > mei_hbuf_max_data(dev)) { + mei_hdr.length = mei_hbuf_max_data(dev); + mei_hdr.msg_complete = 0; + } else { + mei_hdr.length = cb->request_buffer.size; + mei_hdr.msg_complete = 1; + } + + mei_hdr.host_addr = dev->iamthif_cl.host_client_id; + mei_hdr.me_addr = dev->iamthif_cl.me_client_id; + mei_hdr.reserved = 0; + dev->iamthif_msg_buf_index += mei_hdr.length; + if (mei_write_message(dev, &mei_hdr, + (unsigned char *)(dev->iamthif_msg_buf), + mei_hdr.length)) + return -ENODEV; + + if (mei_hdr.msg_complete) { + if (mei_flow_ctrl_reduce(dev, &dev->iamthif_cl)) + return -ENODEV; + dev->iamthif_flow_control_pending = true; + dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL; + dev_dbg(&dev->pdev->dev, "add amthi cb to write waiting list\n"); + dev->iamthif_current_cb = cb; + dev->iamthif_file_object = cb->file_object; + list_add_tail(&cb->list, &dev->write_waiting_list.list); + } else { + dev_dbg(&dev->pdev->dev, "message does not complete, so add amthi cb to write list.\n"); + list_add_tail(&cb->list, &dev->write_list.list); + } + } else { + if (!(dev->mei_host_buffer_is_empty)) + dev_dbg(&dev->pdev->dev, "host buffer is not empty"); + + dev_dbg(&dev->pdev->dev, "No flow control credentials, so add iamthif cb to write list.\n"); + list_add_tail(&cb->list, &dev->write_list.list); + } + return 0; +} + +/** + * mei_amthif_run_next_cmd + * + * @dev: the device structure + * + * returns 0 on success, <0 on failure. + */ +void mei_amthif_run_next_cmd(struct mei_device *dev) +{ + struct mei_cl *cl_tmp; + struct mei_cl_cb *pos = NULL; + struct mei_cl_cb *next = NULL; + int status; + + if (!dev) + return; + + dev->iamthif_msg_buf_size = 0; + dev->iamthif_msg_buf_index = 0; + dev->iamthif_canceled = false; + dev->iamthif_ioctl = true; + dev->iamthif_state = MEI_IAMTHIF_IDLE; + dev->iamthif_timer = 0; + dev->iamthif_file_object = NULL; + + dev_dbg(&dev->pdev->dev, "complete amthi cmd_list cb.\n"); + + list_for_each_entry_safe(pos, next, &dev->amthi_cmd_list.list, list) { + list_del(&pos->list); + cl_tmp = (struct mei_cl *)pos->file_private; + + if (cl_tmp && cl_tmp == &dev->iamthif_cl) { + status = mei_amthif_write(dev, pos); + if (status) { + dev_dbg(&dev->pdev->dev, + "amthi write failed status = %d\n", + status); + return; + } + break; + } + } +} + +/** + * mei_amthif_irq_process_completed - processes completed iamthif operation. + * + * @dev: the device structure. + * @slots: free slots. + * @cb_pos: callback block. + * @cl: private data of the file object. + * @cmpl_list: complete list. + * + * returns 0, OK; otherwise, error. + */ +int mei_amthif_irq_process_completed(struct mei_device *dev, s32 *slots, + struct mei_cl_cb *cb_pos, + struct mei_cl *cl, + struct mei_cl_cb *cmpl_list) +{ + struct mei_msg_hdr *mei_hdr; + + if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) + + dev->iamthif_msg_buf_size - + dev->iamthif_msg_buf_index)) { + mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; + mei_hdr->host_addr = cl->host_client_id; + mei_hdr->me_addr = cl->me_client_id; + mei_hdr->length = dev->iamthif_msg_buf_size - + dev->iamthif_msg_buf_index; + mei_hdr->msg_complete = 1; + mei_hdr->reserved = 0; + + *slots -= mei_data2slots(mei_hdr->length); + + if (mei_write_message(dev, mei_hdr, + (dev->iamthif_msg_buf + + dev->iamthif_msg_buf_index), + mei_hdr->length)) { + dev->iamthif_state = MEI_IAMTHIF_IDLE; + cl->status = -ENODEV; + list_del(&cb_pos->list); + return -ENODEV; + } else { + if (mei_flow_ctrl_reduce(dev, cl)) + return -ENODEV; + dev->iamthif_msg_buf_index += mei_hdr->length; + cb_pos->buf_idx = dev->iamthif_msg_buf_index; + cl->status = 0; + dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL; + dev->iamthif_flow_control_pending = true; + /* save iamthif cb sent to amthi client */ + dev->iamthif_current_cb = cb_pos; + list_move_tail(&cb_pos->list, + &dev->write_waiting_list.list); + + } + } else if (*slots == dev->hbuf_depth) { + /* buffer is still empty */ + mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; + mei_hdr->host_addr = cl->host_client_id; + mei_hdr->me_addr = cl->me_client_id; + mei_hdr->length = + (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr); + mei_hdr->msg_complete = 0; + mei_hdr->reserved = 0; + + *slots -= mei_data2slots(mei_hdr->length); + + if (mei_write_message(dev, mei_hdr, + (dev->iamthif_msg_buf + + dev->iamthif_msg_buf_index), + mei_hdr->length)) { + cl->status = -ENODEV; + list_del(&cb_pos->list); + } else { + dev->iamthif_msg_buf_index += mei_hdr->length; + } + return -EMSGSIZE; + } else { + return -EBADMSG; + } + + return 0; +} + +/** + * mei_amthif_irq_read_message - read routine after ISR to + * handle the read amthi message + * + * @complete_list: An instance of our list structure + * @dev: the device structure + * @mei_hdr: header of amthi message + * + * returns 0 on success, <0 on failure. + */ +int mei_amthif_irq_read_message(struct mei_cl_cb *complete_list, + struct mei_device *dev, struct mei_msg_hdr *mei_hdr) +{ + struct mei_cl *cl; + struct mei_cl_cb *cb; + unsigned char *buffer; + + BUG_ON(mei_hdr->me_addr != dev->iamthif_cl.me_client_id); + BUG_ON(dev->iamthif_state != MEI_IAMTHIF_READING); + + buffer = dev->iamthif_msg_buf + dev->iamthif_msg_buf_index; + BUG_ON(dev->iamthif_mtu < dev->iamthif_msg_buf_index + mei_hdr->length); + + mei_read_slots(dev, buffer, mei_hdr->length); + + dev->iamthif_msg_buf_index += mei_hdr->length; + + if (!mei_hdr->msg_complete) + return 0; + + dev_dbg(&dev->pdev->dev, + "amthi_message_buffer_index =%d\n", + mei_hdr->length); + + dev_dbg(&dev->pdev->dev, "completed amthi read.\n "); + if (!dev->iamthif_current_cb) + return -ENODEV; + + cb = dev->iamthif_current_cb; + dev->iamthif_current_cb = NULL; + + cl = (struct mei_cl *)cb->file_private; + if (!cl) + return -ENODEV; + + dev->iamthif_stall_timer = 0; + cb->buf_idx = dev->iamthif_msg_buf_index; + cb->read_time = jiffies; + if (dev->iamthif_ioctl && cl == &dev->iamthif_cl) { + /* found the iamthif cb */ + dev_dbg(&dev->pdev->dev, "complete the amthi read cb.\n "); + dev_dbg(&dev->pdev->dev, "add the amthi read cb to complete.\n "); + list_add_tail(&cb->list, &complete_list->list); + } + return 0; +} + +/** + * mei_amthif_irq_read - prepares to read amthif data. + * + * @dev: the device structure. + * @slots: free slots. + * + * returns 0, OK; otherwise, error. + */ +int mei_amthif_irq_read(struct mei_device *dev, s32 *slots) +{ + + if (((*slots) * sizeof(u32)) < (sizeof(struct mei_msg_hdr) + + sizeof(struct hbm_flow_control))) { + return -EMSGSIZE; + } + *slots -= mei_data2slots(sizeof(struct hbm_flow_control)); + if (mei_send_flow_control(dev, &dev->iamthif_cl)) { + dev_dbg(&dev->pdev->dev, "iamthif flow control failed\n"); + return -EIO; + } + + dev_dbg(&dev->pdev->dev, "iamthif flow control success\n"); + dev->iamthif_state = MEI_IAMTHIF_READING; + dev->iamthif_flow_control_pending = false; + dev->iamthif_msg_buf_index = 0; + dev->iamthif_msg_buf_size = 0; + dev->iamthif_stall_timer = MEI_IAMTHIF_STALL_TIMER; + dev->mei_host_buffer_is_empty = mei_hbuf_is_empty(dev); + return 0; +} + +/** + * mei_amthif_complete - complete amthif callback. + * + * @dev: the device structure. + * @cb_pos: callback block. + */ +void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb) +{ + if (dev->iamthif_canceled != 1) { + dev->iamthif_state = MEI_IAMTHIF_READ_COMPLETE; + dev->iamthif_stall_timer = 0; + memcpy(cb->response_buffer.data, + dev->iamthif_msg_buf, + dev->iamthif_msg_buf_index); + list_add_tail(&cb->list, &dev->amthi_read_complete_list.list); + dev_dbg(&dev->pdev->dev, "amthi read completed\n"); + dev->iamthif_timer = jiffies; + dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n", + dev->iamthif_timer); + } else { + mei_amthif_run_next_cmd(dev); + } + + dev_dbg(&dev->pdev->dev, "completing amthi call back.\n"); + wake_up_interruptible(&dev->iamthif_cl.wait); +} + + diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index e6951ec..4a8eb92 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c @@ -43,10 +43,6 @@ const char *mei_dev_state_str(int state) } -const uuid_le mei_amthi_guid = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, 0xac, - 0xa8, 0x46, 0xe0, 0xff, 0x65, - 0x81, 0x4c); - /** * mei_io_list_flush - removes list entry belonging to cl. * @@ -92,23 +88,6 @@ int mei_cl_flush_queues(struct mei_cl *cl) /** - * mei_reset_iamthif_params - initializes mei device iamthif - * - * @dev: the device structure - */ -static void mei_reset_iamthif_params(struct mei_device *dev) -{ - /* reset iamthif parameters. */ - dev->iamthif_current_cb = NULL; - dev->iamthif_msg_buf_size = 0; - dev->iamthif_msg_buf_index = 0; - dev->iamthif_canceled = false; - dev->iamthif_ioctl = false; - dev->iamthif_state = MEI_IAMTHIF_IDLE; - dev->iamthif_timer = 0; -} - -/** * init_mei_device - allocates and initializes the mei device structure * * @pdev: The pci device structure @@ -313,7 +292,7 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled) mei_remove_client_from_file_list(dev, dev->iamthif_cl.host_client_id); - mei_reset_iamthif_params(dev); + mei_amthif_reset_params(dev); dev->extra_write_index = 0; } @@ -577,56 +556,6 @@ int mei_me_cl_update_filext(struct mei_device *dev, struct mei_cl *cl, } /** - * host_init_iamthif - mei initialization iamthif client. - * - * @dev: the device structure - * - */ -void mei_host_init_iamthif(struct mei_device *dev) -{ - int i; - unsigned char *msg_buf; - - mei_cl_init(&dev->iamthif_cl, dev); - dev->iamthif_cl.state = MEI_FILE_DISCONNECTED; - - /* find ME amthi client */ - i = mei_me_cl_update_filext(dev, &dev->iamthif_cl, - &mei_amthi_guid, MEI_IAMTHIF_HOST_CLIENT_ID); - if (i < 0) { - dev_dbg(&dev->pdev->dev, "failed to find iamthif client.\n"); - return; - } - - /* Assign iamthif_mtu to the value received from ME */ - - dev->iamthif_mtu = dev->me_clients[i].props.max_msg_length; - dev_dbg(&dev->pdev->dev, "IAMTHIF_MTU = %d\n", - dev->me_clients[i].props.max_msg_length); - - kfree(dev->iamthif_msg_buf); - dev->iamthif_msg_buf = NULL; - - /* allocate storage for ME message buffer */ - msg_buf = kcalloc(dev->iamthif_mtu, - sizeof(unsigned char), GFP_KERNEL); - if (!msg_buf) { - dev_dbg(&dev->pdev->dev, "memory allocation for ME message buffer failed.\n"); - return; - } - - dev->iamthif_msg_buf = msg_buf; - - if (mei_connect(dev, &dev->iamthif_cl)) { - dev_dbg(&dev->pdev->dev, "Failed to connect to AMTHI client\n"); - dev->iamthif_cl.state = MEI_FILE_DISCONNECTED; - dev->iamthif_cl.host_client_id = 0; - } else { - dev->iamthif_cl.timer_count = MEI_CONNECT_TIMEOUT; - } -} - -/** * mei_alloc_file_private - allocates a private file structure and sets it up. * @file: the file structure * diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 248f581..62f8b65 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -74,92 +74,6 @@ static void _mei_cmpl(struct mei_cl *cl, struct mei_cl_cb *cb_pos) } /** - * _mei_cmpl_iamthif - processes completed iamthif operation. - * - * @dev: the device structure. - * @cb_pos: callback block. - */ -static void _mei_cmpl_iamthif(struct mei_device *dev, struct mei_cl_cb *cb_pos) -{ - if (dev->iamthif_canceled != 1) { - dev->iamthif_state = MEI_IAMTHIF_READ_COMPLETE; - dev->iamthif_stall_timer = 0; - memcpy(cb_pos->response_buffer.data, - dev->iamthif_msg_buf, - dev->iamthif_msg_buf_index); - list_add_tail(&cb_pos->list, &dev->amthi_read_complete_list.list); - dev_dbg(&dev->pdev->dev, "amthi read completed\n"); - dev->iamthif_timer = jiffies; - dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n", - dev->iamthif_timer); - } else { - mei_run_next_iamthif_cmd(dev); - } - - dev_dbg(&dev->pdev->dev, "completing amthi call back.\n"); - wake_up_interruptible(&dev->iamthif_cl.wait); -} - - -/** - * mei_irq_thread_read_amthi_message - bottom half read routine after ISR to - * handle the read amthi message data processing. - * - * @complete_list: An instance of our list structure - * @dev: the device structure - * @mei_hdr: header of amthi message - * - * returns 0 on success, <0 on failure. - */ -static int mei_irq_thread_read_amthi_message(struct mei_cl_cb *complete_list, - struct mei_device *dev, - struct mei_msg_hdr *mei_hdr) -{ - struct mei_cl *cl; - struct mei_cl_cb *cb; - unsigned char *buffer; - - BUG_ON(mei_hdr->me_addr != dev->iamthif_cl.me_client_id); - BUG_ON(dev->iamthif_state != MEI_IAMTHIF_READING); - - buffer = dev->iamthif_msg_buf + dev->iamthif_msg_buf_index; - BUG_ON(dev->iamthif_mtu < dev->iamthif_msg_buf_index + mei_hdr->length); - - mei_read_slots(dev, buffer, mei_hdr->length); - - dev->iamthif_msg_buf_index += mei_hdr->length; - - if (!mei_hdr->msg_complete) - return 0; - - dev_dbg(&dev->pdev->dev, - "amthi_message_buffer_index =%d\n", - mei_hdr->length); - - dev_dbg(&dev->pdev->dev, "completed amthi read.\n "); - if (!dev->iamthif_current_cb) - return -ENODEV; - - cb = dev->iamthif_current_cb; - dev->iamthif_current_cb = NULL; - - cl = (struct mei_cl *)cb->file_private; - if (!cl) - return -ENODEV; - - dev->iamthif_stall_timer = 0; - cb->buf_idx = dev->iamthif_msg_buf_index; - cb->read_time = jiffies; - if (dev->iamthif_ioctl && cl == &dev->iamthif_cl) { - /* found the iamthif cb */ - dev_dbg(&dev->pdev->dev, "complete the amthi read cb.\n "); - dev_dbg(&dev->pdev->dev, "add the amthi read cb to complete.\n "); - list_add_tail(&cb->list, &complete_list->list); - } - return 0; -} - -/** * _mei_irq_thread_state_ok - checks if mei header matches file private data * * @cl: private data of the file object @@ -244,37 +158,6 @@ quit: } /** - * _mei_irq_thread_iamthif_read - prepares to read iamthif data. - * - * @dev: the device structure. - * @slots: free slots. - * - * returns 0, OK; otherwise, error. - */ -static int _mei_irq_thread_iamthif_read(struct mei_device *dev, s32 *slots) -{ - - if (((*slots) * sizeof(u32)) < (sizeof(struct mei_msg_hdr) - + sizeof(struct hbm_flow_control))) { - return -EMSGSIZE; - } - *slots -= mei_data2slots(sizeof(struct hbm_flow_control)); - if (mei_send_flow_control(dev, &dev->iamthif_cl)) { - dev_dbg(&dev->pdev->dev, "iamthif flow control failed\n"); - return -EIO; - } - - dev_dbg(&dev->pdev->dev, "iamthif flow control success\n"); - dev->iamthif_state = MEI_IAMTHIF_READING; - dev->iamthif_flow_control_pending = false; - dev->iamthif_msg_buf_index = 0; - dev->iamthif_msg_buf_size = 0; - dev->iamthif_stall_timer = MEI_IAMTHIF_STALL_TIMER; - dev->mei_host_buffer_is_empty = mei_hbuf_is_empty(dev); - return 0; -} - -/** * _mei_irq_thread_close - processes close related operation. * * @dev: the device structure. @@ -370,7 +253,7 @@ static void mei_client_connect_response(struct mei_device *dev, mei_watchdog_register(dev); /* next step in the state maching */ - mei_host_init_iamthif(dev); + mei_amthif_host_init(dev); return; } @@ -728,7 +611,7 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, * will be received */ if (mei_wd_host_init(dev)) - mei_host_init_iamthif(dev); + mei_amthif_host_init(dev); } } else { @@ -964,87 +847,6 @@ static int _mei_irq_thread_cmpl(struct mei_device *dev, s32 *slots, } /** - * _mei_irq_thread_cmpl_iamthif - processes completed iamthif operation. - * - * @dev: the device structure. - * @slots: free slots. - * @cb_pos: callback block. - * @cl: private data of the file object. - * @cmpl_list: complete list. - * - * returns 0, OK; otherwise, error. - */ -static int _mei_irq_thread_cmpl_iamthif(struct mei_device *dev, s32 *slots, - struct mei_cl_cb *cb_pos, - struct mei_cl *cl, - struct mei_cl_cb *cmpl_list) -{ - struct mei_msg_hdr *mei_hdr; - - if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) + - dev->iamthif_msg_buf_size - - dev->iamthif_msg_buf_index)) { - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; - mei_hdr->host_addr = cl->host_client_id; - mei_hdr->me_addr = cl->me_client_id; - mei_hdr->length = dev->iamthif_msg_buf_size - - dev->iamthif_msg_buf_index; - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - - *slots -= mei_data2slots(mei_hdr->length); - - if (mei_write_message(dev, mei_hdr, - (dev->iamthif_msg_buf + - dev->iamthif_msg_buf_index), - mei_hdr->length)) { - dev->iamthif_state = MEI_IAMTHIF_IDLE; - cl->status = -ENODEV; - list_del(&cb_pos->list); - return -ENODEV; - } else { - if (mei_flow_ctrl_reduce(dev, cl)) - return -ENODEV; - dev->iamthif_msg_buf_index += mei_hdr->length; - cb_pos->buf_idx = dev->iamthif_msg_buf_index; - cl->status = 0; - dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL; - dev->iamthif_flow_control_pending = true; - /* save iamthif cb sent to amthi client */ - dev->iamthif_current_cb = cb_pos; - list_move_tail(&cb_pos->list, &dev->write_waiting_list.list); - - } - } else if (*slots == dev->hbuf_depth) { - /* buffer is still empty */ - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; - mei_hdr->host_addr = cl->host_client_id; - mei_hdr->me_addr = cl->me_client_id; - mei_hdr->length = - (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr); - mei_hdr->msg_complete = 0; - mei_hdr->reserved = 0; - - *slots -= mei_data2slots(mei_hdr->length); - - if (mei_write_message(dev, mei_hdr, - (dev->iamthif_msg_buf + - dev->iamthif_msg_buf_index), - mei_hdr->length)) { - cl->status = -ENODEV; - list_del(&cb_pos->list); - } else { - dev->iamthif_msg_buf_index += mei_hdr->length; - } - return -EMSGSIZE; - } else { - return -EBADMSG; - } - - return 0; -} - -/** * mei_irq_thread_read_handler - bottom half read routine after ISR to * handle the read processing. * @@ -1117,8 +919,8 @@ static int mei_irq_thread_read_handler(struct mei_cl_cb *cmpl_list, dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_iamthif_message.\n"); dev_dbg(&dev->pdev->dev, "mei_hdr->length =%d\n", mei_hdr->length); - ret = mei_irq_thread_read_amthi_message(cmpl_list, - dev, mei_hdr); + + ret = mei_amthif_irq_read_message(cmpl_list, dev, mei_hdr); if (ret) goto end; @@ -1195,7 +997,7 @@ static int mei_irq_thread_write_handler(struct mei_cl_cb *cmpl_list, if (cl == &dev->iamthif_cl) { dev_dbg(&dev->pdev->dev, "check iamthif flow control.\n"); if (dev->iamthif_flow_control_pending) { - ret = _mei_irq_thread_iamthif_read(dev, slots); + ret = mei_amthif_irq_read(dev, slots); if (ret) return ret; } @@ -1300,8 +1102,8 @@ static int mei_irq_thread_write_handler(struct mei_cl_cb *cmpl_list, cl->host_client_id); continue; } - ret = _mei_irq_thread_cmpl_iamthif(dev, slots, pos, - cl, cmpl_list); + ret = mei_amthif_irq_process_completed(dev, slots, pos, + cl, cmpl_list); if (ret) return ret; @@ -1372,7 +1174,7 @@ void mei_timer(struct work_struct *work) dev->iamthif_current_cb = NULL; dev->iamthif_file_object = NULL; - mei_run_next_iamthif_cmd(dev); + mei_amthif_run_next_cmd(dev); } } @@ -1409,7 +1211,7 @@ void mei_timer(struct work_struct *work) dev->iamthif_file_object->private_data = NULL; dev->iamthif_file_object = NULL; dev->iamthif_timer = 0; - mei_run_next_iamthif_cmd(dev); + mei_amthif_run_next_cmd(dev); } } @@ -1524,7 +1326,7 @@ end: _mei_cmpl(cl, cb_pos); cb_pos = NULL; } else if (cl == &dev->iamthif_cl) { - _mei_cmpl_iamthif(dev, cb_pos); + mei_amthif_complete(dev, cb_pos); } } } diff --git a/drivers/misc/mei/iorw.c b/drivers/misc/mei/iorw.c index 8026cbf..a1d9ba1 100644 --- a/drivers/misc/mei/iorw.c +++ b/drivers/misc/mei/iorw.c @@ -320,152 +320,6 @@ end: } /** - * find_amthi_read_list_entry - finds a amthilist entry for current file - * - * @dev: the device structure - * @file: pointer to file object - * - * returns returned a list entry on success, NULL on failure. - */ -struct mei_cl_cb *find_amthi_read_list_entry( - struct mei_device *dev, - struct file *file) -{ - struct mei_cl *cl_temp; - struct mei_cl_cb *pos = NULL; - struct mei_cl_cb *next = NULL; - - list_for_each_entry_safe(pos, next, - &dev->amthi_read_complete_list.list, list) { - cl_temp = (struct mei_cl *)pos->file_private; - if (cl_temp && cl_temp == &dev->iamthif_cl && - pos->file_object == file) - return pos; - } - return NULL; -} - -/** - * amthi_read - read data from AMTHI client - * - * @dev: the device structure - * @if_num: minor number - * @file: pointer to file object - * @*ubuf: pointer to user data in user space - * @length: data length to read - * @offset: data read offset - * - * Locking: called under "dev->device_lock" lock - * - * returns - * returned data length on success, - * zero if no data to read, - * negative on failure. - */ -int amthi_read(struct mei_device *dev, struct file *file, - char __user *ubuf, size_t length, loff_t *offset) -{ - int rets; - int wait_ret; - struct mei_cl_cb *cb = NULL; - struct mei_cl *cl = file->private_data; - unsigned long timeout; - int i; - - /* Only Posible if we are in timeout */ - if (!cl || cl != &dev->iamthif_cl) { - dev_dbg(&dev->pdev->dev, "bad file ext.\n"); - return -ETIMEDOUT; - } - - i = mei_me_cl_by_id(dev, dev->iamthif_cl.me_client_id); - - if (i < 0) { - dev_dbg(&dev->pdev->dev, "amthi client not found.\n"); - return -ENODEV; - } - dev_dbg(&dev->pdev->dev, "checking amthi data\n"); - cb = find_amthi_read_list_entry(dev, file); - - /* Check for if we can block or not*/ - if (cb == NULL && file->f_flags & O_NONBLOCK) - return -EAGAIN; - - - dev_dbg(&dev->pdev->dev, "waiting for amthi data\n"); - while (cb == NULL) { - /* unlock the Mutex */ - mutex_unlock(&dev->device_lock); - - wait_ret = wait_event_interruptible(dev->iamthif_cl.wait, - (cb = find_amthi_read_list_entry(dev, file))); - - if (wait_ret) - return -ERESTARTSYS; - - dev_dbg(&dev->pdev->dev, "woke up from sleep\n"); - - /* Locking again the Mutex */ - mutex_lock(&dev->device_lock); - } - - - dev_dbg(&dev->pdev->dev, "Got amthi data\n"); - dev->iamthif_timer = 0; - - if (cb) { - timeout = cb->read_time + - mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER); - dev_dbg(&dev->pdev->dev, "amthi timeout = %lud\n", - timeout); - - if (time_after(jiffies, timeout)) { - dev_dbg(&dev->pdev->dev, "amthi Time out\n"); - /* 15 sec for the message has expired */ - list_del(&cb->list); - rets = -ETIMEDOUT; - goto free; - } - } - /* if the whole message will fit remove it from the list */ - if (cb->buf_idx >= *offset && length >= (cb->buf_idx - *offset)) - list_del(&cb->list); - else if (cb->buf_idx > 0 && cb->buf_idx <= *offset) { - /* end of the message has been reached */ - list_del(&cb->list); - rets = 0; - goto free; - } - /* else means that not full buffer will be read and do not - * remove message from deletion list - */ - - dev_dbg(&dev->pdev->dev, "amthi cb->response_buffer size - %d\n", - cb->response_buffer.size); - dev_dbg(&dev->pdev->dev, "amthi cb->buf_idx - %lu\n", cb->buf_idx); - - /* length is being turncated to PAGE_SIZE, however, - * the buf_idx may point beyond */ - length = min_t(size_t, length, (cb->buf_idx - *offset)); - - if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length)) - rets = -EFAULT; - else { - rets = length; - if ((*offset + length) < cb->buf_idx) { - *offset += length; - goto out; - } - } -free: - dev_dbg(&dev->pdev->dev, "free amthi cb memory.\n"); - *offset = 0; - mei_io_cb_free(cb); -out: - return rets; -} - -/** * mei_start_read - the start read client message function. * * @dev: the device structure @@ -524,123 +378,3 @@ err: return rets; } -/** - * amthi_write - write iamthif data to amthi client - * - * @dev: the device structure - * @cb: mei call back struct - * - * returns 0 on success, <0 on failure. - */ -int amthi_write(struct mei_device *dev, struct mei_cl_cb *cb) -{ - struct mei_msg_hdr mei_hdr; - int ret; - - if (!dev || !cb) - return -ENODEV; - - dev_dbg(&dev->pdev->dev, "write data to amthi client.\n"); - - dev->iamthif_state = MEI_IAMTHIF_WRITING; - dev->iamthif_current_cb = cb; - dev->iamthif_file_object = cb->file_object; - dev->iamthif_canceled = false; - dev->iamthif_ioctl = true; - dev->iamthif_msg_buf_size = cb->request_buffer.size; - memcpy(dev->iamthif_msg_buf, cb->request_buffer.data, - cb->request_buffer.size); - - ret = mei_flow_ctrl_creds(dev, &dev->iamthif_cl); - if (ret < 0) - return ret; - - if (ret && dev->mei_host_buffer_is_empty) { - ret = 0; - dev->mei_host_buffer_is_empty = false; - if (cb->request_buffer.size > mei_hbuf_max_data(dev)) { - mei_hdr.length = mei_hbuf_max_data(dev); - mei_hdr.msg_complete = 0; - } else { - mei_hdr.length = cb->request_buffer.size; - mei_hdr.msg_complete = 1; - } - - mei_hdr.host_addr = dev->iamthif_cl.host_client_id; - mei_hdr.me_addr = dev->iamthif_cl.me_client_id; - mei_hdr.reserved = 0; - dev->iamthif_msg_buf_index += mei_hdr.length; - if (mei_write_message(dev, &mei_hdr, - (unsigned char *)(dev->iamthif_msg_buf), - mei_hdr.length)) - return -ENODEV; - - if (mei_hdr.msg_complete) { - if (mei_flow_ctrl_reduce(dev, &dev->iamthif_cl)) - return -ENODEV; - dev->iamthif_flow_control_pending = true; - dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL; - dev_dbg(&dev->pdev->dev, "add amthi cb to write waiting list\n"); - dev->iamthif_current_cb = cb; - dev->iamthif_file_object = cb->file_object; - list_add_tail(&cb->list, &dev->write_waiting_list.list); - } else { - dev_dbg(&dev->pdev->dev, "message does not complete, " - "so add amthi cb to write list.\n"); - list_add_tail(&cb->list, &dev->write_list.list); - } - } else { - if (!(dev->mei_host_buffer_is_empty)) - dev_dbg(&dev->pdev->dev, "host buffer is not empty"); - - dev_dbg(&dev->pdev->dev, "No flow control credentials, " - "so add iamthif cb to write list.\n"); - list_add_tail(&cb->list, &dev->write_list.list); - } - return 0; -} - -/** - * iamthif_ioctl_send_msg - send cmd data to amthi client - * - * @dev: the device structure - * - * returns 0 on success, <0 on failure. - */ -void mei_run_next_iamthif_cmd(struct mei_device *dev) -{ - struct mei_cl *cl_tmp; - struct mei_cl_cb *pos = NULL; - struct mei_cl_cb *next = NULL; - int status; - - if (!dev) - return; - - dev->iamthif_msg_buf_size = 0; - dev->iamthif_msg_buf_index = 0; - dev->iamthif_canceled = false; - dev->iamthif_ioctl = true; - dev->iamthif_state = MEI_IAMTHIF_IDLE; - dev->iamthif_timer = 0; - dev->iamthif_file_object = NULL; - - dev_dbg(&dev->pdev->dev, "complete amthi cmd_list cb.\n"); - - list_for_each_entry_safe(pos, next, &dev->amthi_cmd_list.list, list) { - list_del(&pos->list); - cl_tmp = (struct mei_cl *)pos->file_private; - - if (cl_tmp && cl_tmp == &dev->iamthif_cl) { - status = amthi_write(dev, pos); - if (status) { - dev_dbg(&dev->pdev->dev, - "amthi write failed status = %d\n", - status); - return; - } - break; - } - } -} - diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 659727a..f69e085 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -349,7 +349,7 @@ static int mei_release(struct inode *inode, struct file *file) dev->iamthif_canceled = true; if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE) { dev_dbg(&dev->pdev->dev, "run next amthi iamthif cb\n"); - mei_run_next_iamthif_cmd(dev); + mei_amthif_run_next_cmd(dev); } } @@ -410,7 +410,7 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, } if (cl == &dev->iamthif_cl) { - rets = amthi_read(dev, file, ubuf, length, offset); + rets = mei_amthif_read(dev, file, ubuf, length, offset); goto out; } @@ -563,7 +563,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, goto err; } if (cl == &dev->iamthif_cl) { - write_cb = find_amthi_read_list_entry(dev, file); + write_cb = mei_amthif_find_read_list_entry(dev, file); if (write_cb) { timeout = write_cb->read_time + @@ -636,7 +636,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, list_add_tail(&write_cb->list, &dev->amthi_cmd_list.list); } else { dev_dbg(&dev->pdev->dev, "call amthi write\n"); - rets = amthi_write(dev, write_cb); + rets = mei_amthif_write(dev, write_cb); if (rets) { dev_err(&dev->pdev->dev, "amthi write failed with status = %d\n", @@ -823,7 +823,7 @@ static unsigned int mei_poll(struct file *file, poll_table *wait) dev->iamthif_file_object == file) { mask |= (POLLIN | POLLRDNORM); dev_dbg(&dev->pdev->dev, "run next amthi cb\n"); - mei_run_next_iamthif_cmd(dev); + mei_amthif_run_next_cmd(dev); } goto out; } diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 32c951a..57a5a4e 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -286,7 +286,6 @@ int mei_task_initialize_clients(void *data); int mei_initialize_clients(struct mei_device *dev); int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl); void mei_remove_client_from_file_list(struct mei_device *dev, u8 host_client_id); -void mei_host_init_iamthif(struct mei_device *dev); void mei_allocate_me_clients_storage(struct mei_device *dev); @@ -362,17 +361,37 @@ int mei_ioctl_connect_client(struct file *file, int mei_start_read(struct mei_device *dev, struct mei_cl *cl); -int amthi_write(struct mei_device *dev, struct mei_cl_cb *priv_cb); -int amthi_read(struct mei_device *dev, struct file *file, +/* + * AMTHIF - AMT Host Interface Functions + */ +void mei_amthif_reset_params(struct mei_device *dev); + +void mei_amthif_host_init(struct mei_device *dev); + +int mei_amthif_write(struct mei_device *dev, struct mei_cl_cb *priv_cb); + +int mei_amthif_read(struct mei_device *dev, struct file *file, char __user *ubuf, size_t length, loff_t *offset); -struct mei_cl_cb *find_amthi_read_list_entry(struct mei_device *dev, +struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev, struct file *file); -void mei_run_next_iamthif_cmd(struct mei_device *dev); +void mei_amthif_run_next_cmd(struct mei_device *dev); + + +int mei_amthif_read_message(struct mei_cl_cb *complete_list, + struct mei_device *dev, struct mei_msg_hdr *mei_hdr); +int mei_amthif_irq_process_completed(struct mei_device *dev, s32 *slots, + struct mei_cl_cb *cb_pos, + struct mei_cl *cl, + struct mei_cl_cb *cmpl_list); +void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb); +int mei_amthif_irq_read_message(struct mei_cl_cb *complete_list, + struct mei_device *dev, struct mei_msg_hdr *mei_hdr); +int mei_amthif_irq_read(struct mei_device *dev, s32 *slots); /* * Register Access Function -- cgit v0.10.2 From 15ea19105bdeef36820ade6754b9b7f1e3511e98 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 1 Nov 2012 21:17:16 +0200 Subject: mei: mei_clear_list: kill file_temp file_temp is used only once, so there is no any benefit of creating a temporary variable Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index f69e085..d8221a5 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -103,18 +103,16 @@ static DEFINE_MUTEX(mei_mutex); * returns true if callback removed from the list, false otherwise */ static bool mei_clear_list(struct mei_device *dev, - struct file *file, struct list_head *mei_cb_list) + const struct file *file, struct list_head *mei_cb_list) { struct mei_cl_cb *cb_pos = NULL; struct mei_cl_cb *cb_next = NULL; - struct file *file_temp; bool removed = false; /* list all list member */ list_for_each_entry_safe(cb_pos, cb_next, mei_cb_list, list) { - file_temp = (struct file *)cb_pos->file_object; /* check if list member associated with a file */ - if (file_temp == file) { + if (file == cb_pos->file_object) { /* remove member from the list */ list_del(&cb_pos->list); /* check if cb equal to current iamthif cb */ -- cgit v0.10.2 From c7d3df354dcb7477900b29a1200744a8c976c03a Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 1 Nov 2012 21:17:17 +0200 Subject: mei: use internal watchdog device registration tracking remove bool wd_interface_reg as watchdog device already keeps track of its registration Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index 4a8eb92..8c3c268 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c @@ -111,8 +111,6 @@ struct mei_device *mei_device_init(struct pci_dev *pdev) init_waitqueue_head(&dev->wait_stop_wd); dev->dev_state = MEI_DEV_INITIALIZING; dev->iamthif_state = MEI_IAMTHIF_IDLE; - dev->wd_interface_reg = false; - mei_io_list_init(&dev->read_list); mei_io_list_init(&dev->write_list); diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 57a5a4e..8b96d99 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -249,7 +249,6 @@ struct mei_device { struct mei_cl wd_cl; enum mei_wd_states wd_state; - bool wd_interface_reg; bool wd_pending; u16 wd_timeout; unsigned char wd_data[MEI_WD_START_MSG_SIZE]; diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c index 8edb054..4fc2b3d 100644 --- a/drivers/misc/mei/wd.c +++ b/drivers/misc/mei/wd.c @@ -360,23 +360,20 @@ void mei_watchdog_register(struct mei_device *dev) if (watchdog_register_device(&amt_wd_dev)) { dev_err(&dev->pdev->dev, "wd: unable to register watchdog device.\n"); - dev->wd_interface_reg = false; return; } dev_dbg(&dev->pdev->dev, "wd: successfully register watchdog interface.\n"); - dev->wd_interface_reg = true; watchdog_set_drvdata(&amt_wd_dev, dev); } void mei_watchdog_unregister(struct mei_device *dev) { - if (!dev->wd_interface_reg) + if (test_bit(WDOG_UNREGISTERED, &amt_wd_dev.status)) return; watchdog_set_drvdata(&amt_wd_dev, NULL); watchdog_unregister_device(&amt_wd_dev); - dev->wd_interface_reg = false; } -- cgit v0.10.2 From ab5c4a56d46f6a41d238aa6546f900407c9be275 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 1 Nov 2012 21:17:18 +0200 Subject: mei: move amthif specific code from mei_write to mei_amthif_write For sake of amthif consolidation move amthif specific code from mei_write to mei_amthif_write The original mei_amthif_write to mei_amthif_send_cmd as this function deals with sending single command while mei_amthif_write is interface function called from the main driver which in turns calls mei_amthif_send_cmd Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c index 392203d..96db3ad 100644 --- a/drivers/misc/mei/amthif.c +++ b/drivers/misc/mei/amthif.c @@ -255,14 +255,15 @@ out: } /** - * mei_amthif_write - write amthif data to amthif client + * mei_amthif_send_cmd - send amthif command to the ME * * @dev: the device structure * @cb: mei call back struct * * returns 0 on success, <0 on failure. + * */ -int mei_amthif_write(struct mei_device *dev, struct mei_cl_cb *cb) +static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb) { struct mei_msg_hdr mei_hdr; int ret; @@ -329,6 +330,38 @@ int mei_amthif_write(struct mei_device *dev, struct mei_cl_cb *cb) } /** + * mei_amthif_write - write amthif data to amthif client + * + * @dev: the device structure + * @cb: mei call back struct + * + * returns 0 on success, <0 on failure. + * + */ +int mei_amthif_write(struct mei_device *dev, struct mei_cl_cb *cb) +{ + int ret; + + if (!dev || !cb) + return -ENODEV; + + ret = mei_io_cb_alloc_resp_buf(cb, dev->iamthif_mtu); + if (ret) + return ret; + + cb->major_file_operations = MEI_IOCTL; + + if (!list_empty(&dev->amthi_cmd_list.list) || + dev->iamthif_state != MEI_IAMTHIF_IDLE) { + dev_dbg(&dev->pdev->dev, + "amthif state = %d\n", dev->iamthif_state); + dev_dbg(&dev->pdev->dev, "AMTHIF: add cb to the wait list\n"); + list_add_tail(&cb->list, &dev->amthi_cmd_list.list); + return 0; + } + return mei_amthif_send_cmd(dev, cb); +} +/** * mei_amthif_run_next_cmd * * @dev: the device structure @@ -360,7 +393,7 @@ void mei_amthif_run_next_cmd(struct mei_device *dev) cl_tmp = (struct mei_cl *)pos->file_private; if (cl_tmp && cl_tmp == &dev->iamthif_cl) { - status = mei_amthif_write(dev, pos); + status = mei_amthif_send_cmd(dev, pos); if (status) { dev_dbg(&dev->pdev->dev, "amthi write failed status = %d\n", diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index d8221a5..ff50cc1 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -620,27 +620,12 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, cl->sm_state |= MEI_WD_STATE_INDEPENDENCE_MSG_SENT; if (cl == &dev->iamthif_cl) { - rets = mei_io_cb_alloc_resp_buf(write_cb, dev->iamthif_mtu); - if (rets) - goto err; + rets = mei_amthif_write(dev, write_cb); - write_cb->major_file_operations = MEI_IOCTL; - - if (!list_empty(&dev->amthi_cmd_list.list) || - dev->iamthif_state != MEI_IAMTHIF_IDLE) { - dev_dbg(&dev->pdev->dev, "amthi_state = %d\n", - (int) dev->iamthif_state); - dev_dbg(&dev->pdev->dev, "add amthi cb to amthi cmd waiting list\n"); - list_add_tail(&write_cb->list, &dev->amthi_cmd_list.list); - } else { - dev_dbg(&dev->pdev->dev, "call amthi write\n"); - rets = mei_amthif_write(dev, write_cb); - - if (rets) { - dev_err(&dev->pdev->dev, "amthi write failed with status = %d\n", - rets); - goto err; - } + if (rets) { + dev_err(&dev->pdev->dev, + "amthi write failed with status = %d\n", rets); + goto err; } mutex_unlock(&dev->device_lock); return length; -- cgit v0.10.2 From e773efc405026bb8540c84bf45420bd66d5b34a7 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sun, 11 Nov 2012 17:37:58 +0200 Subject: mei: amthif: prefix cb list with amthif amthif cb list were prefixed with amthi_ instead if amthif. Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c index 96db3ad..1de28df 100644 --- a/drivers/misc/mei/amthif.c +++ b/drivers/misc/mei/amthif.c @@ -124,7 +124,7 @@ struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev, struct mei_cl_cb *next = NULL; list_for_each_entry_safe(pos, next, - &dev->amthi_read_complete_list.list, list) { + &dev->amthif_rd_complete_list.list, list) { cl_temp = (struct mei_cl *)pos->file_private; if (cl_temp && cl_temp == &dev->iamthif_cl && pos->file_object == file) @@ -351,12 +351,12 @@ int mei_amthif_write(struct mei_device *dev, struct mei_cl_cb *cb) cb->major_file_operations = MEI_IOCTL; - if (!list_empty(&dev->amthi_cmd_list.list) || + if (!list_empty(&dev->amthif_cmd_list.list) || dev->iamthif_state != MEI_IAMTHIF_IDLE) { dev_dbg(&dev->pdev->dev, "amthif state = %d\n", dev->iamthif_state); dev_dbg(&dev->pdev->dev, "AMTHIF: add cb to the wait list\n"); - list_add_tail(&cb->list, &dev->amthi_cmd_list.list); + list_add_tail(&cb->list, &dev->amthif_cmd_list.list); return 0; } return mei_amthif_send_cmd(dev, cb); @@ -388,7 +388,7 @@ void mei_amthif_run_next_cmd(struct mei_device *dev) dev_dbg(&dev->pdev->dev, "complete amthi cmd_list cb.\n"); - list_for_each_entry_safe(pos, next, &dev->amthi_cmd_list.list, list) { + list_for_each_entry_safe(pos, next, &dev->amthif_cmd_list.list, list) { list_del(&pos->list); cl_tmp = (struct mei_cl *)pos->file_private; @@ -589,7 +589,7 @@ void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb) memcpy(cb->response_buffer.data, dev->iamthif_msg_buf, dev->iamthif_msg_buf_index); - list_add_tail(&cb->list, &dev->amthi_read_complete_list.list); + list_add_tail(&cb->list, &dev->amthif_rd_complete_list.list); dev_dbg(&dev->pdev->dev, "amthi read completed\n"); dev->iamthif_timer = jiffies; dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n", diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index 8c3c268..7e6d591 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c @@ -80,8 +80,8 @@ int mei_cl_flush_queues(struct mei_cl *cl) mei_io_list_flush(&cl->dev->write_waiting_list, cl); mei_io_list_flush(&cl->dev->ctrl_wr_list, cl); mei_io_list_flush(&cl->dev->ctrl_rd_list, cl); - mei_io_list_flush(&cl->dev->amthi_cmd_list, cl); - mei_io_list_flush(&cl->dev->amthi_read_complete_list, cl); + mei_io_list_flush(&cl->dev->amthif_cmd_list, cl); + mei_io_list_flush(&cl->dev->amthif_rd_complete_list, cl); return 0; } @@ -117,8 +117,8 @@ struct mei_device *mei_device_init(struct pci_dev *pdev) mei_io_list_init(&dev->write_waiting_list); mei_io_list_init(&dev->ctrl_wr_list); mei_io_list_init(&dev->ctrl_rd_list); - mei_io_list_init(&dev->amthi_cmd_list); - mei_io_list_init(&dev->amthi_read_complete_list); + mei_io_list_init(&dev->amthif_cmd_list); + mei_io_list_init(&dev->amthif_rd_complete_list); dev->pdev = pdev; return dev; } diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 62f8b65..7193149 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -1127,7 +1127,6 @@ void mei_timer(struct work_struct *work) unsigned long timeout; struct mei_cl *cl_pos = NULL; struct mei_cl *cl_next = NULL; - struct list_head *amthi_complete_list = NULL; struct mei_cl_cb *cb_pos = NULL; struct mei_cl_cb *cb_next = NULL; @@ -1195,9 +1194,8 @@ void mei_timer(struct work_struct *work) dev_dbg(&dev->pdev->dev, "freeing AMTHI for other requests\n"); - amthi_complete_list = &dev->amthi_read_complete_list.list; - - list_for_each_entry_safe(cb_pos, cb_next, amthi_complete_list, list) { + list_for_each_entry_safe(cb_pos, cb_next, + &dev->amthif_rd_complete_list.list, list) { cl_pos = cb_pos->file_object->private_data; diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index ff50cc1..bea545a 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -146,9 +146,8 @@ static bool mei_clear_lists(struct mei_device *dev, struct file *file) bool removed = false; /* remove callbacks associated with a file */ - mei_clear_list(dev, file, &dev->amthi_cmd_list.list); - if (mei_clear_list(dev, file, - &dev->amthi_read_complete_list.list)) + mei_clear_list(dev, file, &dev->amthif_cmd_list.list); + if (mei_clear_list(dev, file, &dev->amthif_rd_complete_list.list)) removed = true; mei_clear_list(dev, file, &dev->ctrl_rd_list.list); diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 8b96d99..ce246b0 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -184,16 +184,13 @@ struct mei_device { /* * lists of queues */ - /* array of pointers to aio lists */ + /* array of pointers to aio lists */ struct mei_cl_cb read_list; /* driver read queue */ struct mei_cl_cb write_list; /* driver write queue */ struct mei_cl_cb write_waiting_list; /* write waiting queue */ struct mei_cl_cb ctrl_wr_list; /* managed write IOCTL list */ struct mei_cl_cb ctrl_rd_list; /* managed read IOCTL list */ - struct mei_cl_cb amthi_cmd_list; /* amthi list for cmd waiting */ - /* driver managed amthi list for reading completed amthi cmd data */ - struct mei_cl_cb amthi_read_complete_list; /* * list of files */ @@ -254,6 +251,10 @@ struct mei_device { unsigned char wd_data[MEI_WD_START_MSG_SIZE]; + /* amthif list for cmd waiting */ + struct mei_cl_cb amthif_cmd_list; + /* driver managed amthif list for reading completed amthif cmd data */ + struct mei_cl_cb amthif_rd_complete_list; struct file *iamthif_file_object; struct mei_cl iamthif_cl; struct mei_cl_cb *iamthif_current_cb; -- cgit v0.10.2 From db3ed43185c6f5d4fd6c5ac963347b849540996e Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sun, 11 Nov 2012 17:37:59 +0200 Subject: mei: use type struct mei_cl *cl instead of void in struct mei_cb We can use correct type 'struct mei_cl' instead of 'void *' for file_private in the struct mei_cb as there is no other type assigned to this member of the structure We rename the member from file_private to cl Remove about 10 lines of declarations of temporary variables used for type casting Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c index 1de28df..74d593f 100644 --- a/drivers/misc/mei/amthif.c +++ b/drivers/misc/mei/amthif.c @@ -119,14 +119,12 @@ void mei_amthif_host_init(struct mei_device *dev) struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev, struct file *file) { - struct mei_cl *cl_temp; struct mei_cl_cb *pos = NULL; struct mei_cl_cb *next = NULL; list_for_each_entry_safe(pos, next, &dev->amthif_rd_complete_list.list, list) { - cl_temp = (struct mei_cl *)pos->file_private; - if (cl_temp && cl_temp == &dev->iamthif_cl && + if (pos->cl && pos->cl == &dev->iamthif_cl && pos->file_object == file) return pos; } @@ -370,7 +368,6 @@ int mei_amthif_write(struct mei_device *dev, struct mei_cl_cb *cb) */ void mei_amthif_run_next_cmd(struct mei_device *dev) { - struct mei_cl *cl_tmp; struct mei_cl_cb *pos = NULL; struct mei_cl_cb *next = NULL; int status; @@ -390,9 +387,8 @@ void mei_amthif_run_next_cmd(struct mei_device *dev) list_for_each_entry_safe(pos, next, &dev->amthif_cmd_list.list, list) { list_del(&pos->list); - cl_tmp = (struct mei_cl *)pos->file_private; - if (cl_tmp && cl_tmp == &dev->iamthif_cl) { + if (pos->cl && pos->cl == &dev->iamthif_cl) { status = mei_amthif_send_cmd(dev, pos); if (status) { dev_dbg(&dev->pdev->dev, @@ -500,7 +496,6 @@ int mei_amthif_irq_process_completed(struct mei_device *dev, s32 *slots, int mei_amthif_irq_read_message(struct mei_cl_cb *complete_list, struct mei_device *dev, struct mei_msg_hdr *mei_hdr) { - struct mei_cl *cl; struct mei_cl_cb *cb; unsigned char *buffer; @@ -528,14 +523,13 @@ int mei_amthif_irq_read_message(struct mei_cl_cb *complete_list, cb = dev->iamthif_current_cb; dev->iamthif_current_cb = NULL; - cl = (struct mei_cl *)cb->file_private; - if (!cl) + if (!cb->cl) return -ENODEV; dev->iamthif_stall_timer = 0; cb->buf_idx = dev->iamthif_msg_buf_index; cb->read_time = jiffies; - if (dev->iamthif_ioctl && cl == &dev->iamthif_cl) { + if (dev->iamthif_ioctl && cb->cl == &dev->iamthif_cl) { /* found the iamthif cb */ dev_dbg(&dev->pdev->dev, "complete the amthi read cb.\n "); dev_dbg(&dev->pdev->dev, "add the amthi read cb to complete.\n "); diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index 7e6d591..0046ca5 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c @@ -55,10 +55,8 @@ void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl) struct mei_cl_cb *next; list_for_each_entry_safe(pos, next, &list->list, list) { - if (pos->file_private) { - struct mei_cl *cl_tmp; - cl_tmp = (struct mei_cl *)pos->file_private; - if (mei_cl_cmp_id(cl, cl_tmp)) + if (pos->cl) { + if (mei_cl_cmp_id(cl, pos->cl)) list_del(&pos->list); } } diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 7193149..acc994e 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -113,7 +113,7 @@ static int mei_irq_thread_read_client_message(struct mei_cl_cb *complete_list, goto quit; list_for_each_entry_safe(cb_pos, cb_next, &dev->read_list.list, list) { - cl = (struct mei_cl *)cb_pos->file_private; + cl = cb_pos->cl; if (cl && _mei_irq_thread_state_ok(cl, mei_hdr)) { cl->reading_state = MEI_READING; buffer = cb_pos->response_buffer.data + cb_pos->buf_idx; @@ -263,7 +263,7 @@ static void mei_client_connect_response(struct mei_device *dev, } list_for_each_entry_safe(pos, next, &dev->ctrl_rd_list.list, list) { - cl = (struct mei_cl *)pos->file_private; + cl = pos->cl; if (!cl) { list_del(&pos->list); return; @@ -301,7 +301,7 @@ static void mei_client_disconnect_response(struct mei_device *dev, rs->status); list_for_each_entry_safe(pos, next, &dev->ctrl_rd_list.list, list) { - cl = (struct mei_cl *)pos->file_private; + cl = pos->cl; if (!cl) { list_del(&pos->list); @@ -981,7 +981,7 @@ static int mei_irq_thread_write_handler(struct mei_cl_cb *cmpl_list, list = &dev->write_waiting_list; list_for_each_entry_safe(pos, next, &list->list, list) { - cl = (struct mei_cl *)pos->file_private; + cl = pos->cl; if (cl == NULL) continue; @@ -1039,7 +1039,7 @@ static int mei_irq_thread_write_handler(struct mei_cl_cb *cmpl_list, /* complete control write list CB */ dev_dbg(&dev->pdev->dev, "complete control write list cb.\n"); list_for_each_entry_safe(pos, next, &dev->ctrl_wr_list.list, list) { - cl = (struct mei_cl *) pos->file_private; + cl = pos->cl; if (!cl) { list_del(&pos->list); return -ENODEV; @@ -1077,7 +1077,7 @@ static int mei_irq_thread_write_handler(struct mei_cl_cb *cmpl_list, /* complete write list CB */ dev_dbg(&dev->pdev->dev, "complete write list cb.\n"); list_for_each_entry_safe(pos, next, &dev->write_list.list, list) { - cl = (struct mei_cl *)pos->file_private; + cl = pos->cl; if (cl == NULL) continue; @@ -1316,7 +1316,7 @@ end: list_for_each_entry_safe(cb_pos, cb_next, &complete_list.list, list) { - cl = (struct mei_cl *)cb_pos->file_private; + cl = cb_pos->cl; list_del(&cb_pos->list); if (cl) { if (cl != &dev->iamthif_cl) { diff --git a/drivers/misc/mei/iorw.c b/drivers/misc/mei/iorw.c index a1d9ba1..cc53ce7 100644 --- a/drivers/misc/mei/iorw.c +++ b/drivers/misc/mei/iorw.c @@ -71,7 +71,7 @@ struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp) mei_io_list_init(cb); cb->file_object = fp; - cb->file_private = cl; + cb->cl = cl; cb->buf_idx = 0; return cb; } diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index bea545a..e0e39c4 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -189,13 +189,9 @@ static struct mei_cl_cb *find_read_list_entry( struct mei_cl_cb *next = NULL; dev_dbg(&dev->pdev->dev, "remove read_list CB\n"); - list_for_each_entry_safe(pos, next, &dev->read_list.list, list) { - struct mei_cl *cl_temp; - cl_temp = (struct mei_cl *)pos->file_private; - - if (mei_cl_cmp_id(cl, cl_temp)) + list_for_each_entry_safe(pos, next, &dev->read_list.list, list) + if (mei_cl_cmp_id(cl, pos->cl)) return pos; - } return NULL; } diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index ce246b0..da0c1f5 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -143,10 +143,17 @@ struct mei_message_data { }; +struct mei_cl; + +/* + * struct mei_cl_cb - file operation callback structure + * + * @cl - file client who is running this operation + */ struct mei_cl_cb { struct list_head list; + struct mei_cl *cl; enum mei_cb_major_types major_file_operations; - void *file_private; struct mei_message_data request_buffer; struct mei_message_data response_buffer; unsigned long buf_idx; -- cgit v0.10.2 From 4b8960b492360c115f8214ec116f469338ac2734 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sun, 11 Nov 2012 17:38:00 +0200 Subject: mei: rename enum mei_cb_major_types to enum mei_cb_file_ops 1. Rename mei_cb_major_types to more understandable mei_cb_file_ops 2. Rename member struct mei_cl_cb of this type to simple 'fop_type' 3. Add kernel doc for the type Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c index 74d593f..34d37a9 100644 --- a/drivers/misc/mei/amthif.c +++ b/drivers/misc/mei/amthif.c @@ -347,7 +347,7 @@ int mei_amthif_write(struct mei_device *dev, struct mei_cl_cb *cb) if (ret) return ret; - cb->major_file_operations = MEI_IOCTL; + cb->fop_type = MEI_FOP_IOCTL; if (!list_empty(&dev->amthif_cmd_list.list) || dev->iamthif_state != MEI_IAMTHIF_IDLE) { diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index 0046ca5..85b6520 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c @@ -597,7 +597,7 @@ int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl) if (!cb) return -ENOMEM; - cb->major_file_operations = MEI_CLOSE; + cb->fop_type = MEI_FOP_CLOSE; if (dev->mei_host_buffer_is_empty) { dev->mei_host_buffer_is_empty = false; if (mei_disconnect(dev, cl)) { diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index acc994e..34e20cc 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -57,14 +57,14 @@ irqreturn_t mei_interrupt_quick_handler(int irq, void *dev_id) */ static void _mei_cmpl(struct mei_cl *cl, struct mei_cl_cb *cb_pos) { - if (cb_pos->major_file_operations == MEI_WRITE) { + if (cb_pos->fop_type == MEI_FOP_WRITE) { mei_io_cb_free(cb_pos); cb_pos = NULL; cl->writing_state = MEI_WRITE_COMPLETE; if (waitqueue_active(&cl->tx_wait)) wake_up_interruptible(&cl->tx_wait); - } else if (cb_pos->major_file_operations == MEI_READ && + } else if (cb_pos->fop_type == MEI_FOP_READ && MEI_READING == cl->reading_state) { cl->reading_state = MEI_READ_COMPLETE; if (waitqueue_active(&cl->rx_wait)) @@ -268,7 +268,7 @@ static void mei_client_connect_response(struct mei_device *dev, list_del(&pos->list); return; } - if (MEI_IOCTL == pos->major_file_operations) { + if (pos->fop_type == MEI_FOP_IOCTL) { if (is_treat_specially_client(cl, rs)) { list_del(&pos->list); cl->status = 0; @@ -988,8 +988,8 @@ static int mei_irq_thread_write_handler(struct mei_cl_cb *cmpl_list, cl->status = 0; list_del(&pos->list); if (MEI_WRITING == cl->writing_state && - (pos->major_file_operations == MEI_WRITE) && - (cl != &dev->iamthif_cl)) { + pos->fop_type == MEI_FOP_WRITE && + cl != &dev->iamthif_cl) { dev_dbg(&dev->pdev->dev, "MEI WRITE COMPLETE\n"); cl->writing_state = MEI_WRITE_COMPLETE; list_add_tail(&pos->list, &cmpl_list->list); @@ -1044,22 +1044,22 @@ static int mei_irq_thread_write_handler(struct mei_cl_cb *cmpl_list, list_del(&pos->list); return -ENODEV; } - switch (pos->major_file_operations) { - case MEI_CLOSE: + switch (pos->fop_type) { + case MEI_FOP_CLOSE: /* send disconnect message */ ret = _mei_irq_thread_close(dev, slots, pos, cl, cmpl_list); if (ret) return ret; break; - case MEI_READ: + case MEI_FOP_READ: /* send flow control message */ ret = _mei_irq_thread_read(dev, slots, pos, cl, cmpl_list); if (ret) return ret; break; - case MEI_IOCTL: + case MEI_FOP_IOCTL: /* connect message */ if (mei_other_client_is_connecting(dev, cl)) continue; diff --git a/drivers/misc/mei/iorw.c b/drivers/misc/mei/iorw.c index cc53ce7..cf11076 100644 --- a/drivers/misc/mei/iorw.c +++ b/drivers/misc/mei/iorw.c @@ -193,7 +193,7 @@ int mei_ioctl_connect_client(struct file *file, goto end; } - cb->major_file_operations = MEI_IOCTL; + cb->fop_type = MEI_FOP_IOCTL; if (dev->dev_state != MEI_DEV_ENABLED) { rets = -ENODEV; @@ -360,7 +360,7 @@ int mei_start_read(struct mei_device *dev, struct mei_cl *cl) if (rets) goto err; - cb->major_file_operations = MEI_READ; + cb->fop_type = MEI_FOP_READ; cl->read_cb = cb; if (dev->mei_host_buffer_is_empty) { dev->mei_host_buffer_is_empty = false; diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index e0e39c4..57bf96c 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -626,7 +626,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, return length; } - write_cb->major_file_operations = MEI_WRITE; + write_cb->fop_type = MEI_FOP_WRITE; dev_dbg(&dev->pdev->dev, "host client = %d, ME client = %d\n", cl->host_client_id, cl->me_client_id); diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index da0c1f5..59e94c2 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -125,13 +125,20 @@ enum mei_wd_states { MEI_WD_STOPPING, }; -/* MEI CB */ -enum mei_cb_major_types { - MEI_READ = 0, - MEI_WRITE, - MEI_IOCTL, - MEI_OPEN, - MEI_CLOSE +/** + * enum mei_cb_file_ops - file operation associated with the callback + * @MEI_FOP_READ - read + * @MEI_FOP_WRITE - write + * @MEI_FOP_IOCTL - ioctl + * @MEI_FOP_OPEN - open + * @MEI_FOP_CLOSE - close + */ +enum mei_cb_file_ops { + MEI_FOP_READ = 0, + MEI_FOP_WRITE, + MEI_FOP_IOCTL, + MEI_FOP_OPEN, + MEI_FOP_CLOSE }; /* @@ -145,15 +152,16 @@ struct mei_message_data { struct mei_cl; -/* +/** * struct mei_cl_cb - file operation callback structure * * @cl - file client who is running this operation + * @fop_type - file operation type */ struct mei_cl_cb { struct list_head list; struct mei_cl *cl; - enum mei_cb_major_types major_file_operations; + enum mei_cb_file_ops fop_type; struct mei_message_data request_buffer; struct mei_message_data response_buffer; unsigned long buf_idx; -- cgit v0.10.2 From a562d5c25aa48c23774ab8d60bfd3bbcbca4bf1d Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sun, 11 Nov 2012 17:38:01 +0200 Subject: mei: move amthif specific release code to amithif Move amthif code part into separate function mei_amthif_release. Also helper functions mei_clear_list and mei_clear_lists are moved along Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c index 34d37a9..8f4373a 100644 --- a/drivers/misc/mei/amthif.c +++ b/drivers/misc/mei/amthif.c @@ -596,4 +596,118 @@ void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb) wake_up_interruptible(&dev->iamthif_cl.wait); } +/** + * mei_clear_list - removes all callbacks associated with file + * from mei_cb_list + * + * @dev: device structure. + * @file: file structure + * @mei_cb_list: callbacks list + * + * mei_clear_list is called to clear resources associated with file + * when application calls close function or Ctrl-C was pressed + * + * returns true if callback removed from the list, false otherwise + */ +static bool mei_clear_list(struct mei_device *dev, + const struct file *file, struct list_head *mei_cb_list) +{ + struct mei_cl_cb *cb_pos = NULL; + struct mei_cl_cb *cb_next = NULL; + bool removed = false; + + /* list all list member */ + list_for_each_entry_safe(cb_pos, cb_next, mei_cb_list, list) { + /* check if list member associated with a file */ + if (file == cb_pos->file_object) { + /* remove member from the list */ + list_del(&cb_pos->list); + /* check if cb equal to current iamthif cb */ + if (dev->iamthif_current_cb == cb_pos) { + dev->iamthif_current_cb = NULL; + /* send flow control to iamthif client */ + mei_send_flow_control(dev, &dev->iamthif_cl); + } + /* free all allocated buffers */ + mei_io_cb_free(cb_pos); + cb_pos = NULL; + removed = true; + } + } + return removed; +} + +/** + * mei_clear_lists - removes all callbacks associated with file + * + * @dev: device structure + * @file: file structure + * + * mei_clear_lists is called to clear resources associated with file + * when application calls close function or Ctrl-C was pressed + * + * returns true if callback removed from the list, false otherwise + */ +static bool mei_clear_lists(struct mei_device *dev, struct file *file) +{ + bool removed = false; + + /* remove callbacks associated with a file */ + mei_clear_list(dev, file, &dev->amthif_cmd_list.list); + if (mei_clear_list(dev, file, &dev->amthif_rd_complete_list.list)) + removed = true; + mei_clear_list(dev, file, &dev->ctrl_rd_list.list); + + if (mei_clear_list(dev, file, &dev->ctrl_wr_list.list)) + removed = true; + + if (mei_clear_list(dev, file, &dev->write_waiting_list.list)) + removed = true; + + if (mei_clear_list(dev, file, &dev->write_list.list)) + removed = true; + + /* check if iamthif_current_cb not NULL */ + if (dev->iamthif_current_cb && !removed) { + /* check file and iamthif current cb association */ + if (dev->iamthif_current_cb->file_object == file) { + /* remove cb */ + mei_io_cb_free(dev->iamthif_current_cb); + dev->iamthif_current_cb = NULL; + removed = true; + } + } + return removed; +} + +/** +* mei_amthif_release - the release function +* +* @inode: pointer to inode structure +* @file: pointer to file structure +* +* returns 0 on success, <0 on error +*/ +int mei_amthif_release(struct mei_device *dev, struct file *file) +{ + if (dev->open_handle_count > 0) + dev->open_handle_count--; + + if (dev->iamthif_file_object == file && + dev->iamthif_state != MEI_IAMTHIF_IDLE) { + + dev_dbg(&dev->pdev->dev, "amthi canceled iamthif state %d\n", + dev->iamthif_state); + dev->iamthif_canceled = true; + if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE) { + dev_dbg(&dev->pdev->dev, "run next amthi iamthif cb\n"); + mei_amthif_run_next_cmd(dev); + } + } + + if (mei_clear_lists(dev, file)) + dev->iamthif_state = MEI_IAMTHIF_IDLE; + + return 0; +} diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 57bf96c..43512e5 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -90,90 +90,6 @@ static DEFINE_MUTEX(mei_mutex); /** - * mei_clear_list - removes all callbacks associated with file - * from mei_cb_list - * - * @dev: device structure. - * @file: file structure - * @mei_cb_list: callbacks list - * - * mei_clear_list is called to clear resources associated with file - * when application calls close function or Ctrl-C was pressed - * - * returns true if callback removed from the list, false otherwise - */ -static bool mei_clear_list(struct mei_device *dev, - const struct file *file, struct list_head *mei_cb_list) -{ - struct mei_cl_cb *cb_pos = NULL; - struct mei_cl_cb *cb_next = NULL; - bool removed = false; - - /* list all list member */ - list_for_each_entry_safe(cb_pos, cb_next, mei_cb_list, list) { - /* check if list member associated with a file */ - if (file == cb_pos->file_object) { - /* remove member from the list */ - list_del(&cb_pos->list); - /* check if cb equal to current iamthif cb */ - if (dev->iamthif_current_cb == cb_pos) { - dev->iamthif_current_cb = NULL; - /* send flow control to iamthif client */ - mei_send_flow_control(dev, &dev->iamthif_cl); - } - /* free all allocated buffers */ - mei_io_cb_free(cb_pos); - cb_pos = NULL; - removed = true; - } - } - return removed; -} - -/** - * mei_clear_lists - removes all callbacks associated with file - * - * @dev: device structure - * @file: file structure - * - * mei_clear_lists is called to clear resources associated with file - * when application calls close function or Ctrl-C was pressed - * - * returns true if callback removed from the list, false otherwise - */ -static bool mei_clear_lists(struct mei_device *dev, struct file *file) -{ - bool removed = false; - - /* remove callbacks associated with a file */ - mei_clear_list(dev, file, &dev->amthif_cmd_list.list); - if (mei_clear_list(dev, file, &dev->amthif_rd_complete_list.list)) - removed = true; - - mei_clear_list(dev, file, &dev->ctrl_rd_list.list); - - if (mei_clear_list(dev, file, &dev->ctrl_wr_list.list)) - removed = true; - - if (mei_clear_list(dev, file, &dev->write_waiting_list.list)) - removed = true; - - if (mei_clear_list(dev, file, &dev->write_list.list)) - removed = true; - - /* check if iamthif_current_cb not NULL */ - if (dev->iamthif_current_cb && !removed) { - /* check file and iamthif current cb association */ - if (dev->iamthif_current_cb->file_object == file) { - /* remove cb */ - mei_io_cb_free(dev->iamthif_current_cb); - dev->iamthif_current_cb = NULL; - removed = true; - } - } - return removed; -} -/** * find_read_list_entry - find read list entry * * @dev: device structure @@ -289,67 +205,51 @@ static int mei_release(struct inode *inode, struct file *file) dev = cl->dev; mutex_lock(&dev->device_lock); - if (cl != &dev->iamthif_cl) { - if (cl->state == MEI_FILE_CONNECTED) { - cl->state = MEI_FILE_DISCONNECTING; - dev_dbg(&dev->pdev->dev, - "disconnecting client host client = %d, " - "ME client = %d\n", - cl->host_client_id, - cl->me_client_id); - rets = mei_disconnect_host_client(dev, cl); - } - mei_cl_flush_queues(cl); - dev_dbg(&dev->pdev->dev, "remove client host client = %d, ME client = %d\n", + if (cl == &dev->iamthif_cl) { + rets = mei_amthif_release(dev, file); + goto out; + } + if (cl->state == MEI_FILE_CONNECTED) { + cl->state = MEI_FILE_DISCONNECTING; + dev_dbg(&dev->pdev->dev, + "disconnecting client host client = %d, " + "ME client = %d\n", cl->host_client_id, cl->me_client_id); + rets = mei_disconnect_host_client(dev, cl); + } + mei_cl_flush_queues(cl); + dev_dbg(&dev->pdev->dev, "remove client host client = %d, ME client = %d\n", + cl->host_client_id, + cl->me_client_id); + + if (dev->open_handle_count > 0) { + clear_bit(cl->host_client_id, dev->host_clients_map); + dev->open_handle_count--; + } + mei_remove_client_from_file_list(dev, cl->host_client_id); - if (dev->open_handle_count > 0) { - clear_bit(cl->host_client_id, dev->host_clients_map); - dev->open_handle_count--; - } - mei_remove_client_from_file_list(dev, cl->host_client_id); - - /* free read cb */ - cb = NULL; - if (cl->read_cb) { - cb = find_read_list_entry(dev, cl); - /* Remove entry from read list */ - if (cb) - list_del(&cb->list); - - cb = cl->read_cb; - cl->read_cb = NULL; - } - - file->private_data = NULL; - - if (cb) { - mei_io_cb_free(cb); - cb = NULL; - } + /* free read cb */ + cb = NULL; + if (cl->read_cb) { + cb = find_read_list_entry(dev, cl); + /* Remove entry from read list */ + if (cb) + list_del(&cb->list); - kfree(cl); - } else { - if (dev->open_handle_count > 0) - dev->open_handle_count--; - - if (dev->iamthif_file_object == file && - dev->iamthif_state != MEI_IAMTHIF_IDLE) { - - dev_dbg(&dev->pdev->dev, "amthi canceled iamthif state %d\n", - dev->iamthif_state); - dev->iamthif_canceled = true; - if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE) { - dev_dbg(&dev->pdev->dev, "run next amthi iamthif cb\n"); - mei_amthif_run_next_cmd(dev); - } - } + cb = cl->read_cb; + cl->read_cb = NULL; + } - if (mei_clear_lists(dev, file)) - dev->iamthif_state = MEI_IAMTHIF_IDLE; + file->private_data = NULL; + if (cb) { + mei_io_cb_free(cb); + cb = NULL; } + + kfree(cl); +out: mutex_unlock(&dev->device_lock); return rets; } diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 59e94c2..bdad35e 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -389,6 +389,8 @@ int mei_amthif_write(struct mei_device *dev, struct mei_cl_cb *priv_cb); int mei_amthif_read(struct mei_device *dev, struct file *file, char __user *ubuf, size_t length, loff_t *offset); +int mei_amthif_release(struct mei_device *dev, struct file *file); + struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev, struct file *file); -- cgit v0.10.2 From 744f0f2f424d374b233cea5f9b34caa851543755 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sun, 11 Nov 2012 17:38:02 +0200 Subject: mei: extract amthif specific code from mei_poll to mei_amthif_poll Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c index 8f4373a..7416241 100644 --- a/drivers/misc/mei/amthif.c +++ b/drivers/misc/mei/amthif.c @@ -401,6 +401,25 @@ void mei_amthif_run_next_cmd(struct mei_device *dev) } } + +unsigned int mei_amthif_poll(struct mei_device *dev, + struct file *file, poll_table *wait) +{ + unsigned int mask = 0; + mutex_unlock(&dev->device_lock); + poll_wait(file, &dev->iamthif_cl.wait, wait); + mutex_lock(&dev->device_lock); + if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE && + dev->iamthif_file_object == file) { + mask |= (POLLIN | POLLRDNORM); + dev_dbg(&dev->pdev->dev, "run next amthi cb\n"); + mei_amthif_run_next_cmd(dev); + } + return mask; +} + + + /** * mei_amthif_irq_process_completed - processes completed iamthif operation. * diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 43512e5..2cc1ebb 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -694,15 +694,7 @@ static unsigned int mei_poll(struct file *file, poll_table *wait) if (cl == &dev->iamthif_cl) { - mutex_unlock(&dev->device_lock); - poll_wait(file, &dev->iamthif_cl.wait, wait); - mutex_lock(&dev->device_lock); - if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE && - dev->iamthif_file_object == file) { - mask |= (POLLIN | POLLRDNORM); - dev_dbg(&dev->pdev->dev, "run next amthi cb\n"); - mei_amthif_run_next_cmd(dev); - } + mask = mei_amthif_poll(dev, file, wait); goto out; } diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index bdad35e..dad85f3 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -19,6 +19,7 @@ #include #include +#include #include #include "hw.h" @@ -387,7 +388,10 @@ void mei_amthif_host_init(struct mei_device *dev); int mei_amthif_write(struct mei_device *dev, struct mei_cl_cb *priv_cb); int mei_amthif_read(struct mei_device *dev, struct file *file, - char __user *ubuf, size_t length, loff_t *offset); + char __user *ubuf, size_t length, loff_t *offset); + +unsigned int mei_amthif_poll(struct mei_device *dev, + struct file *file, poll_table *wait); int mei_amthif_release(struct mei_device *dev, struct file *file); -- cgit v0.10.2 From ff8b2f4e424a489222d3c7d55fb2d04c9639ef98 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sun, 11 Nov 2012 17:38:03 +0200 Subject: mei: use link and unlink terms for connecting ME and HOST client 1. rename mei_me_cl_update_filext to mei_me_cl_link 2. rename mei_remove_client_from_file_list to mei_me_cl_unlink Code style, documenation, and usage of both function is updated Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c index 7416241..095d059 100644 --- a/drivers/misc/mei/amthif.c +++ b/drivers/misc/mei/amthif.c @@ -73,10 +73,10 @@ void mei_amthif_host_init(struct mei_device *dev) dev->iamthif_cl.state = MEI_FILE_DISCONNECTED; /* find ME amthi client */ - i = mei_me_cl_update_filext(dev, &dev->iamthif_cl, + i = mei_me_cl_link(dev, &dev->iamthif_cl, &mei_amthi_guid, MEI_IAMTHIF_HOST_CLIENT_ID); if (i < 0) { - dev_dbg(&dev->pdev->dev, "failed to find iamthif client.\n"); + dev_info(&dev->pdev->dev, "failed to find iamthif client.\n"); return; } diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index 85b6520..4fcb0bb 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c @@ -281,12 +281,10 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled) cl_pos->timer_count = 0; } /* remove entry if already in list */ - dev_dbg(&dev->pdev->dev, "list del iamthif and wd file list.\n"); - mei_remove_client_from_file_list(dev, - dev->wd_cl.host_client_id); + dev_dbg(&dev->pdev->dev, "remove iamthif and wd from the file list.\n"); + mei_me_cl_unlink(dev, &dev->wd_cl); - mei_remove_client_from_file_list(dev, - dev->iamthif_cl.host_client_id); + mei_me_cl_unlink(dev, &dev->iamthif_cl); mei_amthif_reset_params(dev); dev->extra_write_index = 0; @@ -520,17 +518,20 @@ int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *cuuid) /** - * mei_me_cl_update_filext - searches for ME client guid - * sets client_id in mei_file_private if found + * mei_me_cl_link - create link between host and me clinet and add + * me_cl to the list + * * @dev: the device structure - * @cl: private file structure to set client_id in - * @cuuid: searched uuid of ME client - * @client_id: id of host client to be set in file private structure + * @cl: link between me and host client assocated with opened file descriptor + * @cuuid: uuid of ME client + * @client_id: id of the host client * - * returns ME client index + * returns ME client index if ME client + * -EINVAL on incorrect values + * -ENONET if client not found */ -int mei_me_cl_update_filext(struct mei_device *dev, struct mei_cl *cl, - const uuid_le *cuuid, u8 host_cl_id) +int mei_me_cl_link(struct mei_device *dev, struct mei_cl *cl, + const uuid_le *cuuid, u8 host_cl_id) { int i; @@ -550,6 +551,24 @@ int mei_me_cl_update_filext(struct mei_device *dev, struct mei_cl *cl, return -ENOENT; } +/** + * mei_me_cl_unlink - remove me_cl from the list + * + * @dev: the device structure + * @host_client_id: host client id to be removed + */ +void mei_me_cl_unlink(struct mei_device *dev, struct mei_cl *cl) +{ + struct mei_cl *pos, *next; + list_for_each_entry_safe(pos, next, &dev->file_list, link) { + if (cl->host_client_id == pos->host_client_id) { + dev_dbg(&dev->pdev->dev, "remove host client = %d, ME client = %d\n", + pos->host_client_id, pos->me_client_id); + list_del_init(&pos->link); + break; + } + } +} /** * mei_alloc_file_private - allocates a private file structure and sets it up. @@ -642,25 +661,3 @@ free: return rets; } -/** - * mei_remove_client_from_file_list - - * removes file private data from device file list - * - * @dev: the device structure - * @host_client_id: host client id to be removed - */ -void mei_remove_client_from_file_list(struct mei_device *dev, - u8 host_client_id) -{ - struct mei_cl *cl_pos = NULL; - struct mei_cl *cl_next = NULL; - list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) { - if (host_client_id == cl_pos->host_client_id) { - dev_dbg(&dev->pdev->dev, "remove host client = %d, ME client = %d\n", - cl_pos->host_client_id, - cl_pos->me_client_id); - list_del_init(&cl_pos->link); - break; - } - } -} diff --git a/drivers/misc/mei/iorw.c b/drivers/misc/mei/iorw.c index cf11076..eb93a1b 100644 --- a/drivers/misc/mei/iorw.c +++ b/drivers/misc/mei/iorw.c @@ -171,8 +171,6 @@ int mei_ioctl_connect_client(struct file *file, struct mei_cl_cb *cb; struct mei_client *client; struct mei_cl *cl; - struct mei_cl *cl_pos = NULL; - struct mei_cl *cl_next = NULL; long timeout = mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT); int i; int err; @@ -229,21 +227,9 @@ int mei_ioctl_connect_client(struct file *file, goto end; } clear_bit(cl->host_client_id, dev->host_clients_map); - list_for_each_entry_safe(cl_pos, cl_next, - &dev->file_list, link) { - if (mei_cl_cmp_id(cl, cl_pos)) { - dev_dbg(&dev->pdev->dev, - "remove file private data node host" - " client = %d, ME client = %d.\n", - cl_pos->host_client_id, - cl_pos->me_client_id); - list_del(&cl_pos->link); - } + mei_me_cl_unlink(dev, cl); - } - dev_dbg(&dev->pdev->dev, "free file private data memory.\n"); kfree(cl); - cl = NULL; file->private_data = &dev->iamthif_cl; diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 2cc1ebb..251aaff 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -227,7 +227,7 @@ static int mei_release(struct inode *inode, struct file *file) clear_bit(cl->host_client_id, dev->host_clients_map); dev->open_handle_count--; } - mei_remove_client_from_file_list(dev, cl->host_client_id); + mei_me_cl_unlink(dev, cl); /* free read cb */ cb = NULL; @@ -913,8 +913,8 @@ static void __devexit mei_remove(struct pci_dev *pdev) /* remove entry if already in list */ dev_dbg(&pdev->dev, "list del iamthif and wd file list.\n"); - mei_remove_client_from_file_list(dev, dev->wd_cl.host_client_id); - mei_remove_client_from_file_list(dev, dev->iamthif_cl.host_client_id); + mei_me_cl_unlink(dev, &dev->wd_cl); + mei_me_cl_unlink(dev, &dev->iamthif_cl); dev->iamthif_current_cb = NULL; dev->me_clients_num = 0; diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index dad85f3..aaee666 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -301,12 +301,12 @@ int mei_hw_init(struct mei_device *dev); int mei_task_initialize_clients(void *data); int mei_initialize_clients(struct mei_device *dev); int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl); -void mei_remove_client_from_file_list(struct mei_device *dev, u8 host_client_id); void mei_allocate_me_clients_storage(struct mei_device *dev); -int mei_me_cl_update_filext(struct mei_device *dev, struct mei_cl *cl, +int mei_me_cl_link(struct mei_device *dev, struct mei_cl *cl, const uuid_le *cguid, u8 host_client_id); +void mei_me_cl_unlink(struct mei_device *dev, struct mei_cl *cl); int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *cuuid); int mei_me_cl_by_id(struct mei_device *dev, u8 client_id); diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c index 4fc2b3d..636409f 100644 --- a/drivers/misc/mei/wd.c +++ b/drivers/misc/mei/wd.c @@ -62,6 +62,7 @@ static void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout) */ int mei_wd_host_init(struct mei_device *dev) { + int id; mei_cl_init(&dev->wd_cl, dev); /* look for WD client and connect to it */ @@ -69,12 +70,11 @@ int mei_wd_host_init(struct mei_device *dev) dev->wd_timeout = MEI_WD_DEFAULT_TIMEOUT; dev->wd_state = MEI_WD_IDLE; - /* find ME WD client */ - mei_me_cl_update_filext(dev, &dev->wd_cl, + /* Connect WD ME client to the host client */ + id = mei_me_cl_link(dev, &dev->wd_cl, &mei_wd_guid, MEI_WD_HOST_CLIENT_ID); - dev_dbg(&dev->pdev->dev, "wd: check client\n"); - if (MEI_FILE_CONNECTING != dev->wd_cl.state) { + if (id < 0) { dev_info(&dev->pdev->dev, "wd: failed to find the client\n"); return -ENOENT; } -- cgit v0.10.2 From aeba4a06f28fad11b1e61d150bd3cde3008b80c8 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sun, 11 Nov 2012 17:38:04 +0200 Subject: mei: use the same bus msg for connect and disconnect request structs hbm_client_connect_request and hbm_client_disconnect_request have the same layout so we can drop the later Add kdoc for the request and response structure so it is clear they can be used for both purposes Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h index f21721a..be8ca6b 100644 --- a/drivers/misc/mei/hw.h +++ b/drivers/misc/mei/hw.h @@ -293,6 +293,14 @@ struct hbm_props_response { struct mei_client_properties client_properties; } __packed; +/** + * struct hbm_client_connect_request - connect/disconnect request + * + * @hbm_cmd - bus message command header + * @me_addr - address of the client in ME + * @host_addr - address of the client in the driver + * @reserved + */ struct hbm_client_connect_request { u8 hbm_cmd; u8 me_addr; @@ -300,6 +308,14 @@ struct hbm_client_connect_request { u8 reserved; } __packed; +/** + * struct hbm_client_connect_response - connect/disconnect response + * + * @hbm_cmd - bus message command header + * @me_addr - address of the client in ME + * @host_addr - address of the client in the driver + * @status - status of the request + */ struct hbm_client_connect_response { u8 hbm_cmd; u8 me_addr; @@ -307,12 +323,6 @@ struct hbm_client_connect_response { u8 status; } __packed; -struct hbm_client_disconnect_request { - u8 hbm_cmd; - u8 me_addr; - u8 host_addr; - u8 reserved[1]; -} __packed; #define MEI_FC_MESSAGE_RESERVED_LENGTH 5 diff --git a/drivers/misc/mei/interface.c b/drivers/misc/mei/interface.c index 509c395..6b50cf0 100644 --- a/drivers/misc/mei/interface.c +++ b/drivers/misc/mei/interface.c @@ -352,26 +352,24 @@ int mei_other_client_is_connecting(struct mei_device *dev, int mei_disconnect(struct mei_device *dev, struct mei_cl *cl) { struct mei_msg_hdr *mei_hdr; - struct hbm_client_disconnect_request *mei_cli_disconnect; + struct hbm_client_connect_request *req; mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; mei_hdr->host_addr = 0; mei_hdr->me_addr = 0; - mei_hdr->length = sizeof(struct hbm_client_disconnect_request); + mei_hdr->length = sizeof(struct hbm_client_connect_request); mei_hdr->msg_complete = 1; mei_hdr->reserved = 0; - mei_cli_disconnect = - (struct hbm_client_disconnect_request *) &dev->wr_msg_buf[1]; - memset(mei_cli_disconnect, 0, sizeof(*mei_cli_disconnect)); - mei_cli_disconnect->host_addr = cl->host_client_id; - mei_cli_disconnect->me_addr = cl->me_client_id; - mei_cli_disconnect->hbm_cmd = CLIENT_DISCONNECT_REQ_CMD; - mei_cli_disconnect->reserved[0] = 0; + req = (struct hbm_client_connect_request *)&dev->wr_msg_buf[1]; + memset(req, 0, sizeof(*req)); + req->host_addr = cl->host_client_id; + req->me_addr = cl->me_client_id; + req->hbm_cmd = CLIENT_DISCONNECT_REQ_CMD; + req->reserved = 0; - return mei_write_message(dev, mei_hdr, - (unsigned char *) mei_cli_disconnect, - sizeof(struct hbm_client_disconnect_request)); + return mei_write_message(dev, mei_hdr, (unsigned char *)req, + sizeof(struct hbm_client_connect_request)); } /** diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 34e20cc..f882101 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -174,10 +174,10 @@ static int _mei_irq_thread_close(struct mei_device *dev, s32 *slots, struct mei_cl_cb *cmpl_list) { if ((*slots * sizeof(u32)) < (sizeof(struct mei_msg_hdr) + - sizeof(struct hbm_client_disconnect_request))) + sizeof(struct hbm_client_connect_request))) return -EBADMSG; - *slots -= mei_data2slots(sizeof(struct hbm_client_disconnect_request)); + *slots -= mei_data2slots(sizeof(struct hbm_client_connect_request)); if (mei_disconnect(dev, cl)) { cl->status = 0; @@ -414,10 +414,10 @@ static void mei_client_flow_control_response(struct mei_device *dev, * returns !=0, same; 0,not. */ static int same_disconn_addr(struct mei_cl *cl, - struct hbm_client_disconnect_request *disconn) + struct hbm_client_connect_request *req) { - return (cl->host_client_id == disconn->host_addr && - cl->me_client_id == disconn->me_addr); + return (cl->host_client_id == req->host_addr && + cl->me_client_id == req->me_addr); } /** @@ -427,7 +427,7 @@ static int same_disconn_addr(struct mei_cl *cl, * @disconnect_req: disconnect request bus message. */ static void mei_client_disconnect_request(struct mei_device *dev, - struct hbm_client_disconnect_request *disconnect_req) + struct hbm_client_connect_request *disconnect_req) { struct mei_msg_hdr *mei_hdr; struct hbm_client_connect_response *disconnect_res; @@ -484,10 +484,10 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, struct hbm_host_version_response *version_res; struct hbm_client_connect_response *connect_res; struct hbm_client_connect_response *disconnect_res; + struct hbm_client_connect_request *disconnect_req; struct hbm_flow_control *flow_control; struct hbm_props_response *props_res; struct hbm_host_enum_response *enum_res; - struct hbm_client_disconnect_request *disconnect_req; struct hbm_host_stop_request *host_stop_req; int res; @@ -653,8 +653,7 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, case CLIENT_DISCONNECT_REQ_CMD: /* search for client */ - disconnect_req = - (struct hbm_client_disconnect_request *) mei_msg; + disconnect_req = (struct hbm_client_connect_request *)mei_msg; mei_client_disconnect_request(dev, disconnect_req); break; -- cgit v0.10.2 From 95a69adab9acfc3981c504737a2b6578e4d846ef Mon Sep 17 00:00:00 2001 From: Tomas Hozza Date: Thu, 8 Nov 2012 10:53:29 +0100 Subject: tools: hv: Netlink source address validation allows DoS The source code without this patch caused hypervkvpd to exit when it processed a spoofed Netlink packet which has been sent from an untrusted local user. Now Netlink messages with a non-zero nl_pid source address are ignored and a warning is printed into the syslog. Signed-off-by: Tomas Hozza Acked-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index 13c2a14..c1d9102 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c @@ -1486,13 +1486,19 @@ int main(void) len = recvfrom(fd, kvp_recv_buffer, sizeof(kvp_recv_buffer), 0, addr_p, &addr_l); - if (len < 0 || addr.nl_pid) { + if (len < 0) { syslog(LOG_ERR, "recvfrom failed; pid:%u error:%d %s", addr.nl_pid, errno, strerror(errno)); close(fd); return -1; } + if (addr.nl_pid) { + syslog(LOG_WARNING, "Received packet from untrusted pid:%u", + addr.nl_pid); + continue; + } + incoming_msg = (struct nlmsghdr *)kvp_recv_buffer; incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg); hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data; -- cgit v0.10.2 From d892de8d3fb1e807de561289cfb1fed42950440a Mon Sep 17 00:00:00 2001 From: Tomas Hozza Date: Fri, 9 Nov 2012 15:01:20 +0100 Subject: tools/hv: Fix string types Initial patch by Ben Hutchings Standard C strings are arrays of char, not __u8 (unsigned char). Declare variables and parameters accordingly, and add the necessary casts. Signed-off-by: Tomas Hozza Acked-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index c1d9102..d25a469 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c @@ -299,7 +299,7 @@ static int kvp_file_init(void) return 0; } -static int kvp_key_delete(int pool, __u8 *key, int key_size) +static int kvp_key_delete(int pool, const char *key, int key_size) { int i; int j, k; @@ -342,7 +342,7 @@ static int kvp_key_delete(int pool, __u8 *key, int key_size) return 1; } -static int kvp_key_add_or_modify(int pool, __u8 *key, int key_size, __u8 *value, +static int kvp_key_add_or_modify(int pool, const char *key, int key_size, const char *value, int value_size) { int i; @@ -396,7 +396,7 @@ static int kvp_key_add_or_modify(int pool, __u8 *key, int key_size, __u8 *value, return 0; } -static int kvp_get_value(int pool, __u8 *key, int key_size, __u8 *value, +static int kvp_get_value(int pool, const char *key, int key_size, char *value, int value_size) { int i; @@ -428,8 +428,8 @@ static int kvp_get_value(int pool, __u8 *key, int key_size, __u8 *value, return 1; } -static int kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size, - __u8 *value, int value_size) +static int kvp_pool_enumerate(int pool, int index, char *key, int key_size, + char *value, int value_size) { struct kvp_record *record; -- cgit v0.10.2 From 997071bcb34005f42e0fe5bc7930e895b070f251 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Thu, 15 Nov 2012 14:34:42 -0800 Subject: mm: export a function to get vm committed memory It will be useful to be able to access global memory commitment from device drivers. On the Hyper-V platform, the host has a policy engine to balance the available physical memory amongst all competing virtual machines hosted on a given node. This policy engine is driven by a number of metrics including the memory commitment reported by the guests. The balloon driver for Linux on Hyper-V will use this function to retrieve guest memory commitment. This function is also used in Xen self ballooning code. [akpm@linux-foundation.org: coding-style tweak] Signed-off-by: K. Y. Srinivasan Acked-by: David Rientjes Acked-by: Dan Magenheimer Cc: Konrad Rzeszutek Wilk Cc: Jeremy Fitzhardinge Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/xen/xen-selfballoon.c b/drivers/xen/xen-selfballoon.c index 7d041cb..2552d3e 100644 --- a/drivers/xen/xen-selfballoon.c +++ b/drivers/xen/xen-selfballoon.c @@ -222,7 +222,7 @@ static void selfballoon_process(struct work_struct *work) if (xen_selfballooning_enabled) { cur_pages = totalram_pages; tgt_pages = cur_pages; /* default is no change */ - goal_pages = percpu_counter_read_positive(&vm_committed_as) + + goal_pages = vm_memory_committed() + totalreserve_pages + MB2PAGES(selfballoon_reserved_mb); #ifdef CONFIG_FRONTSWAP diff --git a/include/linux/mman.h b/include/linux/mman.h index d09dde1..9aa863d 100644 --- a/include/linux/mman.h +++ b/include/linux/mman.h @@ -11,6 +11,8 @@ extern int sysctl_overcommit_memory; extern int sysctl_overcommit_ratio; extern struct percpu_counter vm_committed_as; +unsigned long vm_memory_committed(void); + static inline void vm_acct_memory(long pages) { percpu_counter_add(&vm_committed_as, pages); diff --git a/mm/mmap.c b/mm/mmap.c index 2d94235..b064822 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -89,6 +89,20 @@ int sysctl_max_map_count __read_mostly = DEFAULT_MAX_MAP_COUNT; struct percpu_counter vm_committed_as ____cacheline_aligned_in_smp; /* + * The global memory commitment made in the system can be a metric + * that can be used to drive ballooning decisions when Linux is hosted + * as a guest. On Hyper-V, the host implements a policy engine for dynamically + * balancing memory across competing virtual machines that are hosted. + * Several metrics drive this policy engine including the guest reported + * memory commitment. + */ +unsigned long vm_memory_committed(void) +{ + return percpu_counter_read_positive(&vm_committed_as); +} +EXPORT_SYMBOL_GPL(vm_memory_committed); + +/* * Check that a process has enough memory to allocate a new virtual * mapping. 0 means there is enough memory for the allocation to * succeed and -ENOMEM implies there is not. diff --git a/mm/nommu.c b/mm/nommu.c index 45131b4..79c3cac 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -66,6 +66,21 @@ int heap_stack_gap = 0; atomic_long_t mmap_pages_allocated; +/* + * The global memory commitment made in the system can be a metric + * that can be used to drive ballooning decisions when Linux is hosted + * as a guest. On Hyper-V, the host implements a policy engine for dynamically + * balancing memory across competing virtual machines that are hosted. + * Several metrics drive this policy engine including the guest reported + * memory commitment. + */ +unsigned long vm_memory_committed(void) +{ + return percpu_counter_read_positive(&vm_committed_as); +} + +EXPORT_SYMBOL_GPL(vm_memory_committed); + EXPORT_SYMBOL(mem_map); EXPORT_SYMBOL(num_physpages); -- cgit v0.10.2 From 9aa8b50b2b3d3a70728438a15a0fdd03a6794a84 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Wed, 14 Nov 2012 01:09:02 -0800 Subject: Drivers: hv: Add Hyper-V balloon driver Add the basic balloon driver. Windows hosts dynamically manage the guest memory allocation via a combination memory hot add and ballooning. Memory hot add is used to grow the guest memory upto the maximum memory that can be allocatted to the guest. Ballooning is used to both shrink as well as expand up to the max memory. Supporting hot add needs additional support from the host. We will support hot add when this support is available. For now, by setting the VM startup memory to the VM max memory, we can use ballooning alone to dynamically manage memory allocation amongst competing guests on a given host. Signed-off-by: K. Y. Srinivasan Reviewed-by: Haiyang Zhang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/hv/Kconfig b/drivers/hv/Kconfig index 70f5dde..b38ef6d 100644 --- a/drivers/hv/Kconfig +++ b/drivers/hv/Kconfig @@ -13,4 +13,10 @@ config HYPERV_UTILS help Select this option to enable the Hyper-V Utilities. +config HYPERV_BALLOON + tristate "Microsoft Hyper-V Balloon driver" + depends on HYPERV + help + Select this option to enable Hyper-V Balloon driver. + endmenu diff --git a/drivers/hv/Makefile b/drivers/hv/Makefile index a23938b..e6abfa0 100644 --- a/drivers/hv/Makefile +++ b/drivers/hv/Makefile @@ -1,5 +1,6 @@ obj-$(CONFIG_HYPERV) += hv_vmbus.o obj-$(CONFIG_HYPERV_UTILS) += hv_utils.o +obj-$(CONFIG_HYPERV_BALLOON) += hv_balloon.o hv_vmbus-y := vmbus_drv.o \ hv.o connection.o channel.o \ diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c new file mode 100644 index 0000000..bbc4973 --- /dev/null +++ b/drivers/hv/hv_balloon.c @@ -0,0 +1,1041 @@ +/* + * Copyright (c) 2012, Microsoft Corporation. + * + * Author: + * K. Y. Srinivasan + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * We begin with definitions supporting the Dynamic Memory protocol + * with the host. + * + * Begin protocol definitions. + */ + + + +/* + * Protocol versions. The low word is the minor version, the high word the major + * version. + * + * History: + * Initial version 1.0 + * Changed to 0.1 on 2009/03/25 + * Changes to 0.2 on 2009/05/14 + * Changes to 0.3 on 2009/12/03 + * Changed to 1.0 on 2011/04/05 + */ + +#define DYNMEM_MAKE_VERSION(Major, Minor) ((__u32)(((Major) << 16) | (Minor))) +#define DYNMEM_MAJOR_VERSION(Version) ((__u32)(Version) >> 16) +#define DYNMEM_MINOR_VERSION(Version) ((__u32)(Version) & 0xff) + +enum { + DYNMEM_PROTOCOL_VERSION_1 = DYNMEM_MAKE_VERSION(0, 3), + DYNMEM_PROTOCOL_VERSION_2 = DYNMEM_MAKE_VERSION(1, 0), + + DYNMEM_PROTOCOL_VERSION_WIN7 = DYNMEM_PROTOCOL_VERSION_1, + DYNMEM_PROTOCOL_VERSION_WIN8 = DYNMEM_PROTOCOL_VERSION_2, + + DYNMEM_PROTOCOL_VERSION_CURRENT = DYNMEM_PROTOCOL_VERSION_WIN8 +}; + + + +/* + * Message Types + */ + +enum dm_message_type { + /* + * Version 0.3 + */ + DM_ERROR = 0, + DM_VERSION_REQUEST = 1, + DM_VERSION_RESPONSE = 2, + DM_CAPABILITIES_REPORT = 3, + DM_CAPABILITIES_RESPONSE = 4, + DM_STATUS_REPORT = 5, + DM_BALLOON_REQUEST = 6, + DM_BALLOON_RESPONSE = 7, + DM_UNBALLOON_REQUEST = 8, + DM_UNBALLOON_RESPONSE = 9, + DM_MEM_HOT_ADD_REQUEST = 10, + DM_MEM_HOT_ADD_RESPONSE = 11, + DM_VERSION_03_MAX = 11, + /* + * Version 1.0. + */ + DM_INFO_MESSAGE = 12, + DM_VERSION_1_MAX = 12 +}; + + +/* + * Structures defining the dynamic memory management + * protocol. + */ + +union dm_version { + struct { + __u16 minor_version; + __u16 major_version; + }; + __u32 version; +} __packed; + + +union dm_caps { + struct { + __u64 balloon:1; + __u64 hot_add:1; + __u64 reservedz:62; + } cap_bits; + __u64 caps; +} __packed; + +union dm_mem_page_range { + struct { + /* + * The PFN number of the first page in the range. + * 40 bits is the architectural limit of a PFN + * number for AMD64. + */ + __u64 start_page:40; + /* + * The number of pages in the range. + */ + __u64 page_cnt:24; + } finfo; + __u64 page_range; +} __packed; + + + +/* + * The header for all dynamic memory messages: + * + * type: Type of the message. + * size: Size of the message in bytes; including the header. + * trans_id: The guest is responsible for manufacturing this ID. + */ + +struct dm_header { + __u16 type; + __u16 size; + __u32 trans_id; +} __packed; + +/* + * A generic message format for dynamic memory. + * Specific message formats are defined later in the file. + */ + +struct dm_message { + struct dm_header hdr; + __u8 data[]; /* enclosed message */ +} __packed; + + +/* + * Specific message types supporting the dynamic memory protocol. + */ + +/* + * Version negotiation message. Sent from the guest to the host. + * The guest is free to try different versions until the host + * accepts the version. + * + * dm_version: The protocol version requested. + * is_last_attempt: If TRUE, this is the last version guest will request. + * reservedz: Reserved field, set to zero. + */ + +struct dm_version_request { + struct dm_header hdr; + union dm_version version; + __u32 is_last_attempt:1; + __u32 reservedz:31; +} __packed; + +/* + * Version response message; Host to Guest and indicates + * if the host has accepted the version sent by the guest. + * + * is_accepted: If TRUE, host has accepted the version and the guest + * should proceed to the next stage of the protocol. FALSE indicates that + * guest should re-try with a different version. + * + * reservedz: Reserved field, set to zero. + */ + +struct dm_version_response { + struct dm_header hdr; + __u64 is_accepted:1; + __u64 reservedz:63; +} __packed; + +/* + * Message reporting capabilities. This is sent from the guest to the + * host. + */ + +struct dm_capabilities { + struct dm_header hdr; + union dm_caps caps; + __u64 min_page_cnt; + __u64 max_page_number; +} __packed; + +/* + * Response to the capabilities message. This is sent from the host to the + * guest. This message notifies if the host has accepted the guest's + * capabilities. If the host has not accepted, the guest must shutdown + * the service. + * + * is_accepted: Indicates if the host has accepted guest's capabilities. + * reservedz: Must be 0. + */ + +struct dm_capabilities_resp_msg { + struct dm_header hdr; + __u64 is_accepted:1; + __u64 reservedz:63; +} __packed; + +/* + * This message is used to report memory pressure from the guest. + * This message is not part of any transaction and there is no + * response to this message. + * + * num_avail: Available memory in pages. + * num_committed: Committed memory in pages. + * page_file_size: The accumulated size of all page files + * in the system in pages. + * zero_free: The nunber of zero and free pages. + * page_file_writes: The writes to the page file in pages. + * io_diff: An indicator of file cache efficiency or page file activity, + * calculated as File Cache Page Fault Count - Page Read Count. + * This value is in pages. + * + * Some of these metrics are Windows specific and fortunately + * the algorithm on the host side that computes the guest memory + * pressure only uses num_committed value. + */ + +struct dm_status { + struct dm_header hdr; + __u64 num_avail; + __u64 num_committed; + __u64 page_file_size; + __u64 zero_free; + __u32 page_file_writes; + __u32 io_diff; +} __packed; + + +/* + * Message to ask the guest to allocate memory - balloon up message. + * This message is sent from the host to the guest. The guest may not be + * able to allocate as much memory as requested. + * + * num_pages: number of pages to allocate. + */ + +struct dm_balloon { + struct dm_header hdr; + __u32 num_pages; + __u32 reservedz; +} __packed; + + +/* + * Balloon response message; this message is sent from the guest + * to the host in response to the balloon message. + * + * reservedz: Reserved; must be set to zero. + * more_pages: If FALSE, this is the last message of the transaction. + * if TRUE there will atleast one more message from the guest. + * + * range_count: The number of ranges in the range array. + * + * range_array: An array of page ranges returned to the host. + * + */ + +struct dm_balloon_response { + struct dm_header hdr; + __u32 reservedz; + __u32 more_pages:1; + __u32 range_count:31; + union dm_mem_page_range range_array[]; +} __packed; + +/* + * Un-balloon message; this message is sent from the host + * to the guest to give guest more memory. + * + * more_pages: If FALSE, this is the last message of the transaction. + * if TRUE there will atleast one more message from the guest. + * + * reservedz: Reserved; must be set to zero. + * + * range_count: The number of ranges in the range array. + * + * range_array: An array of page ranges returned to the host. + * + */ + +struct dm_unballoon_request { + struct dm_header hdr; + __u32 more_pages:1; + __u32 reservedz:31; + __u32 range_count; + union dm_mem_page_range range_array[]; +} __packed; + +/* + * Un-balloon response message; this message is sent from the guest + * to the host in response to an unballoon request. + * + */ + +struct dm_unballoon_response { + struct dm_header hdr; +} __packed; + + +/* + * Hot add request message. Message sent from the host to the guest. + * + * mem_range: Memory range to hot add. + * + * On Linux we currently don't support this since we cannot hot add + * arbitrary granularity of memory. + */ + +struct dm_hot_add { + struct dm_header hdr; + union dm_mem_page_range range; +} __packed; + +/* + * Hot add response message. + * This message is sent by the guest to report the status of a hot add request. + * If page_count is less than the requested page count, then the host should + * assume all further hot add requests will fail, since this indicates that + * the guest has hit an upper physical memory barrier. + * + * Hot adds may also fail due to low resources; in this case, the guest must + * not complete this message until the hot add can succeed, and the host must + * not send a new hot add request until the response is sent. + * If VSC fails to hot add memory DYNMEM_NUMBER_OF_UNSUCCESSFUL_HOTADD_ATTEMPTS + * times it fails the request. + * + * + * page_count: number of pages that were successfully hot added. + * + * result: result of the operation 1: success, 0: failure. + * + */ + +struct dm_hot_add_response { + struct dm_header hdr; + __u32 page_count; + __u32 result; +} __packed; + +/* + * Types of information sent from host to the guest. + */ + +enum dm_info_type { + INFO_TYPE_MAX_PAGE_CNT = 0, + MAX_INFO_TYPE +}; + + +/* + * Header for the information message. + */ + +struct dm_info_header { + enum dm_info_type type; + __u32 data_size; +} __packed; + +/* + * This message is sent from the host to the guest to pass + * some relevant information (win8 addition). + * + * reserved: no used. + * info_size: size of the information blob. + * info: information blob. + */ + +struct dm_info_msg { + struct dm_info_header header; + __u32 reserved; + __u32 info_size; + __u8 info[]; +}; + +/* + * End protocol definitions. + */ + +static bool hot_add; +static bool do_hot_add; + +module_param(hot_add, bool, (S_IRUGO | S_IWUSR)); +MODULE_PARM_DESC(hot_add, "If set attempt memory hot_add"); + +static atomic_t trans_id = ATOMIC_INIT(0); + +static int dm_ring_size = (5 * PAGE_SIZE); + +/* + * Driver specific state. + */ + +enum hv_dm_state { + DM_INITIALIZING = 0, + DM_INITIALIZED, + DM_BALLOON_UP, + DM_BALLOON_DOWN, + DM_HOT_ADD, + DM_INIT_ERROR +}; + + +static __u8 recv_buffer[PAGE_SIZE]; +static __u8 *send_buffer; +#define PAGES_IN_2M 512 + +struct hv_dynmem_device { + struct hv_device *dev; + enum hv_dm_state state; + struct completion host_event; + struct completion config_event; + + /* + * Number of pages we have currently ballooned out. + */ + unsigned int num_pages_ballooned; + + /* + * This thread handles both balloon/hot-add + * requests from the host as well as notifying + * the host with regards to memory pressure in + * the guest. + */ + struct task_struct *thread; + + /* + * We start with the highest version we can support + * and downgrade based on the host; we save here the + * next version to try. + */ + __u32 next_version; +}; + +static struct hv_dynmem_device dm_device; + +static void hot_add_req(struct hv_dynmem_device *dm, struct dm_hot_add *msg) +{ + + struct dm_hot_add_response resp; + + if (do_hot_add) { + + pr_info("Memory hot add not supported\n"); + + /* + * Currently we do not support hot add. + * Just fail the request. + */ + } + + memset(&resp, 0, sizeof(struct dm_hot_add_response)); + resp.hdr.type = DM_MEM_HOT_ADD_RESPONSE; + resp.hdr.size = sizeof(struct dm_hot_add_response); + resp.hdr.trans_id = atomic_inc_return(&trans_id); + + resp.page_count = 0; + resp.result = 0; + + dm->state = DM_INITIALIZED; + vmbus_sendpacket(dm->dev->channel, &resp, + sizeof(struct dm_hot_add_response), + (unsigned long)NULL, + VM_PKT_DATA_INBAND, 0); + +} + +static void process_info(struct hv_dynmem_device *dm, struct dm_info_msg *msg) +{ + switch (msg->header.type) { + case INFO_TYPE_MAX_PAGE_CNT: + pr_info("Received INFO_TYPE_MAX_PAGE_CNT\n"); + pr_info("Data Size is %d\n", msg->header.data_size); + break; + default: + pr_info("Received Unknown type: %d\n", msg->header.type); + } +} + +/* + * Post our status as it relates memory pressure to the + * host. Host expects the guests to post this status + * periodically at 1 second intervals. + * + * The metrics specified in this protocol are very Windows + * specific and so we cook up numbers here to convey our memory + * pressure. + */ + +static void post_status(struct hv_dynmem_device *dm) +{ + struct dm_status status; + + + memset(&status, 0, sizeof(struct dm_status)); + status.hdr.type = DM_STATUS_REPORT; + status.hdr.size = sizeof(struct dm_status); + status.hdr.trans_id = atomic_inc_return(&trans_id); + + + status.num_committed = vm_memory_committed(); + + vmbus_sendpacket(dm->dev->channel, &status, + sizeof(struct dm_status), + (unsigned long)NULL, + VM_PKT_DATA_INBAND, 0); + +} + + + +void free_balloon_pages(struct hv_dynmem_device *dm, + union dm_mem_page_range *range_array) +{ + int num_pages = range_array->finfo.page_cnt; + __u64 start_frame = range_array->finfo.start_page; + struct page *pg; + int i; + + for (i = 0; i < num_pages; i++) { + pg = pfn_to_page(i + start_frame); + __free_page(pg); + dm->num_pages_ballooned--; + } +} + + + +static int alloc_balloon_pages(struct hv_dynmem_device *dm, int num_pages, + struct dm_balloon_response *bl_resp, int alloc_unit, + bool *alloc_error) +{ + int i = 0; + struct page *pg; + + if (num_pages < alloc_unit) + return 0; + + for (i = 0; (i * alloc_unit) < num_pages; i++) { + if (bl_resp->hdr.size + sizeof(union dm_mem_page_range) > + PAGE_SIZE) + return i * alloc_unit; + + /* + * We execute this code in a thread context. Furthermore, + * we don't want the kernel to try too hard. + */ + pg = alloc_pages(GFP_HIGHUSER | __GFP_NORETRY | + __GFP_NOMEMALLOC | __GFP_NOWARN, + get_order(alloc_unit << PAGE_SHIFT)); + + if (!pg) { + *alloc_error = true; + return i * alloc_unit; + } + + + dm->num_pages_ballooned += alloc_unit; + + bl_resp->range_count++; + bl_resp->range_array[i].finfo.start_page = + page_to_pfn(pg); + bl_resp->range_array[i].finfo.page_cnt = alloc_unit; + bl_resp->hdr.size += sizeof(union dm_mem_page_range); + + } + + return num_pages; +} + + + +static void balloon_up(struct hv_dynmem_device *dm, struct dm_balloon *req) +{ + int num_pages = req->num_pages; + int num_ballooned = 0; + struct dm_balloon_response *bl_resp; + int alloc_unit; + int ret; + bool alloc_error = false; + bool done = false; + int i; + + + /* + * Currently, we only support 4k allocations. + */ + alloc_unit = 1; + + while (!done) { + bl_resp = (struct dm_balloon_response *)send_buffer; + memset(send_buffer, 0, PAGE_SIZE); + bl_resp->hdr.type = DM_BALLOON_RESPONSE; + bl_resp->hdr.trans_id = atomic_inc_return(&trans_id); + bl_resp->hdr.size = sizeof(struct dm_balloon_response); + bl_resp->more_pages = 1; + + + num_pages -= num_ballooned; + num_ballooned = alloc_balloon_pages(dm, num_pages, + bl_resp, alloc_unit, + &alloc_error); + + if ((alloc_error) || (num_ballooned == num_pages)) { + bl_resp->more_pages = 0; + done = true; + dm->state = DM_INITIALIZED; + } + + /* + * We are pushing a lot of data through the channel; + * deal with transient failures caused because of the + * lack of space in the ring buffer. + */ + + do { + ret = vmbus_sendpacket(dm_device.dev->channel, + bl_resp, + bl_resp->hdr.size, + (unsigned long)NULL, + VM_PKT_DATA_INBAND, 0); + + if (ret == -EAGAIN) + msleep(20); + + } while (ret == -EAGAIN); + + if (ret) { + /* + * Free up the memory we allocatted. + */ + pr_info("Balloon response failed\n"); + + for (i = 0; i < bl_resp->range_count; i++) + free_balloon_pages(dm, + &bl_resp->range_array[i]); + + done = true; + } + } + +} + +static void balloon_down(struct hv_dynmem_device *dm, + struct dm_unballoon_request *req) +{ + union dm_mem_page_range *range_array = req->range_array; + int range_count = req->range_count; + struct dm_unballoon_response resp; + int i; + + for (i = 0; i < range_count; i++) + free_balloon_pages(dm, &range_array[i]); + + if (req->more_pages == 1) + return; + + memset(&resp, 0, sizeof(struct dm_unballoon_response)); + resp.hdr.type = DM_UNBALLOON_RESPONSE; + resp.hdr.trans_id = atomic_inc_return(&trans_id); + resp.hdr.size = sizeof(struct dm_unballoon_response); + + vmbus_sendpacket(dm_device.dev->channel, &resp, + sizeof(struct dm_unballoon_response), + (unsigned long)NULL, + VM_PKT_DATA_INBAND, 0); + + dm->state = DM_INITIALIZED; +} + +static void balloon_onchannelcallback(void *context); + +static int dm_thread_func(void *dm_dev) +{ + struct hv_dynmem_device *dm = dm_dev; + int t; + unsigned long scan_start; + + while (!kthread_should_stop()) { + t = wait_for_completion_timeout(&dm_device.config_event, 1*HZ); + /* + * The host expects us to post information on the memory + * pressure every second. + */ + + if (t == 0) + post_status(dm); + + scan_start = jiffies; + switch (dm->state) { + case DM_BALLOON_UP: + balloon_up(dm, (struct dm_balloon *)recv_buffer); + break; + + case DM_HOT_ADD: + hot_add_req(dm, (struct dm_hot_add *)recv_buffer); + break; + default: + break; + } + + if (!time_in_range(jiffies, scan_start, scan_start + HZ)) + post_status(dm); + + } + + return 0; +} + + +static void version_resp(struct hv_dynmem_device *dm, + struct dm_version_response *vresp) +{ + struct dm_version_request version_req; + int ret; + + if (vresp->is_accepted) { + /* + * We are done; wakeup the + * context waiting for version + * negotiation. + */ + complete(&dm->host_event); + return; + } + /* + * If there are more versions to try, continue + * with negotiations; if not + * shutdown the service since we are not able + * to negotiate a suitable version number + * with the host. + */ + if (dm->next_version == 0) + goto version_error; + + dm->next_version = 0; + memset(&version_req, 0, sizeof(struct dm_version_request)); + version_req.hdr.type = DM_VERSION_REQUEST; + version_req.hdr.size = sizeof(struct dm_version_request); + version_req.hdr.trans_id = atomic_inc_return(&trans_id); + version_req.version.version = DYNMEM_PROTOCOL_VERSION_WIN7; + version_req.is_last_attempt = 1; + + ret = vmbus_sendpacket(dm->dev->channel, &version_req, + sizeof(struct dm_version_request), + (unsigned long)NULL, + VM_PKT_DATA_INBAND, 0); + + if (ret) + goto version_error; + + return; + +version_error: + dm->state = DM_INIT_ERROR; + complete(&dm->host_event); +} + +static void cap_resp(struct hv_dynmem_device *dm, + struct dm_capabilities_resp_msg *cap_resp) +{ + if (!cap_resp->is_accepted) { + pr_info("Capabilities not accepted by host\n"); + dm->state = DM_INIT_ERROR; + } + complete(&dm->host_event); +} + +static void balloon_onchannelcallback(void *context) +{ + struct hv_device *dev = context; + u32 recvlen; + u64 requestid; + struct dm_message *dm_msg; + struct dm_header *dm_hdr; + struct hv_dynmem_device *dm = hv_get_drvdata(dev); + + memset(recv_buffer, 0, sizeof(recv_buffer)); + vmbus_recvpacket(dev->channel, recv_buffer, + PAGE_SIZE, &recvlen, &requestid); + + if (recvlen > 0) { + dm_msg = (struct dm_message *)recv_buffer; + dm_hdr = &dm_msg->hdr; + + switch (dm_hdr->type) { + case DM_VERSION_RESPONSE: + version_resp(dm, + (struct dm_version_response *)dm_msg); + break; + + case DM_CAPABILITIES_RESPONSE: + cap_resp(dm, + (struct dm_capabilities_resp_msg *)dm_msg); + break; + + case DM_BALLOON_REQUEST: + dm->state = DM_BALLOON_UP; + complete(&dm->config_event); + break; + + case DM_UNBALLOON_REQUEST: + dm->state = DM_BALLOON_DOWN; + balloon_down(dm, + (struct dm_unballoon_request *)recv_buffer); + break; + + case DM_MEM_HOT_ADD_REQUEST: + dm->state = DM_HOT_ADD; + complete(&dm->config_event); + break; + + case DM_INFO_MESSAGE: + process_info(dm, (struct dm_info_msg *)dm_msg); + break; + + default: + pr_err("Unhandled message: type: %d\n", dm_hdr->type); + + } + } + +} + +static int balloon_probe(struct hv_device *dev, + const struct hv_vmbus_device_id *dev_id) +{ + int ret, t; + struct dm_version_request version_req; + struct dm_capabilities cap_msg; + + do_hot_add = hot_add; + + /* + * First allocate a send buffer. + */ + + send_buffer = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!send_buffer) + return -ENOMEM; + + ret = vmbus_open(dev->channel, dm_ring_size, dm_ring_size, NULL, 0, + balloon_onchannelcallback, dev); + + if (ret) + return ret; + + dm_device.dev = dev; + dm_device.state = DM_INITIALIZING; + dm_device.next_version = DYNMEM_PROTOCOL_VERSION_WIN7; + init_completion(&dm_device.host_event); + init_completion(&dm_device.config_event); + + dm_device.thread = + kthread_run(dm_thread_func, &dm_device, "hv_balloon"); + if (IS_ERR(dm_device.thread)) { + ret = PTR_ERR(dm_device.thread); + goto probe_error0; + } + + hv_set_drvdata(dev, &dm_device); + /* + * Initiate the hand shake with the host and negotiate + * a version that the host can support. We start with the + * highest version number and go down if the host cannot + * support it. + */ + memset(&version_req, 0, sizeof(struct dm_version_request)); + version_req.hdr.type = DM_VERSION_REQUEST; + version_req.hdr.size = sizeof(struct dm_version_request); + version_req.hdr.trans_id = atomic_inc_return(&trans_id); + version_req.version.version = DYNMEM_PROTOCOL_VERSION_WIN8; + version_req.is_last_attempt = 0; + + ret = vmbus_sendpacket(dev->channel, &version_req, + sizeof(struct dm_version_request), + (unsigned long)NULL, + VM_PKT_DATA_INBAND, + VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); + if (ret) + goto probe_error1; + + t = wait_for_completion_timeout(&dm_device.host_event, 5*HZ); + if (t == 0) { + ret = -ETIMEDOUT; + goto probe_error1; + } + + /* + * If we could not negotiate a compatible version with the host + * fail the probe function. + */ + if (dm_device.state == DM_INIT_ERROR) { + ret = -ETIMEDOUT; + goto probe_error1; + } + /* + * Now submit our capabilities to the host. + */ + memset(&cap_msg, 0, sizeof(struct dm_capabilities)); + cap_msg.hdr.type = DM_CAPABILITIES_REPORT; + cap_msg.hdr.size = sizeof(struct dm_capabilities); + cap_msg.hdr.trans_id = atomic_inc_return(&trans_id); + + cap_msg.caps.cap_bits.balloon = 1; + /* + * While we currently don't support hot-add, + * we still advertise this capability since the + * host requires that guests partcipating in the + * dynamic memory protocol support hot add. + */ + cap_msg.caps.cap_bits.hot_add = 1; + + /* + * Currently the host does not use these + * values and we set them to what is done in the + * Windows driver. + */ + cap_msg.min_page_cnt = 0; + cap_msg.max_page_number = -1; + + ret = vmbus_sendpacket(dev->channel, &cap_msg, + sizeof(struct dm_capabilities), + (unsigned long)NULL, + VM_PKT_DATA_INBAND, + VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); + if (ret) + goto probe_error1; + + t = wait_for_completion_timeout(&dm_device.host_event, 5*HZ); + if (t == 0) { + ret = -ETIMEDOUT; + goto probe_error1; + } + + /* + * If the host does not like our capabilities, + * fail the probe function. + */ + if (dm_device.state == DM_INIT_ERROR) { + ret = -ETIMEDOUT; + goto probe_error1; + } + + dm_device.state = DM_INITIALIZED; + + return 0; + +probe_error1: + kthread_stop(dm_device.thread); + +probe_error0: + vmbus_close(dev->channel); + return ret; +} + +static int balloon_remove(struct hv_device *dev) +{ + struct hv_dynmem_device *dm = hv_get_drvdata(dev); + + if (dm->num_pages_ballooned != 0) + pr_warn("Ballooned pages: %d\n", dm->num_pages_ballooned); + + vmbus_close(dev->channel); + kthread_stop(dm->thread); + + return 0; +} + +static const struct hv_vmbus_device_id id_table[] = { + /* Dynamic Memory Class ID */ + /* 525074DC-8985-46e2-8057-A307DC18A502 */ + { VMBUS_DEVICE(0xdc, 0x74, 0x50, 0X52, 0x85, 0x89, 0xe2, 0x46, + 0x80, 0x57, 0xa3, 0x07, 0xdc, 0x18, 0xa5, 0x02) + }, + { }, +}; + +MODULE_DEVICE_TABLE(vmbus, id_table); + +static struct hv_driver balloon_drv = { + .name = "hv_balloon", + .id_table = id_table, + .probe = balloon_probe, + .remove = balloon_remove, +}; + +static int __init init_balloon_drv(void) +{ + + return vmbus_driver_register(&balloon_drv); +} + +static void exit_balloon_drv(void) +{ + + vmbus_driver_unregister(&balloon_drv); +} + +module_init(init_balloon_drv); +module_exit(exit_balloon_drv); + +MODULE_DESCRIPTION("Hyper-V Balloon"); +MODULE_VERSION(HV_DRV_VERSION); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 6e8bd6e727c5ec949194087ac6b593e1e7fe79c4 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Mon, 5 Nov 2012 15:04:23 -0800 Subject: drivers/parport: remove depends on CONFIG_EXPERIMENTAL The CONFIG_EXPERIMENTAL config item has not carried much meaning for a while now and is almost always enabled by default. As agreed during the Linux kernel summit, remove it from any "depends on" lines in Kconfigs. Signed-off-by: Kees Cook Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/parport/Kconfig b/drivers/parport/Kconfig index 4b6e4e7..0e60438 100644 --- a/drivers/parport/Kconfig +++ b/drivers/parport/Kconfig @@ -57,8 +57,8 @@ config PARPORT_SERIAL will be called parport_serial. config PARPORT_PC_FIFO - bool "Use FIFO/DMA if available (EXPERIMENTAL)" - depends on PARPORT_PC && EXPERIMENTAL + bool "Use FIFO/DMA if available" + depends on PARPORT_PC help Many parallel port chipsets provide hardware that can speed up printing. Say Y here if you want to take advantage of that. @@ -70,8 +70,8 @@ config PARPORT_PC_FIFO specify which IRQ/DMA to use. config PARPORT_PC_SUPERIO - bool "SuperIO chipset support (EXPERIMENTAL)" - depends on PARPORT_PC && EXPERIMENTAL + bool "SuperIO chipset support" + depends on PARPORT_PC help Saying Y here enables some probes for Super-IO chipsets in order to find out things like base addresses, IRQ lines and DMA channels. It @@ -85,8 +85,8 @@ config PARPORT_PC_PCMCIA ports. If unsure, say N. config PARPORT_IP32 - tristate "SGI IP32 builtin port (EXPERIMENTAL)" - depends on SGI_IP32 && EXPERIMENTAL + tristate "SGI IP32 builtin port" + depends on SGI_IP32 select PARPORT_NOT_PC help Say Y here if you need support for the parallel port on @@ -126,8 +126,8 @@ config PARPORT_GSC select PARPORT_NOT_PC config PARPORT_SUNBPP - tristate "Sparc hardware (EXPERIMENTAL)" - depends on SBUS && EXPERIMENTAL + tristate "Sparc hardware" + depends on SBUS select PARPORT_NOT_PC help This driver provides support for the bidirectional parallel port -- cgit v0.10.2 From ecd43c0d7e504fde69e6e53ac63adfd2feea135a Mon Sep 17 00:00:00 2001 From: Manuel Traut Date: Fri, 9 Nov 2012 07:06:40 +0100 Subject: uio_pdrv: set memory mapping name If uio_pdrv[_genirq] is used, the uio maps have currently no name set. This patch sets the uio_mem name to the name of the memory resource. Signed-off-by: Manuel Traut Reported-by: Stefan Staedtler Tested-by: Stefan Staedtler Signed-off-by: "Hans J. Koch" Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/uio/uio_pdrv.c b/drivers/uio/uio_pdrv.c index 72d3646..39be9e0 100644 --- a/drivers/uio/uio_pdrv.c +++ b/drivers/uio/uio_pdrv.c @@ -60,6 +60,7 @@ static int uio_pdrv_probe(struct platform_device *pdev) uiomem->memtype = UIO_MEM_PHYS; uiomem->addr = r->start; uiomem->size = resource_size(r); + uiomem->name = r->name; ++uiomem; } diff --git a/drivers/uio/uio_pdrv_genirq.c b/drivers/uio/uio_pdrv_genirq.c index 42202cd..ac988ce 100644 --- a/drivers/uio/uio_pdrv_genirq.c +++ b/drivers/uio/uio_pdrv_genirq.c @@ -172,6 +172,7 @@ static int uio_pdrv_genirq_probe(struct platform_device *pdev) uiomem->memtype = UIO_MEM_PHYS; uiomem->addr = r->start; uiomem->size = resource_size(r); + uiomem->name = r->name; ++uiomem; } -- cgit v0.10.2 From 67d16a4686c9b94c8f52a66afe7521909aeb75b4 Mon Sep 17 00:00:00 2001 From: Wei WANG Date: Fri, 9 Nov 2012 20:53:33 +0800 Subject: drivers/mfd: Add realtek pcie card reader driver Realtek PCI-E card reader driver adapts requests from upper-level sdmmc/memstick layer to the real physical card reader. Signed-off-by: Wei WANG Reviewed-by: Arnd Bergmann Tested-by: Borislav Petkov Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index acab3ef..867af07 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -63,6 +63,15 @@ config MFD_SM501_GPIO lines on the SM501. The platform data is used to supply the base number for the first GPIO line to register. +config MFD_RTSX_PCI + tristate "Support for Realtek PCI-E card reader" + depends on PCI + help + This supports for Realtek PCI-Express card reader including rts5209, + rts5229, rtl8411, etc. Realtek card reader supports access to many + types of memory cards, such as Memory Stick, Memory Stick Pro, + Secure Digital and MultiMediaCard. + config MFD_ASIC3 bool "Support for Compaq ASIC3" depends on GENERIC_HARDIRQS && GPIOLIB && ARM diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index d8ccb63..b53db06 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -9,6 +9,9 @@ obj-$(CONFIG_MFD_88PM805) += 88pm805.o 88pm80x.o obj-$(CONFIG_MFD_SM501) += sm501.o obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o +rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o +obj-$(CONFIG_MFD_RTSX_PCI) += rtsx_pci.o + obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o diff --git a/drivers/mfd/rtl8411.c b/drivers/mfd/rtl8411.c new file mode 100644 index 0000000..89f046c --- /dev/null +++ b/drivers/mfd/rtl8411.c @@ -0,0 +1,251 @@ +/* Driver for Realtek PCI-Express card reader + * + * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + * + * Author: + * Wei WANG + * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China + */ + +#include +#include +#include +#include + +#include "rtsx_pcr.h" + +static u8 rtl8411_get_ic_version(struct rtsx_pcr *pcr) +{ + u8 val; + + rtsx_pci_read_register(pcr, SYS_VER, &val); + return val & 0x0F; +} + +static int rtl8411_extra_init_hw(struct rtsx_pcr *pcr) +{ + return rtsx_pci_write_register(pcr, CD_PAD_CTL, + CD_DISABLE_MASK | CD_AUTO_DISABLE, CD_ENABLE); +} + +static int rtl8411_turn_on_led(struct rtsx_pcr *pcr) +{ + return rtsx_pci_write_register(pcr, CARD_GPIO, 0x01, 0x00); +} + +static int rtl8411_turn_off_led(struct rtsx_pcr *pcr) +{ + return rtsx_pci_write_register(pcr, CARD_GPIO, 0x01, 0x01); +} + +static int rtl8411_enable_auto_blink(struct rtsx_pcr *pcr) +{ + return rtsx_pci_write_register(pcr, CARD_AUTO_BLINK, 0xFF, 0x0D); +} + +static int rtl8411_disable_auto_blink(struct rtsx_pcr *pcr) +{ + return rtsx_pci_write_register(pcr, CARD_AUTO_BLINK, 0x08, 0x00); +} + +static int rtl8411_card_power_on(struct rtsx_pcr *pcr, int card) +{ + int err; + + rtsx_pci_init_cmd(pcr); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, + BPP_POWER_MASK, BPP_POWER_5_PERCENT_ON); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_CTL, + BPP_LDO_POWB, BPP_LDO_SUSPEND); + err = rtsx_pci_send_cmd(pcr, 100); + if (err < 0) + return err; + + /* To avoid too large in-rush current */ + udelay(150); + + err = rtsx_pci_write_register(pcr, CARD_PWR_CTL, + BPP_POWER_MASK, BPP_POWER_10_PERCENT_ON); + if (err < 0) + return err; + + udelay(150); + + err = rtsx_pci_write_register(pcr, CARD_PWR_CTL, + BPP_POWER_MASK, BPP_POWER_15_PERCENT_ON); + if (err < 0) + return err; + + udelay(150); + + err = rtsx_pci_write_register(pcr, CARD_PWR_CTL, + BPP_POWER_MASK, BPP_POWER_ON); + if (err < 0) + return err; + + return rtsx_pci_write_register(pcr, LDO_CTL, BPP_LDO_POWB, BPP_LDO_ON); +} + +static int rtl8411_card_power_off(struct rtsx_pcr *pcr, int card) +{ + int err; + + err = rtsx_pci_write_register(pcr, CARD_PWR_CTL, + BPP_POWER_MASK, BPP_POWER_OFF); + if (err < 0) + return err; + + return rtsx_pci_write_register(pcr, LDO_CTL, + BPP_LDO_POWB, BPP_LDO_SUSPEND); +} + +static unsigned int rtl8411_cd_deglitch(struct rtsx_pcr *pcr) +{ + unsigned int card_exist; + + card_exist = rtsx_pci_readl(pcr, RTSX_BIPR); + card_exist &= CARD_EXIST; + if (!card_exist) { + /* Enable card CD */ + rtsx_pci_write_register(pcr, CD_PAD_CTL, + CD_DISABLE_MASK, CD_ENABLE); + /* Enable card interrupt */ + rtsx_pci_write_register(pcr, EFUSE_CONTENT, 0xe0, 0x00); + return 0; + } + + if (hweight32(card_exist) > 1) { + rtsx_pci_write_register(pcr, CARD_PWR_CTL, + BPP_POWER_MASK, BPP_POWER_5_PERCENT_ON); + msleep(100); + + card_exist = rtsx_pci_readl(pcr, RTSX_BIPR); + if (card_exist & MS_EXIST) + card_exist = MS_EXIST; + else if (card_exist & SD_EXIST) + card_exist = SD_EXIST; + else + card_exist = 0; + + rtsx_pci_write_register(pcr, CARD_PWR_CTL, + BPP_POWER_MASK, BPP_POWER_OFF); + + dev_dbg(&(pcr->pci->dev), + "After CD deglitch, card_exist = 0x%x\n", + card_exist); + } + + if (card_exist & MS_EXIST) { + /* Disable SD interrupt */ + rtsx_pci_write_register(pcr, EFUSE_CONTENT, 0xe0, 0x40); + rtsx_pci_write_register(pcr, CD_PAD_CTL, + CD_DISABLE_MASK, MS_CD_EN_ONLY); + } else if (card_exist & SD_EXIST) { + /* Disable MS interrupt */ + rtsx_pci_write_register(pcr, EFUSE_CONTENT, 0xe0, 0x80); + rtsx_pci_write_register(pcr, CD_PAD_CTL, + CD_DISABLE_MASK, SD_CD_EN_ONLY); + } + + return card_exist; +} + +static const struct pcr_ops rtl8411_pcr_ops = { + .extra_init_hw = rtl8411_extra_init_hw, + .optimize_phy = NULL, + .turn_on_led = rtl8411_turn_on_led, + .turn_off_led = rtl8411_turn_off_led, + .enable_auto_blink = rtl8411_enable_auto_blink, + .disable_auto_blink = rtl8411_disable_auto_blink, + .card_power_on = rtl8411_card_power_on, + .card_power_off = rtl8411_card_power_off, + .cd_deglitch = rtl8411_cd_deglitch, +}; + +/* SD Pull Control Enable: + * SD_DAT[3:0] ==> pull up + * SD_CD ==> pull up + * SD_WP ==> pull up + * SD_CMD ==> pull up + * SD_CLK ==> pull down + */ +static const u32 rtl8411_sd_pull_ctl_enable_tbl[] = { + RTSX_REG_PAIR(CARD_PULL_CTL1, 0xAA), + RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA), + RTSX_REG_PAIR(CARD_PULL_CTL3, 0xA9), + RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09), + RTSX_REG_PAIR(CARD_PULL_CTL5, 0x09), + RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04), + 0, +}; + +/* SD Pull Control Disable: + * SD_DAT[3:0] ==> pull down + * SD_CD ==> pull up + * SD_WP ==> pull down + * SD_CMD ==> pull down + * SD_CLK ==> pull down + */ +static const u32 rtl8411_sd_pull_ctl_disable_tbl[] = { + RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65), + RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), + RTSX_REG_PAIR(CARD_PULL_CTL3, 0x95), + RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09), + RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05), + RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04), + 0, +}; + +/* MS Pull Control Enable: + * MS CD ==> pull up + * others ==> pull down + */ +static const u32 rtl8411_ms_pull_ctl_enable_tbl[] = { + RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65), + RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), + RTSX_REG_PAIR(CARD_PULL_CTL3, 0x95), + RTSX_REG_PAIR(CARD_PULL_CTL4, 0x05), + RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05), + RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04), + 0, +}; + +/* MS Pull Control Disable: + * MS CD ==> pull up + * others ==> pull down + */ +static const u32 rtl8411_ms_pull_ctl_disable_tbl[] = { + RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65), + RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), + RTSX_REG_PAIR(CARD_PULL_CTL3, 0x95), + RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09), + RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05), + RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04), + 0, +}; + +void rtl8411_init_params(struct rtsx_pcr *pcr) +{ + pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104; + pcr->num_slots = 2; + pcr->ops = &rtl8411_pcr_ops; + + pcr->ic_version = rtl8411_get_ic_version(pcr); + pcr->sd_pull_ctl_enable_tbl = rtl8411_sd_pull_ctl_enable_tbl; + pcr->sd_pull_ctl_disable_tbl = rtl8411_sd_pull_ctl_disable_tbl; + pcr->ms_pull_ctl_enable_tbl = rtl8411_ms_pull_ctl_enable_tbl; + pcr->ms_pull_ctl_disable_tbl = rtl8411_ms_pull_ctl_disable_tbl; +} diff --git a/drivers/mfd/rts5209.c b/drivers/mfd/rts5209.c new file mode 100644 index 0000000..283a4f1 --- /dev/null +++ b/drivers/mfd/rts5209.c @@ -0,0 +1,223 @@ +/* Driver for Realtek PCI-Express card reader + * + * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + * + * Author: + * Wei WANG + * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China + */ + +#include +#include +#include + +#include "rtsx_pcr.h" + +static u8 rts5209_get_ic_version(struct rtsx_pcr *pcr) +{ + u8 val; + + val = rtsx_pci_readb(pcr, 0x1C); + return val & 0x0F; +} + +static void rts5209_init_vendor_cfg(struct rtsx_pcr *pcr) +{ + u32 val; + + rtsx_pci_read_config_dword(pcr, 0x724, &val); + dev_dbg(&(pcr->pci->dev), "Cfg 0x724: 0x%x\n", val); + + if (!(val & 0x80)) { + if (val & 0x08) + pcr->ms_pmos = false; + else + pcr->ms_pmos = true; + } +} + +static int rts5209_extra_init_hw(struct rtsx_pcr *pcr) +{ + rtsx_pci_init_cmd(pcr); + + /* Turn off LED */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_GPIO, 0xFF, 0x03); + /* Configure GPIO as output */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_GPIO_DIR, 0xFF, 0x03); + + return rtsx_pci_send_cmd(pcr, 100); +} + +static int rts5209_optimize_phy(struct rtsx_pcr *pcr) +{ + return rtsx_pci_write_phy_register(pcr, 0x00, 0xB966); +} + +static int rts5209_turn_on_led(struct rtsx_pcr *pcr) +{ + return rtsx_pci_write_register(pcr, CARD_GPIO, 0x01, 0x00); +} + +static int rts5209_turn_off_led(struct rtsx_pcr *pcr) +{ + return rtsx_pci_write_register(pcr, CARD_GPIO, 0x01, 0x01); +} + +static int rts5209_enable_auto_blink(struct rtsx_pcr *pcr) +{ + return rtsx_pci_write_register(pcr, CARD_AUTO_BLINK, 0xFF, 0x0D); +} + +static int rts5209_disable_auto_blink(struct rtsx_pcr *pcr) +{ + return rtsx_pci_write_register(pcr, CARD_AUTO_BLINK, 0x08, 0x00); +} + +static int rts5209_card_power_on(struct rtsx_pcr *pcr, int card) +{ + int err; + u8 pwr_mask, partial_pwr_on, pwr_on; + + pwr_mask = SD_POWER_MASK; + partial_pwr_on = SD_PARTIAL_POWER_ON; + pwr_on = SD_POWER_ON; + + if (pcr->ms_pmos && (card == RTSX_MS_CARD)) { + pwr_mask = MS_POWER_MASK; + partial_pwr_on = MS_PARTIAL_POWER_ON; + pwr_on = MS_POWER_ON; + } + + rtsx_pci_init_cmd(pcr); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, + pwr_mask, partial_pwr_on); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, + LDO3318_PWR_MASK, 0x04); + err = rtsx_pci_send_cmd(pcr, 100); + if (err < 0) + return err; + + /* To avoid too large in-rush current */ + udelay(150); + + rtsx_pci_init_cmd(pcr); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, pwr_mask, pwr_on); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, + LDO3318_PWR_MASK, 0x00); + err = rtsx_pci_send_cmd(pcr, 100); + if (err < 0) + return err; + + return 0; +} + +static int rts5209_card_power_off(struct rtsx_pcr *pcr, int card) +{ + u8 pwr_mask, pwr_off; + + pwr_mask = SD_POWER_MASK; + pwr_off = SD_POWER_OFF; + + if (pcr->ms_pmos && (card == RTSX_MS_CARD)) { + pwr_mask = MS_POWER_MASK; + pwr_off = MS_POWER_OFF; + } + + rtsx_pci_init_cmd(pcr); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, + pwr_mask | PMOS_STRG_MASK, pwr_off | PMOS_STRG_400mA); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, + LDO3318_PWR_MASK, 0X06); + return rtsx_pci_send_cmd(pcr, 100); +} + +static const struct pcr_ops rts5209_pcr_ops = { + .extra_init_hw = rts5209_extra_init_hw, + .optimize_phy = rts5209_optimize_phy, + .turn_on_led = rts5209_turn_on_led, + .turn_off_led = rts5209_turn_off_led, + .enable_auto_blink = rts5209_enable_auto_blink, + .disable_auto_blink = rts5209_disable_auto_blink, + .card_power_on = rts5209_card_power_on, + .card_power_off = rts5209_card_power_off, + .cd_deglitch = NULL, +}; + +/* SD Pull Control Enable: + * SD_DAT[3:0] ==> pull up + * SD_CD ==> pull up + * SD_WP ==> pull up + * SD_CMD ==> pull up + * SD_CLK ==> pull down + */ +static const u32 rts5209_sd_pull_ctl_enable_tbl[] = { + RTSX_REG_PAIR(CARD_PULL_CTL1, 0xAA), + RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA), + RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE9), + 0, +}; + +/* SD Pull Control Disable: + * SD_DAT[3:0] ==> pull down + * SD_CD ==> pull up + * SD_WP ==> pull down + * SD_CMD ==> pull down + * SD_CLK ==> pull down + */ +static const u32 rts5209_sd_pull_ctl_disable_tbl[] = { + RTSX_REG_PAIR(CARD_PULL_CTL1, 0x55), + RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), + RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD5), + 0, +}; + +/* MS Pull Control Enable: + * MS CD ==> pull up + * others ==> pull down + */ +static const u32 rts5209_ms_pull_ctl_enable_tbl[] = { + RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55), + RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55), + RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15), + 0, +}; + +/* MS Pull Control Disable: + * MS CD ==> pull up + * others ==> pull down + */ +static const u32 rts5209_ms_pull_ctl_disable_tbl[] = { + RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55), + RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55), + RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15), + 0, +}; + +void rts5209_init_params(struct rtsx_pcr *pcr) +{ + pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | + EXTRA_CAPS_SD_SDR104 | EXTRA_CAPS_MMC_8BIT; + pcr->num_slots = 2; + pcr->ops = &rts5209_pcr_ops; + + rts5209_init_vendor_cfg(pcr); + + pcr->ic_version = rts5209_get_ic_version(pcr); + pcr->sd_pull_ctl_enable_tbl = rts5209_sd_pull_ctl_enable_tbl; + pcr->sd_pull_ctl_disable_tbl = rts5209_sd_pull_ctl_disable_tbl; + pcr->ms_pull_ctl_enable_tbl = rts5209_ms_pull_ctl_enable_tbl; + pcr->ms_pull_ctl_disable_tbl = rts5209_ms_pull_ctl_disable_tbl; +} diff --git a/drivers/mfd/rts5229.c b/drivers/mfd/rts5229.c new file mode 100644 index 0000000..b9dbab2 --- /dev/null +++ b/drivers/mfd/rts5229.c @@ -0,0 +1,205 @@ +/* Driver for Realtek PCI-Express card reader + * + * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + * + * Author: + * Wei WANG + * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China + */ + +#include +#include +#include + +#include "rtsx_pcr.h" + +static u8 rts5229_get_ic_version(struct rtsx_pcr *pcr) +{ + u8 val; + + rtsx_pci_read_register(pcr, DUMMY_REG_RESET_0, &val); + return val & 0x0F; +} + +static int rts5229_extra_init_hw(struct rtsx_pcr *pcr) +{ + rtsx_pci_init_cmd(pcr); + + /* Configure GPIO as output */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, GPIO_CTL, 0x02, 0x02); + /* Switch LDO3318 source from DV33 to card_3v3 */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x00); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x01); + /* LED shine disabled, set initial shine cycle period */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OLT_LED_CTL, 0x0F, 0x02); + + return rtsx_pci_send_cmd(pcr, 100); +} + +static int rts5229_optimize_phy(struct rtsx_pcr *pcr) +{ + /* Optimize RX sensitivity */ + return rtsx_pci_write_phy_register(pcr, 0x00, 0xBA42); +} + +static int rts5229_turn_on_led(struct rtsx_pcr *pcr) +{ + return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x02); +} + +static int rts5229_turn_off_led(struct rtsx_pcr *pcr) +{ + return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x00); +} + +static int rts5229_enable_auto_blink(struct rtsx_pcr *pcr) +{ + return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x08); +} + +static int rts5229_disable_auto_blink(struct rtsx_pcr *pcr) +{ + return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x00); +} + +static int rts5229_card_power_on(struct rtsx_pcr *pcr, int card) +{ + int err; + + rtsx_pci_init_cmd(pcr); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, + SD_POWER_MASK, SD_PARTIAL_POWER_ON); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, + LDO3318_PWR_MASK, 0x02); + err = rtsx_pci_send_cmd(pcr, 100); + if (err < 0) + return err; + + /* To avoid too large in-rush current */ + udelay(150); + + rtsx_pci_init_cmd(pcr); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, + SD_POWER_MASK, SD_POWER_ON); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, + LDO3318_PWR_MASK, 0x06); + err = rtsx_pci_send_cmd(pcr, 100); + if (err < 0) + return err; + + return 0; +} + +static int rts5229_card_power_off(struct rtsx_pcr *pcr, int card) +{ + rtsx_pci_init_cmd(pcr); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, + SD_POWER_MASK | PMOS_STRG_MASK, + SD_POWER_OFF | PMOS_STRG_400mA); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, + LDO3318_PWR_MASK, 0X00); + return rtsx_pci_send_cmd(pcr, 100); +} + +static const struct pcr_ops rts5229_pcr_ops = { + .extra_init_hw = rts5229_extra_init_hw, + .optimize_phy = rts5229_optimize_phy, + .turn_on_led = rts5229_turn_on_led, + .turn_off_led = rts5229_turn_off_led, + .enable_auto_blink = rts5229_enable_auto_blink, + .disable_auto_blink = rts5229_disable_auto_blink, + .card_power_on = rts5229_card_power_on, + .card_power_off = rts5229_card_power_off, + .cd_deglitch = NULL, +}; + +/* SD Pull Control Enable: + * SD_DAT[3:0] ==> pull up + * SD_CD ==> pull up + * SD_WP ==> pull up + * SD_CMD ==> pull up + * SD_CLK ==> pull down + */ +static const u32 rts5229_sd_pull_ctl_enable_tbl1[] = { + RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA), + RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE9), + 0, +}; + +/* For RTS5229 version C */ +static const u32 rts5229_sd_pull_ctl_enable_tbl2[] = { + RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA), + RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD9), + 0, +}; + +/* SD Pull Control Disable: + * SD_DAT[3:0] ==> pull down + * SD_CD ==> pull up + * SD_WP ==> pull down + * SD_CMD ==> pull down + * SD_CLK ==> pull down + */ +static const u32 rts5229_sd_pull_ctl_disable_tbl1[] = { + RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), + RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD5), + 0, +}; + +/* For RTS5229 version C */ +static const u32 rts5229_sd_pull_ctl_disable_tbl2[] = { + RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), + RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE5), + 0, +}; + +/* MS Pull Control Enable: + * MS CD ==> pull up + * others ==> pull down + */ +static const u32 rts5229_ms_pull_ctl_enable_tbl[] = { + RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55), + RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15), + 0, +}; + +/* MS Pull Control Disable: + * MS CD ==> pull up + * others ==> pull down + */ +static const u32 rts5229_ms_pull_ctl_disable_tbl[] = { + RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55), + RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15), + 0, +}; + +void rts5229_init_params(struct rtsx_pcr *pcr) +{ + pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104; + pcr->num_slots = 2; + pcr->ops = &rts5229_pcr_ops; + + pcr->ic_version = rts5229_get_ic_version(pcr); + if (pcr->ic_version == IC_VER_C) { + pcr->sd_pull_ctl_enable_tbl = rts5229_sd_pull_ctl_enable_tbl2; + pcr->sd_pull_ctl_disable_tbl = rts5229_sd_pull_ctl_disable_tbl2; + } else { + pcr->sd_pull_ctl_enable_tbl = rts5229_sd_pull_ctl_enable_tbl1; + pcr->sd_pull_ctl_disable_tbl = rts5229_sd_pull_ctl_disable_tbl1; + } + pcr->ms_pull_ctl_enable_tbl = rts5229_ms_pull_ctl_enable_tbl; + pcr->ms_pull_ctl_disable_tbl = rts5229_ms_pull_ctl_disable_tbl; +} diff --git a/drivers/mfd/rtsx_pcr.c b/drivers/mfd/rtsx_pcr.c new file mode 100644 index 0000000..56d4377 --- /dev/null +++ b/drivers/mfd/rtsx_pcr.c @@ -0,0 +1,1251 @@ +/* Driver for Realtek PCI-Express card reader + * + * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + * + * Author: + * Wei WANG + * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rtsx_pcr.h" + +static bool msi_en = true; +module_param(msi_en, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(msi_en, "Enable MSI"); + +static DEFINE_IDR(rtsx_pci_idr); +static DEFINE_SPINLOCK(rtsx_pci_lock); + +static struct mfd_cell rtsx_pcr_cells[] = { + [RTSX_SD_CARD] = { + .name = DRV_NAME_RTSX_PCI_SDMMC, + }, + [RTSX_MS_CARD] = { + .name = DRV_NAME_RTSX_PCI_MS, + }, +}; + +static DEFINE_PCI_DEVICE_TABLE(rtsx_pci_ids) = { + { PCI_DEVICE(0x10EC, 0x5209), PCI_CLASS_OTHERS << 16, 0xFF0000 }, + { PCI_DEVICE(0x10EC, 0x5229), PCI_CLASS_OTHERS << 16, 0xFF0000 }, + { PCI_DEVICE(0x10EC, 0x5289), PCI_CLASS_OTHERS << 16, 0xFF0000 }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, rtsx_pci_ids); + +void rtsx_pci_start_run(struct rtsx_pcr *pcr) +{ + /* If pci device removed, don't queue idle work any more */ + if (pcr->remove_pci) + return; + + if (pcr->state != PDEV_STAT_RUN) { + pcr->state = PDEV_STAT_RUN; + if (pcr->ops->enable_auto_blink) + pcr->ops->enable_auto_blink(pcr); + } + + mod_delayed_work(system_wq, &pcr->idle_work, msecs_to_jiffies(200)); +} +EXPORT_SYMBOL_GPL(rtsx_pci_start_run); + +int rtsx_pci_write_register(struct rtsx_pcr *pcr, u16 addr, u8 mask, u8 data) +{ + int i; + u32 val = HAIMR_WRITE_START; + + val |= (u32)(addr & 0x3FFF) << 16; + val |= (u32)mask << 8; + val |= (u32)data; + + rtsx_pci_writel(pcr, RTSX_HAIMR, val); + + for (i = 0; i < MAX_RW_REG_CNT; i++) { + val = rtsx_pci_readl(pcr, RTSX_HAIMR); + if ((val & HAIMR_TRANS_END) == 0) { + if (data != (u8)val) + return -EIO; + return 0; + } + } + + return -ETIMEDOUT; +} +EXPORT_SYMBOL_GPL(rtsx_pci_write_register); + +int rtsx_pci_read_register(struct rtsx_pcr *pcr, u16 addr, u8 *data) +{ + u32 val = HAIMR_READ_START; + int i; + + val |= (u32)(addr & 0x3FFF) << 16; + rtsx_pci_writel(pcr, RTSX_HAIMR, val); + + for (i = 0; i < MAX_RW_REG_CNT; i++) { + val = rtsx_pci_readl(pcr, RTSX_HAIMR); + if ((val & HAIMR_TRANS_END) == 0) + break; + } + + if (i >= MAX_RW_REG_CNT) + return -ETIMEDOUT; + + if (data) + *data = (u8)(val & 0xFF); + + return 0; +} +EXPORT_SYMBOL_GPL(rtsx_pci_read_register); + +int rtsx_pci_write_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 val) +{ + int err, i, finished = 0; + u8 tmp; + + rtsx_pci_init_cmd(pcr); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYDATA0, 0xFF, (u8)val); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYDATA1, 0xFF, (u8)(val >> 8)); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYADDR, 0xFF, addr); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYRWCTL, 0xFF, 0x81); + + err = rtsx_pci_send_cmd(pcr, 100); + if (err < 0) + return err; + + for (i = 0; i < 100000; i++) { + err = rtsx_pci_read_register(pcr, PHYRWCTL, &tmp); + if (err < 0) + return err; + + if (!(tmp & 0x80)) { + finished = 1; + break; + } + } + + if (!finished) + return -ETIMEDOUT; + + return 0; +} +EXPORT_SYMBOL_GPL(rtsx_pci_write_phy_register); + +int rtsx_pci_read_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 *val) +{ + int err, i, finished = 0; + u16 data; + u8 *ptr, tmp; + + rtsx_pci_init_cmd(pcr); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYADDR, 0xFF, addr); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYRWCTL, 0xFF, 0x80); + + err = rtsx_pci_send_cmd(pcr, 100); + if (err < 0) + return err; + + for (i = 0; i < 100000; i++) { + err = rtsx_pci_read_register(pcr, PHYRWCTL, &tmp); + if (err < 0) + return err; + + if (!(tmp & 0x80)) { + finished = 1; + break; + } + } + + if (!finished) + return -ETIMEDOUT; + + rtsx_pci_init_cmd(pcr); + + rtsx_pci_add_cmd(pcr, READ_REG_CMD, PHYDATA0, 0, 0); + rtsx_pci_add_cmd(pcr, READ_REG_CMD, PHYDATA1, 0, 0); + + err = rtsx_pci_send_cmd(pcr, 100); + if (err < 0) + return err; + + ptr = rtsx_pci_get_cmd_data(pcr); + data = ((u16)ptr[1] << 8) | ptr[0]; + + if (val) + *val = data; + + return 0; +} +EXPORT_SYMBOL_GPL(rtsx_pci_read_phy_register); + +void rtsx_pci_stop_cmd(struct rtsx_pcr *pcr) +{ + rtsx_pci_writel(pcr, RTSX_HCBCTLR, STOP_CMD); + rtsx_pci_writel(pcr, RTSX_HDBCTLR, STOP_DMA); + + rtsx_pci_write_register(pcr, DMACTL, 0x80, 0x80); + rtsx_pci_write_register(pcr, RBCTL, 0x80, 0x80); +} +EXPORT_SYMBOL_GPL(rtsx_pci_stop_cmd); + +void rtsx_pci_add_cmd(struct rtsx_pcr *pcr, + u8 cmd_type, u16 reg_addr, u8 mask, u8 data) +{ + unsigned long flags; + u32 val = 0; + u32 *ptr = (u32 *)(pcr->host_cmds_ptr); + + val |= (u32)(cmd_type & 0x03) << 30; + val |= (u32)(reg_addr & 0x3FFF) << 16; + val |= (u32)mask << 8; + val |= (u32)data; + + spin_lock_irqsave(&pcr->lock, flags); + ptr += pcr->ci; + if (pcr->ci < (HOST_CMDS_BUF_LEN / 4)) { + put_unaligned_le32(val, ptr); + ptr++; + pcr->ci++; + } + spin_unlock_irqrestore(&pcr->lock, flags); +} +EXPORT_SYMBOL_GPL(rtsx_pci_add_cmd); + +void rtsx_pci_send_cmd_no_wait(struct rtsx_pcr *pcr) +{ + u32 val = 1 << 31; + + rtsx_pci_writel(pcr, RTSX_HCBAR, pcr->host_cmds_addr); + + val |= (u32)(pcr->ci * 4) & 0x00FFFFFF; + /* Hardware Auto Response */ + val |= 0x40000000; + rtsx_pci_writel(pcr, RTSX_HCBCTLR, val); +} +EXPORT_SYMBOL_GPL(rtsx_pci_send_cmd_no_wait); + +int rtsx_pci_send_cmd(struct rtsx_pcr *pcr, int timeout) +{ + struct completion trans_done; + u32 val = 1 << 31; + long timeleft; + unsigned long flags; + int err = 0; + + spin_lock_irqsave(&pcr->lock, flags); + + /* set up data structures for the wakeup system */ + pcr->done = &trans_done; + pcr->trans_result = TRANS_NOT_READY; + init_completion(&trans_done); + + rtsx_pci_writel(pcr, RTSX_HCBAR, pcr->host_cmds_addr); + + val |= (u32)(pcr->ci * 4) & 0x00FFFFFF; + /* Hardware Auto Response */ + val |= 0x40000000; + rtsx_pci_writel(pcr, RTSX_HCBCTLR, val); + + spin_unlock_irqrestore(&pcr->lock, flags); + + /* Wait for TRANS_OK_INT */ + timeleft = wait_for_completion_interruptible_timeout( + &trans_done, msecs_to_jiffies(timeout)); + if (timeleft <= 0) { + dev_dbg(&(pcr->pci->dev), "Timeout (%s %d)\n", + __func__, __LINE__); + err = -ETIMEDOUT; + goto finish_send_cmd; + } + + spin_lock_irqsave(&pcr->lock, flags); + if (pcr->trans_result == TRANS_RESULT_FAIL) + err = -EINVAL; + else if (pcr->trans_result == TRANS_RESULT_OK) + err = 0; + else if (pcr->trans_result == TRANS_NO_DEVICE) + err = -ENODEV; + spin_unlock_irqrestore(&pcr->lock, flags); + +finish_send_cmd: + spin_lock_irqsave(&pcr->lock, flags); + pcr->done = NULL; + spin_unlock_irqrestore(&pcr->lock, flags); + + if ((err < 0) && (err != -ENODEV)) + rtsx_pci_stop_cmd(pcr); + + if (pcr->finish_me) + complete(pcr->finish_me); + + return err; +} +EXPORT_SYMBOL_GPL(rtsx_pci_send_cmd); + +static void rtsx_pci_add_sg_tbl(struct rtsx_pcr *pcr, + dma_addr_t addr, unsigned int len, int end) +{ + u64 *ptr = (u64 *)(pcr->host_sg_tbl_ptr) + pcr->sgi; + u64 val; + u8 option = SG_VALID | SG_TRANS_DATA; + + dev_dbg(&(pcr->pci->dev), "DMA addr: 0x%x, Len: 0x%x\n", + (unsigned int)addr, len); + + if (end) + option |= SG_END; + val = ((u64)addr << 32) | ((u64)len << 12) | option; + + put_unaligned_le64(val, ptr); + ptr++; + pcr->sgi++; +} + +int rtsx_pci_transfer_data(struct rtsx_pcr *pcr, struct scatterlist *sglist, + int num_sg, bool read, int timeout) +{ + struct completion trans_done; + u8 dir; + int err = 0, i, count; + long timeleft; + unsigned long flags; + struct scatterlist *sg; + enum dma_data_direction dma_dir; + u32 val; + dma_addr_t addr; + unsigned int len; + + dev_dbg(&(pcr->pci->dev), "--> %s: num_sg = %d\n", __func__, num_sg); + + /* don't transfer data during abort processing */ + if (pcr->remove_pci) + return -EINVAL; + + if ((sglist == NULL) || (num_sg <= 0)) + return -EINVAL; + + if (read) { + dir = DEVICE_TO_HOST; + dma_dir = DMA_FROM_DEVICE; + } else { + dir = HOST_TO_DEVICE; + dma_dir = DMA_TO_DEVICE; + } + + count = dma_map_sg(&(pcr->pci->dev), sglist, num_sg, dma_dir); + if (count < 1) { + dev_err(&(pcr->pci->dev), "scatterlist map failed\n"); + return -EINVAL; + } + dev_dbg(&(pcr->pci->dev), "DMA mapping count: %d\n", count); + + val = ((u32)(dir & 0x01) << 29) | TRIG_DMA | ADMA_MODE; + pcr->sgi = 0; + for_each_sg(sglist, sg, count, i) { + addr = sg_dma_address(sg); + len = sg_dma_len(sg); + rtsx_pci_add_sg_tbl(pcr, addr, len, i == count - 1); + } + + spin_lock_irqsave(&pcr->lock, flags); + + pcr->done = &trans_done; + pcr->trans_result = TRANS_NOT_READY; + init_completion(&trans_done); + rtsx_pci_writel(pcr, RTSX_HDBAR, pcr->host_sg_tbl_addr); + rtsx_pci_writel(pcr, RTSX_HDBCTLR, val); + + spin_unlock_irqrestore(&pcr->lock, flags); + + timeleft = wait_for_completion_interruptible_timeout( + &trans_done, msecs_to_jiffies(timeout)); + if (timeleft <= 0) { + dev_dbg(&(pcr->pci->dev), "Timeout (%s %d)\n", + __func__, __LINE__); + err = -ETIMEDOUT; + goto out; + } + + spin_lock_irqsave(&pcr->lock, flags); + + if (pcr->trans_result == TRANS_RESULT_FAIL) + err = -EINVAL; + else if (pcr->trans_result == TRANS_NO_DEVICE) + err = -ENODEV; + + spin_unlock_irqrestore(&pcr->lock, flags); + +out: + spin_lock_irqsave(&pcr->lock, flags); + pcr->done = NULL; + spin_unlock_irqrestore(&pcr->lock, flags); + + dma_unmap_sg(&(pcr->pci->dev), sglist, num_sg, dma_dir); + + if ((err < 0) && (err != -ENODEV)) + rtsx_pci_stop_cmd(pcr); + + if (pcr->finish_me) + complete(pcr->finish_me); + + return err; +} +EXPORT_SYMBOL_GPL(rtsx_pci_transfer_data); + +int rtsx_pci_read_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len) +{ + int err; + int i, j; + u16 reg; + u8 *ptr; + + if (buf_len > 512) + buf_len = 512; + + ptr = buf; + reg = PPBUF_BASE2; + for (i = 0; i < buf_len / 256; i++) { + rtsx_pci_init_cmd(pcr); + + for (j = 0; j < 256; j++) + rtsx_pci_add_cmd(pcr, READ_REG_CMD, reg++, 0, 0); + + err = rtsx_pci_send_cmd(pcr, 250); + if (err < 0) + return err; + + memcpy(ptr, rtsx_pci_get_cmd_data(pcr), 256); + ptr += 256; + } + + if (buf_len % 256) { + rtsx_pci_init_cmd(pcr); + + for (j = 0; j < buf_len % 256; j++) + rtsx_pci_add_cmd(pcr, READ_REG_CMD, reg++, 0, 0); + + err = rtsx_pci_send_cmd(pcr, 250); + if (err < 0) + return err; + } + + memcpy(ptr, rtsx_pci_get_cmd_data(pcr), buf_len % 256); + + return 0; +} +EXPORT_SYMBOL_GPL(rtsx_pci_read_ppbuf); + +int rtsx_pci_write_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len) +{ + int err; + int i, j; + u16 reg; + u8 *ptr; + + if (buf_len > 512) + buf_len = 512; + + ptr = buf; + reg = PPBUF_BASE2; + for (i = 0; i < buf_len / 256; i++) { + rtsx_pci_init_cmd(pcr); + + for (j = 0; j < 256; j++) { + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, + reg++, 0xFF, *ptr); + ptr++; + } + + err = rtsx_pci_send_cmd(pcr, 250); + if (err < 0) + return err; + } + + if (buf_len % 256) { + rtsx_pci_init_cmd(pcr); + + for (j = 0; j < buf_len % 256; j++) { + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, + reg++, 0xFF, *ptr); + ptr++; + } + + err = rtsx_pci_send_cmd(pcr, 250); + if (err < 0) + return err; + } + + return 0; +} +EXPORT_SYMBOL_GPL(rtsx_pci_write_ppbuf); + +static int rtsx_pci_set_pull_ctl(struct rtsx_pcr *pcr, const u32 *tbl) +{ + int err; + + rtsx_pci_init_cmd(pcr); + + while (*tbl & 0xFFFF0000) { + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, + (u16)(*tbl >> 16), 0xFF, (u8)(*tbl)); + tbl++; + } + + err = rtsx_pci_send_cmd(pcr, 100); + if (err < 0) + return err; + + return 0; +} + +int rtsx_pci_card_pull_ctl_enable(struct rtsx_pcr *pcr, int card) +{ + const u32 *tbl; + + if (card == RTSX_SD_CARD) + tbl = pcr->sd_pull_ctl_enable_tbl; + else if (card == RTSX_MS_CARD) + tbl = pcr->ms_pull_ctl_enable_tbl; + else + return -EINVAL; + + return rtsx_pci_set_pull_ctl(pcr, tbl); +} +EXPORT_SYMBOL_GPL(rtsx_pci_card_pull_ctl_enable); + +int rtsx_pci_card_pull_ctl_disable(struct rtsx_pcr *pcr, int card) +{ + const u32 *tbl; + + if (card == RTSX_SD_CARD) + tbl = pcr->sd_pull_ctl_disable_tbl; + else if (card == RTSX_MS_CARD) + tbl = pcr->ms_pull_ctl_disable_tbl; + else + return -EINVAL; + + + return rtsx_pci_set_pull_ctl(pcr, tbl); +} +EXPORT_SYMBOL_GPL(rtsx_pci_card_pull_ctl_disable); + +static void rtsx_pci_enable_bus_int(struct rtsx_pcr *pcr) +{ + pcr->bier = TRANS_OK_INT_EN | TRANS_FAIL_INT_EN | SD_INT_EN; + + if (pcr->num_slots > 1) + pcr->bier |= MS_INT_EN; + + /* Enable Bus Interrupt */ + rtsx_pci_writel(pcr, RTSX_BIER, pcr->bier); + + dev_dbg(&(pcr->pci->dev), "RTSX_BIER: 0x%08x\n", pcr->bier); +} + +static inline u8 double_ssc_depth(u8 depth) +{ + return ((depth > 1) ? (depth - 1) : depth); +} + +static u8 revise_ssc_depth(u8 ssc_depth, u8 div) +{ + if (div > CLK_DIV_1) { + if (ssc_depth > (div - 1)) + ssc_depth -= (div - 1); + else + ssc_depth = SSC_DEPTH_4M; + } + + return ssc_depth; +} + +int rtsx_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock, + u8 ssc_depth, bool initial_mode, bool double_clk, bool vpclk) +{ + int err, clk; + u8 N, min_N, max_N, clk_divider; + u8 mcu_cnt, div, max_div; + u8 depth[] = { + [RTSX_SSC_DEPTH_4M] = SSC_DEPTH_4M, + [RTSX_SSC_DEPTH_2M] = SSC_DEPTH_2M, + [RTSX_SSC_DEPTH_1M] = SSC_DEPTH_1M, + [RTSX_SSC_DEPTH_500K] = SSC_DEPTH_500K, + [RTSX_SSC_DEPTH_250K] = SSC_DEPTH_250K, + }; + + if (initial_mode) { + /* We use 250k(around) here, in initial stage */ + clk_divider = SD_CLK_DIVIDE_128; + card_clock = 30000000; + } else { + clk_divider = SD_CLK_DIVIDE_0; + } + err = rtsx_pci_write_register(pcr, SD_CFG1, + SD_CLK_DIVIDE_MASK, clk_divider); + if (err < 0) + return err; + + card_clock /= 1000000; + dev_dbg(&(pcr->pci->dev), "Switch card clock to %dMHz\n", card_clock); + + min_N = 80; + max_N = 208; + max_div = CLK_DIV_8; + + clk = card_clock; + if (!initial_mode && double_clk) + clk = card_clock * 2; + dev_dbg(&(pcr->pci->dev), + "Internal SSC clock: %dMHz (cur_clock = %d)\n", + clk, pcr->cur_clock); + + if (clk == pcr->cur_clock) + return 0; + + N = (u8)(clk - 2); + if ((clk <= 2) || (N > max_N)) + return -EINVAL; + + mcu_cnt = (u8)(125/clk + 3); + if (mcu_cnt > 15) + mcu_cnt = 15; + + /* Make sure that the SSC clock div_n is equal or greater than min_N */ + div = CLK_DIV_1; + while ((N < min_N) && (div < max_div)) { + N = (N + 2) * 2 - 2; + div++; + } + dev_dbg(&(pcr->pci->dev), "N = %d, div = %d\n", N, div); + + ssc_depth = depth[ssc_depth]; + if (double_clk) + ssc_depth = double_ssc_depth(ssc_depth); + + ssc_depth = revise_ssc_depth(ssc_depth, div); + dev_dbg(&(pcr->pci->dev), "ssc_depth = %d\n", ssc_depth); + + rtsx_pci_init_cmd(pcr); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, + CLK_LOW_FREQ, CLK_LOW_FREQ); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_DIV, + 0xFF, (div << 4) | mcu_cnt); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, 0); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL2, + SSC_DEPTH_MASK, ssc_depth); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_DIV_N_0, 0xFF, N); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, SSC_RSTB); + if (vpclk) { + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL, + PHASE_NOT_RESET, 0); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL, + PHASE_NOT_RESET, PHASE_NOT_RESET); + } + + err = rtsx_pci_send_cmd(pcr, 2000); + if (err < 0) + return err; + + /* Wait SSC clock stable */ + udelay(10); + err = rtsx_pci_write_register(pcr, CLK_CTL, CLK_LOW_FREQ, 0); + if (err < 0) + return err; + + pcr->cur_clock = clk; + return 0; +} +EXPORT_SYMBOL_GPL(rtsx_pci_switch_clock); + +int rtsx_pci_card_power_on(struct rtsx_pcr *pcr, int card) +{ + if (pcr->ops->card_power_on) + return pcr->ops->card_power_on(pcr, card); + + return 0; +} +EXPORT_SYMBOL_GPL(rtsx_pci_card_power_on); + +int rtsx_pci_card_power_off(struct rtsx_pcr *pcr, int card) +{ + if (pcr->ops->card_power_off) + return pcr->ops->card_power_off(pcr, card); + + return 0; +} +EXPORT_SYMBOL_GPL(rtsx_pci_card_power_off); + +unsigned int rtsx_pci_card_exist(struct rtsx_pcr *pcr) +{ + unsigned int val; + + val = rtsx_pci_readl(pcr, RTSX_BIPR); + if (pcr->ops->cd_deglitch) + val = pcr->ops->cd_deglitch(pcr); + + return val; +} +EXPORT_SYMBOL_GPL(rtsx_pci_card_exist); + +void rtsx_pci_complete_unfinished_transfer(struct rtsx_pcr *pcr) +{ + struct completion finish; + + pcr->finish_me = &finish; + init_completion(&finish); + + if (pcr->done) + complete(pcr->done); + + if (!pcr->remove_pci) + rtsx_pci_stop_cmd(pcr); + + wait_for_completion_interruptible_timeout(&finish, + msecs_to_jiffies(2)); + pcr->finish_me = NULL; +} +EXPORT_SYMBOL_GPL(rtsx_pci_complete_unfinished_transfer); + +static void rtsx_pci_card_detect(struct work_struct *work) +{ + struct delayed_work *dwork; + struct rtsx_pcr *pcr; + unsigned long flags; + unsigned int card_detect = 0; + u32 irq_status; + + dwork = to_delayed_work(work); + pcr = container_of(dwork, struct rtsx_pcr, carddet_work); + + dev_dbg(&(pcr->pci->dev), "--> %s\n", __func__); + + spin_lock_irqsave(&pcr->lock, flags); + + irq_status = rtsx_pci_readl(pcr, RTSX_BIPR); + dev_dbg(&(pcr->pci->dev), "irq_status: 0x%08x\n", irq_status); + + if (pcr->card_inserted || pcr->card_removed) { + dev_dbg(&(pcr->pci->dev), + "card_inserted: 0x%x, card_removed: 0x%x\n", + pcr->card_inserted, pcr->card_removed); + + if (pcr->ops->cd_deglitch) + pcr->card_inserted = pcr->ops->cd_deglitch(pcr); + + card_detect = pcr->card_inserted | pcr->card_removed; + pcr->card_inserted = 0; + pcr->card_removed = 0; + } + + spin_unlock_irqrestore(&pcr->lock, flags); + + if (card_detect & SD_EXIST) + pcr->slots[RTSX_SD_CARD].card_event( + pcr->slots[RTSX_SD_CARD].p_dev); + if (card_detect & MS_EXIST) + pcr->slots[RTSX_MS_CARD].card_event( + pcr->slots[RTSX_MS_CARD].p_dev); +} + +static irqreturn_t rtsx_pci_isr(int irq, void *dev_id) +{ + struct rtsx_pcr *pcr = dev_id; + u32 int_reg; + + if (!pcr) + return IRQ_NONE; + + spin_lock(&pcr->lock); + + int_reg = rtsx_pci_readl(pcr, RTSX_BIPR); + /* Clear interrupt flag */ + rtsx_pci_writel(pcr, RTSX_BIPR, int_reg); + if ((int_reg & pcr->bier) == 0) { + spin_unlock(&pcr->lock); + return IRQ_NONE; + } + if (int_reg == 0xFFFFFFFF) { + spin_unlock(&pcr->lock); + return IRQ_HANDLED; + } + + int_reg &= (pcr->bier | 0x7FFFFF); + + if (int_reg & SD_INT) { + if (int_reg & SD_EXIST) { + pcr->card_inserted |= SD_EXIST; + } else { + pcr->card_removed |= SD_EXIST; + pcr->card_inserted &= ~SD_EXIST; + } + } + + if (int_reg & MS_INT) { + if (int_reg & MS_EXIST) { + pcr->card_inserted |= MS_EXIST; + } else { + pcr->card_removed |= MS_EXIST; + pcr->card_inserted &= ~MS_EXIST; + } + } + + if (pcr->card_inserted || pcr->card_removed) + schedule_delayed_work(&pcr->carddet_work, + msecs_to_jiffies(200)); + + if (int_reg & (NEED_COMPLETE_INT | DELINK_INT)) { + if (int_reg & (TRANS_FAIL_INT | DELINK_INT)) { + pcr->trans_result = TRANS_RESULT_FAIL; + if (pcr->done) + complete(pcr->done); + } else if (int_reg & TRANS_OK_INT) { + pcr->trans_result = TRANS_RESULT_OK; + if (pcr->done) + complete(pcr->done); + } + } + + spin_unlock(&pcr->lock); + return IRQ_HANDLED; +} + +static int rtsx_pci_acquire_irq(struct rtsx_pcr *pcr) +{ + dev_info(&(pcr->pci->dev), "%s: pcr->msi_en = %d, pci->irq = %d\n", + __func__, pcr->msi_en, pcr->pci->irq); + + if (request_irq(pcr->pci->irq, rtsx_pci_isr, + pcr->msi_en ? 0 : IRQF_SHARED, + DRV_NAME_RTSX_PCI, pcr)) { + dev_err(&(pcr->pci->dev), + "rtsx_sdmmc: unable to grab IRQ %d, disabling device\n", + pcr->pci->irq); + return -1; + } + + pcr->irq = pcr->pci->irq; + pci_intx(pcr->pci, !pcr->msi_en); + + return 0; +} + +static void rtsx_pci_idle_work(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr, idle_work); + + dev_dbg(&(pcr->pci->dev), "--> %s\n", __func__); + + mutex_lock(&pcr->pcr_mutex); + + pcr->state = PDEV_STAT_IDLE; + + if (pcr->ops->disable_auto_blink) + pcr->ops->disable_auto_blink(pcr); + if (pcr->ops->turn_off_led) + pcr->ops->turn_off_led(pcr); + + mutex_unlock(&pcr->pcr_mutex); +} + +static int rtsx_pci_init_hw(struct rtsx_pcr *pcr) +{ + int err; + + rtsx_pci_writel(pcr, RTSX_HCBAR, pcr->host_cmds_addr); + + rtsx_pci_enable_bus_int(pcr); + + /* Power on SSC */ + err = rtsx_pci_write_register(pcr, FPDCTL, SSC_POWER_DOWN, 0); + if (err < 0) + return err; + + /* Wait SSC power stable */ + udelay(200); + + if (pcr->ops->optimize_phy) { + err = pcr->ops->optimize_phy(pcr); + if (err < 0) + return err; + } + + rtsx_pci_init_cmd(pcr); + + /* Set mcu_cnt to 7 to ensure data can be sampled properly */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_DIV, 0x07, 0x07); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, HOST_SLEEP_STATE, 0x03, 0x00); + /* Disable card clock */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_EN, 0x1E, 0); + /* Reset ASPM state to default value */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, ASPM_FORCE_CTL, 0x3F, 0); + /* Reset delink mode */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CHANGE_LINK_STATE, 0x0A, 0); + /* Card driving select */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DRIVE_SEL, + 0x07, DRIVER_TYPE_D); + /* Enable SSC Clock */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL1, + 0xFF, SSC_8X_EN | SSC_SEL_4M); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL2, 0xFF, 0x12); + /* Disable cd_pwr_save */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CHANGE_LINK_STATE, 0x16, 0x10); + /* Clear Link Ready Interrupt */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, IRQSTAT0, + LINK_RDY_INT, LINK_RDY_INT); + /* Enlarge the estimation window of PERST# glitch + * to reduce the chance of invalid card interrupt + */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PERST_GLITCH_WIDTH, 0xFF, 0x80); + /* Update RC oscillator to 400k + * bit[0] F_HIGH: for RC oscillator, Rst_value is 1'b1 + * 1: 2M 0: 400k + */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, RCCTL, 0x01, 0x00); + /* Set interrupt write clear + * bit 1: U_elbi_if_rd_clr_en + * 1: Enable ELBI interrupt[31:22] & [7:0] flag read clear + * 0: ELBI interrupt flag[31:22] & [7:0] only can be write clear + */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, NFTS_TX_CTRL, 0x02, 0); + /* Force CLKREQ# PIN to drive 0 to request clock */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0x08, 0x08); + + err = rtsx_pci_send_cmd(pcr, 100); + if (err < 0) + return err; + + /* Enable clk_request_n to enable clock power management */ + rtsx_pci_write_config_byte(pcr, 0x81, 1); + /* Enter L1 when host tx idle */ + rtsx_pci_write_config_byte(pcr, 0x70F, 0x5B); + + if (pcr->ops->extra_init_hw) { + err = pcr->ops->extra_init_hw(pcr); + if (err < 0) + return err; + } + + return 0; +} + +static int rtsx_pci_init_chip(struct rtsx_pcr *pcr) +{ + int err; + + spin_lock_init(&pcr->lock); + mutex_init(&pcr->pcr_mutex); + + switch (PCI_PID(pcr)) { + default: + case 0x5209: + rts5209_init_params(pcr); + break; + + case 0x5229: + rts5229_init_params(pcr); + break; + + case 0x5289: + rtl8411_init_params(pcr); + break; + } + + dev_dbg(&(pcr->pci->dev), "PID: 0x%04x, IC version: 0x%02x\n", + PCI_PID(pcr), pcr->ic_version); + + pcr->slots = kcalloc(pcr->num_slots, sizeof(struct rtsx_slot), + GFP_KERNEL); + if (!pcr->slots) + return -ENOMEM; + + pcr->state = PDEV_STAT_IDLE; + err = rtsx_pci_init_hw(pcr); + if (err < 0) { + kfree(pcr->slots); + return err; + } + + return 0; +} + +static int __devinit rtsx_pci_probe(struct pci_dev *pcidev, + const struct pci_device_id *id) +{ + struct rtsx_pcr *pcr; + struct pcr_handle *handle; + u32 base, len; + int ret, i; + + dev_dbg(&(pcidev->dev), + ": Realtek PCI-E Card Reader found at %s [%04x:%04x] (rev %x)\n", + pci_name(pcidev), (int)pcidev->vendor, (int)pcidev->device, + (int)pcidev->revision); + + ret = pci_enable_device(pcidev); + if (ret) + return ret; + + ret = pci_request_regions(pcidev, DRV_NAME_RTSX_PCI); + if (ret) + goto disable; + + pcr = kzalloc(sizeof(*pcr), GFP_KERNEL); + if (!pcr) { + ret = -ENOMEM; + goto release_pci; + } + + handle = kzalloc(sizeof(*handle), GFP_KERNEL); + if (!handle) { + ret = -ENOMEM; + goto free_pcr; + } + handle->pcr = pcr; + + if (!idr_pre_get(&rtsx_pci_idr, GFP_KERNEL)) { + ret = -ENOMEM; + goto free_handle; + } + + spin_lock(&rtsx_pci_lock); + ret = idr_get_new(&rtsx_pci_idr, pcr, &pcr->id); + spin_unlock(&rtsx_pci_lock); + if (ret) + goto free_handle; + + pcr->pci = pcidev; + dev_set_drvdata(&pcidev->dev, handle); + + len = pci_resource_len(pcidev, 0); + base = pci_resource_start(pcidev, 0); + pcr->remap_addr = ioremap_nocache(base, len); + if (!pcr->remap_addr) { + ret = -ENOMEM; + goto free_host; + } + + pcr->rtsx_resv_buf = dma_alloc_coherent(&(pcidev->dev), + RTSX_RESV_BUF_LEN, &(pcr->rtsx_resv_buf_addr), + GFP_KERNEL); + if (pcr->rtsx_resv_buf == NULL) { + ret = -ENXIO; + goto unmap; + } + pcr->host_cmds_ptr = pcr->rtsx_resv_buf; + pcr->host_cmds_addr = pcr->rtsx_resv_buf_addr; + pcr->host_sg_tbl_ptr = pcr->rtsx_resv_buf + HOST_CMDS_BUF_LEN; + pcr->host_sg_tbl_addr = pcr->rtsx_resv_buf_addr + HOST_CMDS_BUF_LEN; + + pcr->card_inserted = 0; + pcr->card_removed = 0; + INIT_DELAYED_WORK(&pcr->carddet_work, rtsx_pci_card_detect); + INIT_DELAYED_WORK(&pcr->idle_work, rtsx_pci_idle_work); + + pcr->msi_en = msi_en; + if (pcr->msi_en) { + ret = pci_enable_msi(pcidev); + if (ret < 0) + pcr->msi_en = false; + } + + ret = rtsx_pci_acquire_irq(pcr); + if (ret < 0) + goto free_dma; + + pci_set_master(pcidev); + synchronize_irq(pcr->irq); + + ret = rtsx_pci_init_chip(pcr); + if (ret < 0) + goto disable_irq; + + for (i = 0; i < ARRAY_SIZE(rtsx_pcr_cells); i++) { + rtsx_pcr_cells[i].platform_data = handle; + rtsx_pcr_cells[i].pdata_size = sizeof(*handle); + } + ret = mfd_add_devices(&pcidev->dev, pcr->id, rtsx_pcr_cells, + ARRAY_SIZE(rtsx_pcr_cells), NULL, 0, NULL); + if (ret < 0) + goto disable_irq; + + schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200)); + + return 0; + +disable_irq: + free_irq(pcr->irq, (void *)pcr); +free_dma: + dma_free_coherent(&(pcr->pci->dev), RTSX_RESV_BUF_LEN, + pcr->rtsx_resv_buf, pcr->rtsx_resv_buf_addr); +unmap: + iounmap(pcr->remap_addr); +free_host: + dev_set_drvdata(&pcidev->dev, NULL); +free_handle: + kfree(handle); +free_pcr: + kfree(pcr); +release_pci: + pci_release_regions(pcidev); +disable: + pci_disable_device(pcidev); + + return ret; +} + +static void __devexit rtsx_pci_remove(struct pci_dev *pcidev) +{ + struct pcr_handle *handle = pci_get_drvdata(pcidev); + struct rtsx_pcr *pcr = handle->pcr; + + pcr->remove_pci = true; + + cancel_delayed_work(&pcr->carddet_work); + cancel_delayed_work(&pcr->idle_work); + + mfd_remove_devices(&pcidev->dev); + + dma_free_coherent(&(pcr->pci->dev), RTSX_RESV_BUF_LEN, + pcr->rtsx_resv_buf, pcr->rtsx_resv_buf_addr); + free_irq(pcr->irq, (void *)pcr); + if (pcr->msi_en) + pci_disable_msi(pcr->pci); + iounmap(pcr->remap_addr); + + dev_set_drvdata(&pcidev->dev, NULL); + pci_release_regions(pcidev); + pci_disable_device(pcidev); + + spin_lock(&rtsx_pci_lock); + idr_remove(&rtsx_pci_idr, pcr->id); + spin_unlock(&rtsx_pci_lock); + + kfree(pcr->slots); + kfree(pcr); + kfree(handle); + + dev_dbg(&(pcidev->dev), + ": Realtek PCI-E Card Reader at %s [%04x:%04x] has been removed\n", + pci_name(pcidev), (int)pcidev->vendor, (int)pcidev->device); +} + +#ifdef CONFIG_PM + +static int rtsx_pci_suspend(struct pci_dev *pcidev, pm_message_t state) +{ + struct pcr_handle *handle; + struct rtsx_pcr *pcr; + int ret = 0; + + dev_dbg(&(pcidev->dev), "--> %s\n", __func__); + + handle = pci_get_drvdata(pcidev); + pcr = handle->pcr; + + cancel_delayed_work(&pcr->carddet_work); + cancel_delayed_work(&pcr->idle_work); + + mutex_lock(&pcr->pcr_mutex); + + if (pcr->ops->turn_off_led) + pcr->ops->turn_off_led(pcr); + + rtsx_pci_writel(pcr, RTSX_BIER, 0); + pcr->bier = 0; + + rtsx_pci_write_register(pcr, PETXCFG, 0x08, 0x08); + rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, 0x02); + + pci_save_state(pcidev); + pci_enable_wake(pcidev, pci_choose_state(pcidev, state), 0); + pci_disable_device(pcidev); + pci_set_power_state(pcidev, pci_choose_state(pcidev, state)); + + mutex_unlock(&pcr->pcr_mutex); + return ret; +} + +static int rtsx_pci_resume(struct pci_dev *pcidev) +{ + struct pcr_handle *handle; + struct rtsx_pcr *pcr; + int ret = 0; + + dev_dbg(&(pcidev->dev), "--> %s\n", __func__); + + handle = pci_get_drvdata(pcidev); + pcr = handle->pcr; + + mutex_lock(&pcr->pcr_mutex); + + pci_set_power_state(pcidev, PCI_D0); + pci_restore_state(pcidev); + ret = pci_enable_device(pcidev); + if (ret) + goto out; + pci_set_master(pcidev); + + ret = rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, 0x00); + if (ret) + goto out; + + ret = rtsx_pci_init_hw(pcr); + if (ret) + goto out; + + schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200)); + +out: + mutex_unlock(&pcr->pcr_mutex); + return ret; +} + +#else /* CONFIG_PM */ + +#define rtsx_pci_suspend NULL +#define rtsx_pci_resume NULL + +#endif /* CONFIG_PM */ + +static struct pci_driver rtsx_pci_driver = { + .name = DRV_NAME_RTSX_PCI, + .id_table = rtsx_pci_ids, + .probe = rtsx_pci_probe, + .remove = __devexit_p(rtsx_pci_remove), + .suspend = rtsx_pci_suspend, + .resume = rtsx_pci_resume, +}; +module_pci_driver(rtsx_pci_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Wei WANG "); +MODULE_DESCRIPTION("Realtek PCI-E Card Reader Driver"); diff --git a/drivers/mfd/rtsx_pcr.h b/drivers/mfd/rtsx_pcr.h new file mode 100644 index 0000000..12462c1 --- /dev/null +++ b/drivers/mfd/rtsx_pcr.h @@ -0,0 +1,32 @@ +/* Driver for Realtek PCI-Express card reader + * + * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + * + * Author: + * Wei WANG + * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China + */ + +#ifndef __RTSX_PCR_H +#define __RTSX_PCR_H + +#include + +void rts5209_init_params(struct rtsx_pcr *pcr); +void rts5229_init_params(struct rtsx_pcr *pcr); +void rtl8411_init_params(struct rtsx_pcr *pcr); + +#endif diff --git a/include/linux/mfd/rtsx_common.h b/include/linux/mfd/rtsx_common.h new file mode 100644 index 0000000..a8d393e --- /dev/null +++ b/include/linux/mfd/rtsx_common.h @@ -0,0 +1,48 @@ +/* Driver for Realtek driver-based card reader + * + * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + * + * Author: + * Wei WANG + * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China + */ + +#ifndef __RTSX_COMMON_H +#define __RTSX_COMMON_H + +#define DRV_NAME_RTSX_PCI "rtsx_pci" +#define DRV_NAME_RTSX_PCI_SDMMC "rtsx_pci_sdmmc" +#define DRV_NAME_RTSX_PCI_MS "rtsx_pci_ms" + +#define RTSX_REG_PAIR(addr, val) (((u32)(addr) << 16) | (u8)(val)) + +#define RTSX_SSC_DEPTH_4M 0x01 +#define RTSX_SSC_DEPTH_2M 0x02 +#define RTSX_SSC_DEPTH_1M 0x03 +#define RTSX_SSC_DEPTH_500K 0x04 +#define RTSX_SSC_DEPTH_250K 0x05 + +#define RTSX_SD_CARD 0 +#define RTSX_MS_CARD 1 + +struct platform_device; + +struct rtsx_slot { + struct platform_device *p_dev; + void (*card_event)(struct platform_device *p_dev); +}; + +#endif diff --git a/include/linux/mfd/rtsx_pci.h b/include/linux/mfd/rtsx_pci.h new file mode 100644 index 0000000..060b721 --- /dev/null +++ b/include/linux/mfd/rtsx_pci.h @@ -0,0 +1,794 @@ +/* Driver for Realtek PCI-Express card reader + * + * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + * + * Author: + * Wei WANG + * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China + */ + +#ifndef __RTSX_PCI_H +#define __RTSX_PCI_H + +#include +#include + +#include "rtsx_common.h" + +#define MAX_RW_REG_CNT 1024 + +/* PCI Operation Register Address */ +#define RTSX_HCBAR 0x00 +#define RTSX_HCBCTLR 0x04 +#define RTSX_HDBAR 0x08 +#define RTSX_HDBCTLR 0x0C +#define RTSX_HAIMR 0x10 +#define RTSX_BIPR 0x14 +#define RTSX_BIER 0x18 + +/* Host command buffer control register */ +#define STOP_CMD (0x01 << 28) + +/* Host data buffer control register */ +#define SDMA_MODE 0x00 +#define ADMA_MODE (0x02 << 26) +#define STOP_DMA (0x01 << 28) +#define TRIG_DMA (0x01 << 31) + +/* Host access internal memory register */ +#define HAIMR_TRANS_START (0x01 << 31) +#define HAIMR_READ 0x00 +#define HAIMR_WRITE (0x01 << 30) +#define HAIMR_READ_START (HAIMR_TRANS_START | HAIMR_READ) +#define HAIMR_WRITE_START (HAIMR_TRANS_START | HAIMR_WRITE) +#define HAIMR_TRANS_END (HAIMR_TRANS_START) + +/* Bus interrupt pending register */ +#define CMD_DONE_INT (1 << 31) +#define DATA_DONE_INT (1 << 30) +#define TRANS_OK_INT (1 << 29) +#define TRANS_FAIL_INT (1 << 28) +#define XD_INT (1 << 27) +#define MS_INT (1 << 26) +#define SD_INT (1 << 25) +#define GPIO0_INT (1 << 24) +#define OC_INT (1 << 23) +#define SD_WRITE_PROTECT (1 << 19) +#define XD_EXIST (1 << 18) +#define MS_EXIST (1 << 17) +#define SD_EXIST (1 << 16) +#define DELINK_INT GPIO0_INT +#define MS_OC_INT (1 << 23) +#define SD_OC_INT (1 << 22) + +#define CARD_INT (XD_INT | MS_INT | SD_INT) +#define NEED_COMPLETE_INT (DATA_DONE_INT | TRANS_OK_INT | TRANS_FAIL_INT) +#define RTSX_INT (CMD_DONE_INT | NEED_COMPLETE_INT | \ + CARD_INT | GPIO0_INT | OC_INT) + +#define CARD_EXIST (XD_EXIST | MS_EXIST | SD_EXIST) + +/* Bus interrupt enable register */ +#define CMD_DONE_INT_EN (1 << 31) +#define DATA_DONE_INT_EN (1 << 30) +#define TRANS_OK_INT_EN (1 << 29) +#define TRANS_FAIL_INT_EN (1 << 28) +#define XD_INT_EN (1 << 27) +#define MS_INT_EN (1 << 26) +#define SD_INT_EN (1 << 25) +#define GPIO0_INT_EN (1 << 24) +#define OC_INT_EN (1 << 23) +#define DELINK_INT_EN GPIO0_INT_EN +#define MS_OC_INT_EN (1 << 23) +#define SD_OC_INT_EN (1 << 22) + +#define READ_REG_CMD 0 +#define WRITE_REG_CMD 1 +#define CHECK_REG_CMD 2 + +/* + * macros for easy use + */ +#define rtsx_pci_writel(pcr, reg, value) \ + iowrite32(value, (pcr)->remap_addr + reg) +#define rtsx_pci_readl(pcr, reg) \ + ioread32((pcr)->remap_addr + reg) +#define rtsx_pci_writew(pcr, reg, value) \ + iowrite16(value, (pcr)->remap_addr + reg) +#define rtsx_pci_readw(pcr, reg) \ + ioread16((pcr)->remap_addr + reg) +#define rtsx_pci_writeb(pcr, reg, value) \ + iowrite8(value, (pcr)->remap_addr + reg) +#define rtsx_pci_readb(pcr, reg) \ + ioread8((pcr)->remap_addr + reg) + +#define rtsx_pci_read_config_byte(pcr, where, val) \ + pci_read_config_byte((pcr)->pci, where, val) + +#define rtsx_pci_write_config_byte(pcr, where, val) \ + pci_write_config_byte((pcr)->pci, where, val) + +#define rtsx_pci_read_config_dword(pcr, where, val) \ + pci_read_config_dword((pcr)->pci, where, val) + +#define rtsx_pci_write_config_dword(pcr, where, val) \ + pci_write_config_dword((pcr)->pci, where, val) + +#define STATE_TRANS_NONE 0 +#define STATE_TRANS_CMD 1 +#define STATE_TRANS_BUF 2 +#define STATE_TRANS_SG 3 + +#define TRANS_NOT_READY 0 +#define TRANS_RESULT_OK 1 +#define TRANS_RESULT_FAIL 2 +#define TRANS_NO_DEVICE 3 + +#define RTSX_RESV_BUF_LEN 4096 +#define HOST_CMDS_BUF_LEN 1024 +#define HOST_SG_TBL_BUF_LEN (RTSX_RESV_BUF_LEN - HOST_CMDS_BUF_LEN) +#define HOST_SG_TBL_ITEMS (HOST_SG_TBL_BUF_LEN / 8) +#define MAX_SG_ITEM_LEN 0x80000 + +#define HOST_TO_DEVICE 0 +#define DEVICE_TO_HOST 1 + +#define MAX_PHASE 31 +#define RX_TUNING_CNT 3 + +/* SG descriptor */ +#define SG_INT 0x04 +#define SG_END 0x02 +#define SG_VALID 0x01 + +#define SG_NO_OP 0x00 +#define SG_TRANS_DATA (0x02 << 4) +#define SG_LINK_DESC (0x03 << 4) + +/* SD bank voltage */ +#define SD_IO_3V3 0 +#define SD_IO_1V8 1 + + +/* Card Clock Enable Register */ +#define SD_CLK_EN 0x04 +#define MS_CLK_EN 0x08 + +/* Card Select Register */ +#define SD_MOD_SEL 2 +#define MS_MOD_SEL 3 + +/* Card Output Enable Register */ +#define SD_OUTPUT_EN 0x04 +#define MS_OUTPUT_EN 0x08 + +/* CARD_SHARE_MODE */ +#define CARD_SHARE_MASK 0x0F +#define CARD_SHARE_MULTI_LUN 0x00 +#define CARD_SHARE_NORMAL 0x00 +#define CARD_SHARE_48_SD 0x04 +#define CARD_SHARE_48_MS 0x08 +/* CARD_SHARE_MODE for barossa */ +#define CARD_SHARE_BAROSSA_SD 0x01 +#define CARD_SHARE_BAROSSA_MS 0x02 + +/* SD30_DRIVE_SEL */ +#define DRIVER_TYPE_A 0x05 +#define DRIVER_TYPE_B 0x03 +#define DRIVER_TYPE_C 0x02 +#define DRIVER_TYPE_D 0x01 + +/* FPDCTL */ +#define SSC_POWER_DOWN 0x01 +#define SD_OC_POWER_DOWN 0x02 +#define ALL_POWER_DOWN 0x07 +#define OC_POWER_DOWN 0x06 + +/* CLK_CTL */ +#define CHANGE_CLK 0x01 + +/* LDO_CTL */ +#define BPP_LDO_POWB 0x03 +#define BPP_LDO_ON 0x00 +#define BPP_LDO_SUSPEND 0x02 +#define BPP_LDO_OFF 0x03 + +/* CD_PAD_CTL */ +#define CD_DISABLE_MASK 0x07 +#define MS_CD_DISABLE 0x04 +#define SD_CD_DISABLE 0x02 +#define XD_CD_DISABLE 0x01 +#define CD_DISABLE 0x07 +#define CD_ENABLE 0x00 +#define MS_CD_EN_ONLY 0x03 +#define SD_CD_EN_ONLY 0x05 +#define XD_CD_EN_ONLY 0x06 +#define FORCE_CD_LOW_MASK 0x38 +#define FORCE_CD_XD_LOW 0x08 +#define FORCE_CD_SD_LOW 0x10 +#define FORCE_CD_MS_LOW 0x20 +#define CD_AUTO_DISABLE 0x40 + +/* SD_STAT1 */ +#define SD_CRC7_ERR 0x80 +#define SD_CRC16_ERR 0x40 +#define SD_CRC_WRITE_ERR 0x20 +#define SD_CRC_WRITE_ERR_MASK 0x1C +#define GET_CRC_TIME_OUT 0x02 +#define SD_TUNING_COMPARE_ERR 0x01 + +/* SD_STAT2 */ +#define SD_RSP_80CLK_TIMEOUT 0x01 + +/* SD_BUS_STAT */ +#define SD_CLK_TOGGLE_EN 0x80 +#define SD_CLK_FORCE_STOP 0x40 +#define SD_DAT3_STATUS 0x10 +#define SD_DAT2_STATUS 0x08 +#define SD_DAT1_STATUS 0x04 +#define SD_DAT0_STATUS 0x02 +#define SD_CMD_STATUS 0x01 + +/* SD_PAD_CTL */ +#define SD_IO_USING_1V8 0x80 +#define SD_IO_USING_3V3 0x7F +#define TYPE_A_DRIVING 0x00 +#define TYPE_B_DRIVING 0x01 +#define TYPE_C_DRIVING 0x02 +#define TYPE_D_DRIVING 0x03 + +/* SD_SAMPLE_POINT_CTL */ +#define DDR_FIX_RX_DAT 0x00 +#define DDR_VAR_RX_DAT 0x80 +#define DDR_FIX_RX_DAT_EDGE 0x00 +#define DDR_FIX_RX_DAT_14_DELAY 0x40 +#define DDR_FIX_RX_CMD 0x00 +#define DDR_VAR_RX_CMD 0x20 +#define DDR_FIX_RX_CMD_POS_EDGE 0x00 +#define DDR_FIX_RX_CMD_14_DELAY 0x10 +#define SD20_RX_POS_EDGE 0x00 +#define SD20_RX_14_DELAY 0x08 +#define SD20_RX_SEL_MASK 0x08 + +/* SD_PUSH_POINT_CTL */ +#define DDR_FIX_TX_CMD_DAT 0x00 +#define DDR_VAR_TX_CMD_DAT 0x80 +#define DDR_FIX_TX_DAT_14_TSU 0x00 +#define DDR_FIX_TX_DAT_12_TSU 0x40 +#define DDR_FIX_TX_CMD_NEG_EDGE 0x00 +#define DDR_FIX_TX_CMD_14_AHEAD 0x20 +#define SD20_TX_NEG_EDGE 0x00 +#define SD20_TX_14_AHEAD 0x10 +#define SD20_TX_SEL_MASK 0x10 +#define DDR_VAR_SDCLK_POL_SWAP 0x01 + +/* SD_TRANSFER */ +#define SD_TRANSFER_START 0x80 +#define SD_TRANSFER_END 0x40 +#define SD_STAT_IDLE 0x20 +#define SD_TRANSFER_ERR 0x10 +/* SD Transfer Mode definition */ +#define SD_TM_NORMAL_WRITE 0x00 +#define SD_TM_AUTO_WRITE_3 0x01 +#define SD_TM_AUTO_WRITE_4 0x02 +#define SD_TM_AUTO_READ_3 0x05 +#define SD_TM_AUTO_READ_4 0x06 +#define SD_TM_CMD_RSP 0x08 +#define SD_TM_AUTO_WRITE_1 0x09 +#define SD_TM_AUTO_WRITE_2 0x0A +#define SD_TM_NORMAL_READ 0x0C +#define SD_TM_AUTO_READ_1 0x0D +#define SD_TM_AUTO_READ_2 0x0E +#define SD_TM_AUTO_TUNING 0x0F + +/* SD_VPTX_CTL / SD_VPRX_CTL */ +#define PHASE_CHANGE 0x80 +#define PHASE_NOT_RESET 0x40 + +/* SD_DCMPS_TX_CTL / SD_DCMPS_RX_CTL */ +#define DCMPS_CHANGE 0x80 +#define DCMPS_CHANGE_DONE 0x40 +#define DCMPS_ERROR 0x20 +#define DCMPS_CURRENT_PHASE 0x1F + +/* SD Configure 1 Register */ +#define SD_CLK_DIVIDE_0 0x00 +#define SD_CLK_DIVIDE_256 0xC0 +#define SD_CLK_DIVIDE_128 0x80 +#define SD_BUS_WIDTH_1BIT 0x00 +#define SD_BUS_WIDTH_4BIT 0x01 +#define SD_BUS_WIDTH_8BIT 0x02 +#define SD_ASYNC_FIFO_NOT_RST 0x10 +#define SD_20_MODE 0x00 +#define SD_DDR_MODE 0x04 +#define SD_30_MODE 0x08 + +#define SD_CLK_DIVIDE_MASK 0xC0 + +/* SD_CMD_STATE */ +#define SD_CMD_IDLE 0x80 + +/* SD_DATA_STATE */ +#define SD_DATA_IDLE 0x80 + +/* DCM_DRP_CTL */ +#define DCM_RESET 0x08 +#define DCM_LOCKED 0x04 +#define DCM_208M 0x00 +#define DCM_TX 0x01 +#define DCM_RX 0x02 + +/* DCM_DRP_TRIG */ +#define DRP_START 0x80 +#define DRP_DONE 0x40 + +/* DCM_DRP_CFG */ +#define DRP_WRITE 0x80 +#define DRP_READ 0x00 +#define DCM_WRITE_ADDRESS_50 0x50 +#define DCM_WRITE_ADDRESS_51 0x51 +#define DCM_READ_ADDRESS_00 0x00 +#define DCM_READ_ADDRESS_51 0x51 + +/* IRQSTAT0 */ +#define DMA_DONE_INT 0x80 +#define SUSPEND_INT 0x40 +#define LINK_RDY_INT 0x20 +#define LINK_DOWN_INT 0x10 + +/* DMACTL */ +#define DMA_RST 0x80 +#define DMA_BUSY 0x04 +#define DMA_DIR_TO_CARD 0x00 +#define DMA_DIR_FROM_CARD 0x02 +#define DMA_EN 0x01 +#define DMA_128 (0 << 4) +#define DMA_256 (1 << 4) +#define DMA_512 (2 << 4) +#define DMA_1024 (3 << 4) +#define DMA_PACK_SIZE_MASK 0x30 + +/* SSC_CTL1 */ +#define SSC_RSTB 0x80 +#define SSC_8X_EN 0x40 +#define SSC_FIX_FRAC 0x20 +#define SSC_SEL_1M 0x00 +#define SSC_SEL_2M 0x08 +#define SSC_SEL_4M 0x10 +#define SSC_SEL_8M 0x18 + +/* SSC_CTL2 */ +#define SSC_DEPTH_MASK 0x07 +#define SSC_DEPTH_DISALBE 0x00 +#define SSC_DEPTH_4M 0x01 +#define SSC_DEPTH_2M 0x02 +#define SSC_DEPTH_1M 0x03 +#define SSC_DEPTH_500K 0x04 +#define SSC_DEPTH_250K 0x05 + +/* System Clock Control Register */ +#define CLK_LOW_FREQ 0x01 + +/* System Clock Divider Register */ +#define CLK_DIV_1 0x01 +#define CLK_DIV_2 0x02 +#define CLK_DIV_4 0x03 +#define CLK_DIV_8 0x04 + +/* MS_CFG */ +#define SAMPLE_TIME_RISING 0x00 +#define SAMPLE_TIME_FALLING 0x80 +#define PUSH_TIME_DEFAULT 0x00 +#define PUSH_TIME_ODD 0x40 +#define NO_EXTEND_TOGGLE 0x00 +#define EXTEND_TOGGLE_CHK 0x20 +#define MS_BUS_WIDTH_1 0x00 +#define MS_BUS_WIDTH_4 0x10 +#define MS_BUS_WIDTH_8 0x18 +#define MS_2K_SECTOR_MODE 0x04 +#define MS_512_SECTOR_MODE 0x00 +#define MS_TOGGLE_TIMEOUT_EN 0x00 +#define MS_TOGGLE_TIMEOUT_DISEN 0x01 +#define MS_NO_CHECK_INT 0x02 + +/* MS_TRANS_CFG */ +#define WAIT_INT 0x80 +#define NO_WAIT_INT 0x00 +#define NO_AUTO_READ_INT_REG 0x00 +#define AUTO_READ_INT_REG 0x40 +#define MS_CRC16_ERR 0x20 +#define MS_RDY_TIMEOUT 0x10 +#define MS_INT_CMDNK 0x08 +#define MS_INT_BREQ 0x04 +#define MS_INT_ERR 0x02 +#define MS_INT_CED 0x01 + +/* MS_TRANSFER */ +#define MS_TRANSFER_START 0x80 +#define MS_TRANSFER_END 0x40 +#define MS_TRANSFER_ERR 0x20 +#define MS_BS_STATE 0x10 +#define MS_TM_READ_BYTES 0x00 +#define MS_TM_NORMAL_READ 0x01 +#define MS_TM_WRITE_BYTES 0x04 +#define MS_TM_NORMAL_WRITE 0x05 +#define MS_TM_AUTO_READ 0x08 +#define MS_TM_AUTO_WRITE 0x0C + +/* SD Configure 2 Register */ +#define SD_CALCULATE_CRC7 0x00 +#define SD_NO_CALCULATE_CRC7 0x80 +#define SD_CHECK_CRC16 0x00 +#define SD_NO_CHECK_CRC16 0x40 +#define SD_NO_CHECK_WAIT_CRC_TO 0x20 +#define SD_WAIT_BUSY_END 0x08 +#define SD_NO_WAIT_BUSY_END 0x00 +#define SD_CHECK_CRC7 0x00 +#define SD_NO_CHECK_CRC7 0x04 +#define SD_RSP_LEN_0 0x00 +#define SD_RSP_LEN_6 0x01 +#define SD_RSP_LEN_17 0x02 +/* SD/MMC Response Type Definition */ +#define SD_RSP_TYPE_R0 0x04 +#define SD_RSP_TYPE_R1 0x01 +#define SD_RSP_TYPE_R1b 0x09 +#define SD_RSP_TYPE_R2 0x02 +#define SD_RSP_TYPE_R3 0x05 +#define SD_RSP_TYPE_R4 0x05 +#define SD_RSP_TYPE_R5 0x01 +#define SD_RSP_TYPE_R6 0x01 +#define SD_RSP_TYPE_R7 0x01 + +/* SD_CONFIURE3 */ +#define SD_RSP_80CLK_TIMEOUT_EN 0x01 + +/* Card Transfer Reset Register */ +#define SPI_STOP 0x01 +#define XD_STOP 0x02 +#define SD_STOP 0x04 +#define MS_STOP 0x08 +#define SPI_CLR_ERR 0x10 +#define XD_CLR_ERR 0x20 +#define SD_CLR_ERR 0x40 +#define MS_CLR_ERR 0x80 + +/* Card Data Source Register */ +#define PINGPONG_BUFFER 0x01 +#define RING_BUFFER 0x00 + +/* Card Power Control Register */ +#define PMOS_STRG_MASK 0x10 +#define PMOS_STRG_800mA 0x10 +#define PMOS_STRG_400mA 0x00 +#define SD_POWER_OFF 0x03 +#define SD_PARTIAL_POWER_ON 0x01 +#define SD_POWER_ON 0x00 +#define SD_POWER_MASK 0x03 +#define MS_POWER_OFF 0x0C +#define MS_PARTIAL_POWER_ON 0x04 +#define MS_POWER_ON 0x00 +#define MS_POWER_MASK 0x0C +#define BPP_POWER_OFF 0x0F +#define BPP_POWER_5_PERCENT_ON 0x0E +#define BPP_POWER_10_PERCENT_ON 0x0C +#define BPP_POWER_15_PERCENT_ON 0x08 +#define BPP_POWER_ON 0x00 +#define BPP_POWER_MASK 0x0F + +/* PWR_GATE_CTRL */ +#define PWR_GATE_EN 0x01 +#define LDO3318_PWR_MASK 0x06 +#define LDO_ON 0x00 +#define LDO_SUSPEND 0x04 +#define LDO_OFF 0x06 + +/* CARD_CLK_SOURCE */ +#define CRC_FIX_CLK (0x00 << 0) +#define CRC_VAR_CLK0 (0x01 << 0) +#define CRC_VAR_CLK1 (0x02 << 0) +#define SD30_FIX_CLK (0x00 << 2) +#define SD30_VAR_CLK0 (0x01 << 2) +#define SD30_VAR_CLK1 (0x02 << 2) +#define SAMPLE_FIX_CLK (0x00 << 4) +#define SAMPLE_VAR_CLK0 (0x01 << 4) +#define SAMPLE_VAR_CLK1 (0x02 << 4) + +#define MS_CFG 0xFD40 +#define MS_TPC 0xFD41 +#define MS_TRANS_CFG 0xFD42 +#define MS_TRANSFER 0xFD43 +#define MS_INT_REG 0xFD44 +#define MS_BYTE_CNT 0xFD45 +#define MS_SECTOR_CNT_L 0xFD46 +#define MS_SECTOR_CNT_H 0xFD47 +#define MS_DBUS_H 0xFD48 + +#define SD_CFG1 0xFDA0 +#define SD_CFG2 0xFDA1 +#define SD_CFG3 0xFDA2 +#define SD_STAT1 0xFDA3 +#define SD_STAT2 0xFDA4 +#define SD_BUS_STAT 0xFDA5 +#define SD_PAD_CTL 0xFDA6 +#define SD_SAMPLE_POINT_CTL 0xFDA7 +#define SD_PUSH_POINT_CTL 0xFDA8 +#define SD_CMD0 0xFDA9 +#define SD_CMD1 0xFDAA +#define SD_CMD2 0xFDAB +#define SD_CMD3 0xFDAC +#define SD_CMD4 0xFDAD +#define SD_CMD5 0xFDAE +#define SD_BYTE_CNT_L 0xFDAF +#define SD_BYTE_CNT_H 0xFDB0 +#define SD_BLOCK_CNT_L 0xFDB1 +#define SD_BLOCK_CNT_H 0xFDB2 +#define SD_TRANSFER 0xFDB3 +#define SD_CMD_STATE 0xFDB5 +#define SD_DATA_STATE 0xFDB6 + +#define SRCTL 0xFC13 + +#define DCM_DRP_CTL 0xFC23 +#define DCM_DRP_TRIG 0xFC24 +#define DCM_DRP_CFG 0xFC25 +#define DCM_DRP_WR_DATA_L 0xFC26 +#define DCM_DRP_WR_DATA_H 0xFC27 +#define DCM_DRP_RD_DATA_L 0xFC28 +#define DCM_DRP_RD_DATA_H 0xFC29 +#define SD_VPCLK0_CTL 0xFC2A +#define SD_VPCLK1_CTL 0xFC2B +#define SD_DCMPS0_CTL 0xFC2C +#define SD_DCMPS1_CTL 0xFC2D +#define SD_VPTX_CTL SD_VPCLK0_CTL +#define SD_VPRX_CTL SD_VPCLK1_CTL +#define SD_DCMPS_TX_CTL SD_DCMPS0_CTL +#define SD_DCMPS_RX_CTL SD_DCMPS1_CTL +#define CARD_CLK_SOURCE 0xFC2E + +#define CARD_PWR_CTL 0xFD50 +#define CARD_CLK_SWITCH 0xFD51 +#define CARD_SHARE_MODE 0xFD52 +#define CARD_DRIVE_SEL 0xFD53 +#define CARD_STOP 0xFD54 +#define CARD_OE 0xFD55 +#define CARD_AUTO_BLINK 0xFD56 +#define CARD_GPIO_DIR 0xFD57 +#define CARD_GPIO 0xFD58 +#define CARD_DATA_SOURCE 0xFD5B +#define CARD_SELECT 0xFD5C +#define SD30_DRIVE_SEL 0xFD5E +#define CARD_CLK_EN 0xFD69 +#define SDIO_CTRL 0xFD6B +#define CD_PAD_CTL 0xFD73 + +#define FPDCTL 0xFC00 +#define PDINFO 0xFC01 + +#define CLK_CTL 0xFC02 +#define CLK_DIV 0xFC03 +#define CLK_SEL 0xFC04 + +#define SSC_DIV_N_0 0xFC0F +#define SSC_DIV_N_1 0xFC10 +#define SSC_CTL1 0xFC11 +#define SSC_CTL2 0xFC12 + +#define RCCTL 0xFC14 + +#define FPGA_PULL_CTL 0xFC1D +#define OLT_LED_CTL 0xFC1E +#define GPIO_CTL 0xFC1F + +#define LDO_CTL 0xFC1E +#define SYS_VER 0xFC32 + +#define CARD_PULL_CTL1 0xFD60 +#define CARD_PULL_CTL2 0xFD61 +#define CARD_PULL_CTL3 0xFD62 +#define CARD_PULL_CTL4 0xFD63 +#define CARD_PULL_CTL5 0xFD64 +#define CARD_PULL_CTL6 0xFD65 + +/* PCI Express Related Registers */ +#define IRQEN0 0xFE20 +#define IRQSTAT0 0xFE21 +#define IRQEN1 0xFE22 +#define IRQSTAT1 0xFE23 +#define TLPRIEN 0xFE24 +#define TLPRISTAT 0xFE25 +#define TLPTIEN 0xFE26 +#define TLPTISTAT 0xFE27 +#define DMATC0 0xFE28 +#define DMATC1 0xFE29 +#define DMATC2 0xFE2A +#define DMATC3 0xFE2B +#define DMACTL 0xFE2C +#define BCTL 0xFE2D +#define RBBC0 0xFE2E +#define RBBC1 0xFE2F +#define RBDAT 0xFE30 +#define RBCTL 0xFE34 +#define CFGADDR0 0xFE35 +#define CFGADDR1 0xFE36 +#define CFGDATA0 0xFE37 +#define CFGDATA1 0xFE38 +#define CFGDATA2 0xFE39 +#define CFGDATA3 0xFE3A +#define CFGRWCTL 0xFE3B +#define PHYRWCTL 0xFE3C +#define PHYDATA0 0xFE3D +#define PHYDATA1 0xFE3E +#define PHYADDR 0xFE3F +#define MSGRXDATA0 0xFE40 +#define MSGRXDATA1 0xFE41 +#define MSGRXDATA2 0xFE42 +#define MSGRXDATA3 0xFE43 +#define MSGTXDATA0 0xFE44 +#define MSGTXDATA1 0xFE45 +#define MSGTXDATA2 0xFE46 +#define MSGTXDATA3 0xFE47 +#define MSGTXCTL 0xFE48 +#define PETXCFG 0xFE49 + +#define CDRESUMECTL 0xFE52 +#define WAKE_SEL_CTL 0xFE54 +#define PME_FORCE_CTL 0xFE56 +#define ASPM_FORCE_CTL 0xFE57 +#define PM_CLK_FORCE_CTL 0xFE58 +#define PERST_GLITCH_WIDTH 0xFE5C +#define CHANGE_LINK_STATE 0xFE5B +#define RESET_LOAD_REG 0xFE5E +#define EFUSE_CONTENT 0xFE5F +#define HOST_SLEEP_STATE 0xFE60 +#define SDIO_CFG 0xFE70 + +#define NFTS_TX_CTRL 0xFE72 + +#define PWR_GATE_CTRL 0xFE75 +#define PWD_SUSPEND_EN 0xFE76 +#define LDO_PWR_SEL 0xFE78 + +#define DUMMY_REG_RESET_0 0xFE90 + +/* Memory mapping */ +#define SRAM_BASE 0xE600 +#define RBUF_BASE 0xF400 +#define PPBUF_BASE1 0xF800 +#define PPBUF_BASE2 0xFA00 +#define IMAGE_FLAG_ADDR0 0xCE80 +#define IMAGE_FLAG_ADDR1 0xCE81 + +#define rtsx_pci_init_cmd(pcr) ((pcr)->ci = 0) + +struct rtsx_pcr; + +struct pcr_handle { + struct rtsx_pcr *pcr; +}; + +struct pcr_ops { + int (*extra_init_hw)(struct rtsx_pcr *pcr); + int (*optimize_phy)(struct rtsx_pcr *pcr); + int (*turn_on_led)(struct rtsx_pcr *pcr); + int (*turn_off_led)(struct rtsx_pcr *pcr); + int (*enable_auto_blink)(struct rtsx_pcr *pcr); + int (*disable_auto_blink)(struct rtsx_pcr *pcr); + int (*card_power_on)(struct rtsx_pcr *pcr, int card); + int (*card_power_off)(struct rtsx_pcr *pcr, int card); + unsigned int (*cd_deglitch)(struct rtsx_pcr *pcr); +}; + +enum PDEV_STAT {PDEV_STAT_IDLE, PDEV_STAT_RUN}; + +struct rtsx_pcr { + struct pci_dev *pci; + unsigned int id; + + /* pci resources */ + unsigned long addr; + void __iomem *remap_addr; + int irq; + + /* host reserved buffer */ + void *rtsx_resv_buf; + dma_addr_t rtsx_resv_buf_addr; + + void *host_cmds_ptr; + dma_addr_t host_cmds_addr; + int ci; + + void *host_sg_tbl_ptr; + dma_addr_t host_sg_tbl_addr; + int sgi; + + u32 bier; + char trans_result; + + unsigned int card_inserted; + unsigned int card_removed; + + struct delayed_work carddet_work; + struct delayed_work idle_work; + + spinlock_t lock; + struct mutex pcr_mutex; + struct completion *done; + struct completion *finish_me; + + unsigned int cur_clock; + bool ms_pmos; + bool remove_pci; + bool msi_en; + +#define EXTRA_CAPS_SD_SDR50 (1 << 0) +#define EXTRA_CAPS_SD_SDR104 (1 << 1) +#define EXTRA_CAPS_SD_DDR50 (1 << 2) +#define EXTRA_CAPS_MMC_HSDDR (1 << 3) +#define EXTRA_CAPS_MMC_HS200 (1 << 4) +#define EXTRA_CAPS_MMC_8BIT (1 << 5) + u32 extra_caps; + +#define IC_VER_A 0 +#define IC_VER_B 1 +#define IC_VER_C 2 +#define IC_VER_D 3 + u8 ic_version; + + const u32 *sd_pull_ctl_enable_tbl; + const u32 *sd_pull_ctl_disable_tbl; + const u32 *ms_pull_ctl_enable_tbl; + const u32 *ms_pull_ctl_disable_tbl; + + const struct pcr_ops *ops; + enum PDEV_STAT state; + + int num_slots; + struct rtsx_slot *slots; +}; + +#define CHK_PCI_PID(pcr, pid) ((pcr)->pci->device == (pid)) +#define PCI_VID(pcr) ((pcr)->pci->vendor) +#define PCI_PID(pcr) ((pcr)->pci->device) + +void rtsx_pci_start_run(struct rtsx_pcr *pcr); +int rtsx_pci_write_register(struct rtsx_pcr *pcr, u16 addr, u8 mask, u8 data); +int rtsx_pci_read_register(struct rtsx_pcr *pcr, u16 addr, u8 *data); +int rtsx_pci_write_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 val); +int rtsx_pci_read_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 *val); +void rtsx_pci_stop_cmd(struct rtsx_pcr *pcr); +void rtsx_pci_add_cmd(struct rtsx_pcr *pcr, + u8 cmd_type, u16 reg_addr, u8 mask, u8 data); +void rtsx_pci_send_cmd_no_wait(struct rtsx_pcr *pcr); +int rtsx_pci_send_cmd(struct rtsx_pcr *pcr, int timeout); +int rtsx_pci_transfer_data(struct rtsx_pcr *pcr, struct scatterlist *sglist, + int num_sg, bool read, int timeout); +int rtsx_pci_read_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len); +int rtsx_pci_write_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len); +int rtsx_pci_card_pull_ctl_enable(struct rtsx_pcr *pcr, int card); +int rtsx_pci_card_pull_ctl_disable(struct rtsx_pcr *pcr, int card); +int rtsx_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock, + u8 ssc_depth, bool initial_mode, bool double_clk, bool vpclk); +int rtsx_pci_card_power_on(struct rtsx_pcr *pcr, int card); +int rtsx_pci_card_power_off(struct rtsx_pcr *pcr, int card); +unsigned int rtsx_pci_card_exist(struct rtsx_pcr *pcr); +void rtsx_pci_complete_unfinished_transfer(struct rtsx_pcr *pcr); + +static inline u8 *rtsx_pci_get_cmd_data(struct rtsx_pcr *pcr) +{ + return (u8 *)(pcr->host_cmds_ptr); +} + +#endif -- cgit v0.10.2 From 2c94b6452cc6de582584f21066cc5e36d9530c59 Mon Sep 17 00:00:00 2001 From: Wei WANG Date: Fri, 9 Nov 2012 20:53:34 +0800 Subject: drivers/mmc: Add realtek pcie sdmmc host driver Realtek PCI-E SD/MMC card host driver is used to access SD/MMC card, with the help of Realtek PCI-E card reader MFD driver. Signed-off-by: Wei WANG Reviewed-by: Arnd Bergmann Tested-by: Borislav Petkov Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 9bf10e7..dfa6d56 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -621,3 +621,10 @@ config MMC_USHC Note: These controllers only support SDIO cards and do not support MMC or SD memory cards. + +config MMC_REALTEK_PCI + tristate "Realtek PCI-E SD/MMC Card Interface Driver" + depends on MFD_RTSX_PCI + help + Say Y here to include driver code to support SD/MMC card interface + of Realtek PCI-E card reader diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 17ad0a7..8aa592d 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -46,6 +46,8 @@ obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o obj-$(CONFIG_MMC_VUB300) += vub300.o obj-$(CONFIG_MMC_USHC) += ushc.o +obj-$(CONFIG_MMC_REALTEK_PCI) += rtsx_pci_sdmmc.o + obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-pltfm.o obj-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX) += sdhci-esdhc-imx.o diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c new file mode 100644 index 0000000..12eff6f --- /dev/null +++ b/drivers/mmc/host/rtsx_pci_sdmmc.c @@ -0,0 +1,1348 @@ +/* Realtek PCI-Express SD/MMC Card Interface driver + * + * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + * + * Author: + * Wei WANG + * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* SD Tuning Data Structure + * Record continuous timing phase path + */ +struct timing_phase_path { + int start; + int end; + int mid; + int len; +}; + +struct realtek_pci_sdmmc { + struct platform_device *pdev; + struct rtsx_pcr *pcr; + struct mmc_host *mmc; + struct mmc_request *mrq; + + struct mutex host_mutex; + + u8 ssc_depth; + unsigned int clock; + bool vpclk; + bool double_clk; + bool eject; + bool initial_mode; + bool ddr_mode; +}; + +static inline struct device *sdmmc_dev(struct realtek_pci_sdmmc *host) +{ + return &(host->pdev->dev); +} + +static inline void sd_clear_error(struct realtek_pci_sdmmc *host) +{ + rtsx_pci_write_register(host->pcr, CARD_STOP, + SD_STOP | SD_CLR_ERR, SD_STOP | SD_CLR_ERR); +} + +#ifdef DEBUG +static void sd_print_debug_regs(struct realtek_pci_sdmmc *host) +{ + struct rtsx_pcr *pcr = host->pcr; + u16 i; + u8 *ptr; + + /* Print SD host internal registers */ + rtsx_pci_init_cmd(pcr); + for (i = 0xFDA0; i <= 0xFDAE; i++) + rtsx_pci_add_cmd(pcr, READ_REG_CMD, i, 0, 0); + for (i = 0xFD52; i <= 0xFD69; i++) + rtsx_pci_add_cmd(pcr, READ_REG_CMD, i, 0, 0); + rtsx_pci_send_cmd(pcr, 100); + + ptr = rtsx_pci_get_cmd_data(pcr); + for (i = 0xFDA0; i <= 0xFDAE; i++) + dev_dbg(sdmmc_dev(host), "0x%04X: 0x%02x\n", i, *(ptr++)); + for (i = 0xFD52; i <= 0xFD69; i++) + dev_dbg(sdmmc_dev(host), "0x%04X: 0x%02x\n", i, *(ptr++)); +} +#else +#define sd_print_debug_regs(host) +#endif /* DEBUG */ + +static int sd_read_data(struct realtek_pci_sdmmc *host, u8 *cmd, u16 byte_cnt, + u8 *buf, int buf_len, int timeout) +{ + struct rtsx_pcr *pcr = host->pcr; + int err, i; + u8 trans_mode; + + dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD%d\n", __func__, cmd[0] - 0x40); + + if (!buf) + buf_len = 0; + + if ((cmd[0] & 0x3F) == MMC_SEND_TUNING_BLOCK) + trans_mode = SD_TM_AUTO_TUNING; + else + trans_mode = SD_TM_NORMAL_READ; + + rtsx_pci_init_cmd(pcr); + + for (i = 0; i < 5; i++) + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD0 + i, 0xFF, cmd[i]); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, (u8)byte_cnt); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_H, + 0xFF, (u8)(byte_cnt >> 8)); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, 1); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, 0); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG2, 0xFF, + SD_CALCULATE_CRC7 | SD_CHECK_CRC16 | + SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_6); + if (trans_mode != SD_TM_AUTO_TUNING) + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, + CARD_DATA_SOURCE, 0x01, PINGPONG_BUFFER); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_TRANSFER, + 0xFF, trans_mode | SD_TRANSFER_START); + rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, SD_TRANSFER, + SD_TRANSFER_END, SD_TRANSFER_END); + + err = rtsx_pci_send_cmd(pcr, timeout); + if (err < 0) { + sd_print_debug_regs(host); + dev_dbg(sdmmc_dev(host), + "rtsx_pci_send_cmd fail (err = %d)\n", err); + return err; + } + + if (buf && buf_len) { + err = rtsx_pci_read_ppbuf(pcr, buf, buf_len); + if (err < 0) { + dev_dbg(sdmmc_dev(host), + "rtsx_pci_read_ppbuf fail (err = %d)\n", err); + return err; + } + } + + return 0; +} + +static int sd_write_data(struct realtek_pci_sdmmc *host, u8 *cmd, u16 byte_cnt, + u8 *buf, int buf_len, int timeout) +{ + struct rtsx_pcr *pcr = host->pcr; + int err, i; + u8 trans_mode; + + if (!buf) + buf_len = 0; + + if (buf && buf_len) { + err = rtsx_pci_write_ppbuf(pcr, buf, buf_len); + if (err < 0) { + dev_dbg(sdmmc_dev(host), + "rtsx_pci_write_ppbuf fail (err = %d)\n", err); + return err; + } + } + + trans_mode = cmd ? SD_TM_AUTO_WRITE_2 : SD_TM_AUTO_WRITE_3; + rtsx_pci_init_cmd(pcr); + + if (cmd) { + dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d\n", __func__, + cmd[0] - 0x40); + + for (i = 0; i < 5; i++) + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, + SD_CMD0 + i, 0xFF, cmd[i]); + } + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, (u8)byte_cnt); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_H, + 0xFF, (u8)(byte_cnt >> 8)); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, 1); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, 0); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG2, 0xFF, + SD_CALCULATE_CRC7 | SD_CHECK_CRC16 | + SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_6); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_TRANSFER, 0xFF, + trans_mode | SD_TRANSFER_START); + rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, SD_TRANSFER, + SD_TRANSFER_END, SD_TRANSFER_END); + + err = rtsx_pci_send_cmd(pcr, timeout); + if (err < 0) { + sd_print_debug_regs(host); + dev_dbg(sdmmc_dev(host), + "rtsx_pci_send_cmd fail (err = %d)\n", err); + return err; + } + + return 0; +} + +static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host, + struct mmc_command *cmd) +{ + struct rtsx_pcr *pcr = host->pcr; + u8 cmd_idx = (u8)cmd->opcode; + u32 arg = cmd->arg; + int err = 0; + int timeout = 100; + int i; + u8 *ptr; + int stat_idx = 0; + u8 rsp_type; + int rsp_len = 5; + + dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d, arg = 0x%08x\n", + __func__, cmd_idx, arg); + + /* Response type: + * R0 + * R1, R5, R6, R7 + * R1b + * R2 + * R3, R4 + */ + switch (mmc_resp_type(cmd)) { + case MMC_RSP_NONE: + rsp_type = SD_RSP_TYPE_R0; + rsp_len = 0; + break; + case MMC_RSP_R1: + rsp_type = SD_RSP_TYPE_R1; + break; + case MMC_RSP_R1B: + rsp_type = SD_RSP_TYPE_R1b; + break; + case MMC_RSP_R2: + rsp_type = SD_RSP_TYPE_R2; + rsp_len = 16; + break; + case MMC_RSP_R3: + rsp_type = SD_RSP_TYPE_R3; + break; + default: + dev_dbg(sdmmc_dev(host), "cmd->flag is not valid\n"); + err = -EINVAL; + goto out; + } + + if (rsp_type == SD_RSP_TYPE_R1b) + timeout = 3000; + + if (cmd->opcode == SD_SWITCH_VOLTAGE) { + err = rtsx_pci_write_register(pcr, SD_BUS_STAT, + 0xFF, SD_CLK_TOGGLE_EN); + if (err < 0) + goto out; + } + + rtsx_pci_init_cmd(pcr); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD0, 0xFF, 0x40 | cmd_idx); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD1, 0xFF, (u8)(arg >> 24)); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD2, 0xFF, (u8)(arg >> 16)); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD3, 0xFF, (u8)(arg >> 8)); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD4, 0xFF, (u8)arg); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG2, 0xFF, rsp_type); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_DATA_SOURCE, + 0x01, PINGPONG_BUFFER); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_TRANSFER, + 0xFF, SD_TM_CMD_RSP | SD_TRANSFER_START); + rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, SD_TRANSFER, + SD_TRANSFER_END | SD_STAT_IDLE, + SD_TRANSFER_END | SD_STAT_IDLE); + + if (rsp_type == SD_RSP_TYPE_R2) { + /* Read data from ping-pong buffer */ + for (i = PPBUF_BASE2; i < PPBUF_BASE2 + 16; i++) + rtsx_pci_add_cmd(pcr, READ_REG_CMD, (u16)i, 0, 0); + stat_idx = 16; + } else if (rsp_type != SD_RSP_TYPE_R0) { + /* Read data from SD_CMDx registers */ + for (i = SD_CMD0; i <= SD_CMD4; i++) + rtsx_pci_add_cmd(pcr, READ_REG_CMD, (u16)i, 0, 0); + stat_idx = 5; + } + + rtsx_pci_add_cmd(pcr, READ_REG_CMD, SD_STAT1, 0, 0); + + err = rtsx_pci_send_cmd(pcr, timeout); + if (err < 0) { + sd_print_debug_regs(host); + sd_clear_error(host); + dev_dbg(sdmmc_dev(host), + "rtsx_pci_send_cmd error (err = %d)\n", err); + goto out; + } + + if (rsp_type == SD_RSP_TYPE_R0) { + err = 0; + goto out; + } + + /* Eliminate returned value of CHECK_REG_CMD */ + ptr = rtsx_pci_get_cmd_data(pcr) + 1; + + /* Check (Start,Transmission) bit of Response */ + if ((ptr[0] & 0xC0) != 0) { + err = -EILSEQ; + dev_dbg(sdmmc_dev(host), "Invalid response bit\n"); + goto out; + } + + /* Check CRC7 */ + if (!(rsp_type & SD_NO_CHECK_CRC7)) { + if (ptr[stat_idx] & SD_CRC7_ERR) { + err = -EILSEQ; + dev_dbg(sdmmc_dev(host), "CRC7 error\n"); + goto out; + } + } + + if (rsp_type == SD_RSP_TYPE_R2) { + for (i = 0; i < 4; i++) { + cmd->resp[i] = get_unaligned_be32(ptr + 1 + i * 4); + dev_dbg(sdmmc_dev(host), "cmd->resp[%d] = 0x%08x\n", + i, cmd->resp[i]); + } + } else { + cmd->resp[0] = get_unaligned_be32(ptr + 1); + dev_dbg(sdmmc_dev(host), "cmd->resp[0] = 0x%08x\n", + cmd->resp[0]); + } + +out: + cmd->error = err; +} + +static int sd_rw_multi(struct realtek_pci_sdmmc *host, struct mmc_request *mrq) +{ + struct rtsx_pcr *pcr = host->pcr; + struct mmc_host *mmc = host->mmc; + struct mmc_card *card = mmc->card; + struct mmc_data *data = mrq->data; + int uhs = mmc_sd_card_uhs(card); + int read = (data->flags & MMC_DATA_READ) ? 1 : 0; + u8 cfg2, trans_mode; + int err; + size_t data_len = data->blksz * data->blocks; + + if (read) { + cfg2 = SD_CALCULATE_CRC7 | SD_CHECK_CRC16 | + SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_0; + trans_mode = SD_TM_AUTO_READ_3; + } else { + cfg2 = SD_NO_CALCULATE_CRC7 | SD_CHECK_CRC16 | + SD_NO_WAIT_BUSY_END | SD_NO_CHECK_CRC7 | SD_RSP_LEN_0; + trans_mode = SD_TM_AUTO_WRITE_3; + } + + if (!uhs) + cfg2 |= SD_NO_CHECK_WAIT_CRC_TO; + + rtsx_pci_init_cmd(pcr); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, 0x00); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_H, 0xFF, 0x02); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_L, + 0xFF, (u8)data->blocks); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_H, + 0xFF, (u8)(data->blocks >> 8)); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, + CARD_DATA_SOURCE, 0x01, RING_BUFFER); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, IRQSTAT0, + DMA_DONE_INT, DMA_DONE_INT); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC3, + 0xFF, (u8)(data_len >> 24)); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC2, + 0xFF, (u8)(data_len >> 16)); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC1, + 0xFF, (u8)(data_len >> 8)); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC0, 0xFF, (u8)data_len); + if (read) { + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMACTL, + 0x03 | DMA_PACK_SIZE_MASK, + DMA_DIR_FROM_CARD | DMA_EN | DMA_512); + } else { + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMACTL, + 0x03 | DMA_PACK_SIZE_MASK, + DMA_DIR_TO_CARD | DMA_EN | DMA_512); + } + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_DATA_SOURCE, + 0x01, RING_BUFFER); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_TRANSFER, 0xFF, + trans_mode | SD_TRANSFER_START); + rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, SD_TRANSFER, + SD_TRANSFER_END, SD_TRANSFER_END); + + rtsx_pci_send_cmd_no_wait(pcr); + + err = rtsx_pci_transfer_data(pcr, data->sg, data->sg_len, read, 10000); + if (err < 0) { + sd_clear_error(host); + return err; + } + + return 0; +} + +static inline void sd_enable_initial_mode(struct realtek_pci_sdmmc *host) +{ + rtsx_pci_write_register(host->pcr, SD_CFG1, + SD_CLK_DIVIDE_MASK, SD_CLK_DIVIDE_128); +} + +static inline void sd_disable_initial_mode(struct realtek_pci_sdmmc *host) +{ + rtsx_pci_write_register(host->pcr, SD_CFG1, + SD_CLK_DIVIDE_MASK, SD_CLK_DIVIDE_0); +} + +static void sd_normal_rw(struct realtek_pci_sdmmc *host, + struct mmc_request *mrq) +{ + struct mmc_command *cmd = mrq->cmd; + struct mmc_data *data = mrq->data; + u8 _cmd[5], *buf; + + _cmd[0] = 0x40 | (u8)cmd->opcode; + put_unaligned_be32(cmd->arg, (u32 *)(&_cmd[1])); + + buf = kzalloc(data->blksz, GFP_NOIO); + if (!buf) { + cmd->error = -ENOMEM; + return; + } + + if (data->flags & MMC_DATA_READ) { + if (host->initial_mode) + sd_disable_initial_mode(host); + + cmd->error = sd_read_data(host, _cmd, (u16)data->blksz, buf, + data->blksz, 200); + + if (host->initial_mode) + sd_enable_initial_mode(host); + + sg_copy_from_buffer(data->sg, data->sg_len, buf, data->blksz); + } else { + sg_copy_to_buffer(data->sg, data->sg_len, buf, data->blksz); + + cmd->error = sd_write_data(host, _cmd, (u16)data->blksz, buf, + data->blksz, 200); + } + + kfree(buf); +} + +static int sd_change_phase(struct realtek_pci_sdmmc *host, u8 sample_point) +{ + struct rtsx_pcr *pcr = host->pcr; + int err; + + dev_dbg(sdmmc_dev(host), "%s: sample_point = %d\n", + __func__, sample_point); + + rtsx_pci_init_cmd(pcr); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CHANGE_CLK, CHANGE_CLK); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPRX_CTL, 0x1F, sample_point); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL, PHASE_NOT_RESET, 0); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL, + PHASE_NOT_RESET, PHASE_NOT_RESET); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CHANGE_CLK, 0); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG1, SD_ASYNC_FIFO_NOT_RST, 0); + + err = rtsx_pci_send_cmd(pcr, 100); + if (err < 0) + return err; + + return 0; +} + +static u8 sd_search_final_phase(struct realtek_pci_sdmmc *host, u32 phase_map) +{ + struct timing_phase_path path[MAX_PHASE + 1]; + int i, j, cont_path_cnt; + int new_block, max_len, final_path_idx; + u8 final_phase = 0xFF; + + /* Parse phase_map, take it as a bit-ring */ + cont_path_cnt = 0; + new_block = 1; + j = 0; + for (i = 0; i < MAX_PHASE + 1; i++) { + if (phase_map & (1 << i)) { + if (new_block) { + new_block = 0; + j = cont_path_cnt++; + path[j].start = i; + path[j].end = i; + } else { + path[j].end = i; + } + } else { + new_block = 1; + if (cont_path_cnt) { + /* Calculate path length and middle point */ + int idx = cont_path_cnt - 1; + path[idx].len = + path[idx].end - path[idx].start + 1; + path[idx].mid = + path[idx].start + path[idx].len / 2; + } + } + } + + if (cont_path_cnt == 0) { + dev_dbg(sdmmc_dev(host), "No continuous phase path\n"); + goto finish; + } else { + /* Calculate last continuous path length and middle point */ + int idx = cont_path_cnt - 1; + path[idx].len = path[idx].end - path[idx].start + 1; + path[idx].mid = path[idx].start + path[idx].len / 2; + } + + /* Connect the first and last continuous paths if they are adjacent */ + if (!path[0].start && (path[cont_path_cnt - 1].end == MAX_PHASE)) { + /* Using negative index */ + path[0].start = path[cont_path_cnt - 1].start - MAX_PHASE - 1; + path[0].len += path[cont_path_cnt - 1].len; + path[0].mid = path[0].start + path[0].len / 2; + /* Convert negative middle point index to positive one */ + if (path[0].mid < 0) + path[0].mid += MAX_PHASE + 1; + cont_path_cnt--; + } + + /* Choose the longest continuous phase path */ + max_len = 0; + final_phase = 0; + final_path_idx = 0; + for (i = 0; i < cont_path_cnt; i++) { + if (path[i].len > max_len) { + max_len = path[i].len; + final_phase = (u8)path[i].mid; + final_path_idx = i; + } + + dev_dbg(sdmmc_dev(host), "path[%d].start = %d\n", + i, path[i].start); + dev_dbg(sdmmc_dev(host), "path[%d].end = %d\n", + i, path[i].end); + dev_dbg(sdmmc_dev(host), "path[%d].len = %d\n", + i, path[i].len); + dev_dbg(sdmmc_dev(host), "path[%d].mid = %d\n", + i, path[i].mid); + } + +finish: + dev_dbg(sdmmc_dev(host), "Final chosen phase: %d\n", final_phase); + return final_phase; +} + +static void sd_wait_data_idle(struct realtek_pci_sdmmc *host) +{ + int err, i; + u8 val = 0; + + for (i = 0; i < 100; i++) { + err = rtsx_pci_read_register(host->pcr, SD_DATA_STATE, &val); + if (val & SD_DATA_IDLE) + return; + + udelay(100); + } +} + +static int sd_tuning_rx_cmd(struct realtek_pci_sdmmc *host, + u8 opcode, u8 sample_point) +{ + int err; + u8 cmd[5] = {0}; + + err = sd_change_phase(host, sample_point); + if (err < 0) + return err; + + cmd[0] = 0x40 | opcode; + err = sd_read_data(host, cmd, 0x40, NULL, 0, 100); + if (err < 0) { + /* Wait till SD DATA IDLE */ + sd_wait_data_idle(host); + sd_clear_error(host); + return err; + } + + return 0; +} + +static int sd_tuning_phase(struct realtek_pci_sdmmc *host, + u8 opcode, u32 *phase_map) +{ + int err, i; + u32 raw_phase_map = 0; + + for (i = MAX_PHASE; i >= 0; i--) { + err = sd_tuning_rx_cmd(host, opcode, (u8)i); + if (err == 0) + raw_phase_map |= 1 << i; + } + + if (phase_map) + *phase_map = raw_phase_map; + + return 0; +} + +static int sd_tuning_rx(struct realtek_pci_sdmmc *host, u8 opcode) +{ + int err, i; + u32 raw_phase_map[RX_TUNING_CNT] = {0}, phase_map; + u8 final_phase; + + for (i = 0; i < RX_TUNING_CNT; i++) { + err = sd_tuning_phase(host, opcode, &(raw_phase_map[i])); + if (err < 0) + return err; + + if (raw_phase_map[i] == 0) + break; + } + + phase_map = 0xFFFFFFFF; + for (i = 0; i < RX_TUNING_CNT; i++) { + dev_dbg(sdmmc_dev(host), "RX raw_phase_map[%d] = 0x%08x\n", + i, raw_phase_map[i]); + phase_map &= raw_phase_map[i]; + } + dev_dbg(sdmmc_dev(host), "RX phase_map = 0x%08x\n", phase_map); + + if (phase_map) { + final_phase = sd_search_final_phase(host, phase_map); + if (final_phase == 0xFF) + return -EINVAL; + + err = sd_change_phase(host, final_phase); + if (err < 0) + return err; + } else { + return -EINVAL; + } + + return 0; +} + +static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct realtek_pci_sdmmc *host = mmc_priv(mmc); + struct rtsx_pcr *pcr = host->pcr; + struct mmc_command *cmd = mrq->cmd; + struct mmc_data *data = mrq->data; + unsigned int data_size = 0; + + if (host->eject) { + cmd->error = -ENOMEDIUM; + goto finish; + } + + mutex_lock(&pcr->pcr_mutex); + + rtsx_pci_start_run(pcr); + + rtsx_pci_switch_clock(pcr, host->clock, host->ssc_depth, + host->initial_mode, host->double_clk, host->vpclk); + rtsx_pci_write_register(pcr, CARD_SELECT, 0x07, SD_MOD_SEL); + rtsx_pci_write_register(pcr, CARD_SHARE_MODE, + CARD_SHARE_MASK, CARD_SHARE_48_SD); + + mutex_lock(&host->host_mutex); + host->mrq = mrq; + mutex_unlock(&host->host_mutex); + + if (mrq->data) + data_size = data->blocks * data->blksz; + + if (!data_size || mmc_op_multi(cmd->opcode) || + (cmd->opcode == MMC_READ_SINGLE_BLOCK) || + (cmd->opcode == MMC_WRITE_BLOCK)) { + sd_send_cmd_get_rsp(host, cmd); + + if (!cmd->error && data_size) { + sd_rw_multi(host, mrq); + + if (mmc_op_multi(cmd->opcode) && mrq->stop) + sd_send_cmd_get_rsp(host, mrq->stop); + } + } else { + sd_normal_rw(host, mrq); + } + + if (mrq->data) { + if (cmd->error || data->error) + data->bytes_xfered = 0; + else + data->bytes_xfered = data->blocks * data->blksz; + } + + mutex_unlock(&pcr->pcr_mutex); + +finish: + if (cmd->error) + dev_dbg(sdmmc_dev(host), "cmd->error = %d\n", cmd->error); + + mutex_lock(&host->host_mutex); + host->mrq = NULL; + mutex_unlock(&host->host_mutex); + + mmc_request_done(mmc, mrq); +} + +static int sd_set_bus_width(struct realtek_pci_sdmmc *host, + unsigned char bus_width) +{ + int err = 0; + u8 width[] = { + [MMC_BUS_WIDTH_1] = SD_BUS_WIDTH_1BIT, + [MMC_BUS_WIDTH_4] = SD_BUS_WIDTH_4BIT, + [MMC_BUS_WIDTH_8] = SD_BUS_WIDTH_8BIT, + }; + + if (bus_width <= MMC_BUS_WIDTH_8) + err = rtsx_pci_write_register(host->pcr, SD_CFG1, + 0x03, width[bus_width]); + + return err; +} + +static int sd_power_on(struct realtek_pci_sdmmc *host) +{ + struct rtsx_pcr *pcr = host->pcr; + int err; + + rtsx_pci_init_cmd(pcr); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_SELECT, 0x07, SD_MOD_SEL); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_SHARE_MODE, + CARD_SHARE_MASK, CARD_SHARE_48_SD); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_EN, + SD_CLK_EN, SD_CLK_EN); + err = rtsx_pci_send_cmd(pcr, 100); + if (err < 0) + return err; + + err = rtsx_pci_card_pull_ctl_enable(pcr, RTSX_SD_CARD); + if (err < 0) + return err; + + err = rtsx_pci_card_power_on(pcr, RTSX_SD_CARD); + if (err < 0) + return err; + + err = rtsx_pci_write_register(pcr, CARD_OE, SD_OUTPUT_EN, SD_OUTPUT_EN); + if (err < 0) + return err; + + return 0; +} + +static int sd_power_off(struct realtek_pci_sdmmc *host) +{ + struct rtsx_pcr *pcr = host->pcr; + int err; + + rtsx_pci_init_cmd(pcr); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_EN, SD_CLK_EN, 0); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_OE, SD_OUTPUT_EN, 0); + + err = rtsx_pci_send_cmd(pcr, 100); + if (err < 0) + return err; + + err = rtsx_pci_card_power_off(pcr, RTSX_SD_CARD); + if (err < 0) + return err; + + return rtsx_pci_card_pull_ctl_disable(pcr, RTSX_SD_CARD); +} + +static int sd_set_power_mode(struct realtek_pci_sdmmc *host, + unsigned char power_mode) +{ + int err; + + if (power_mode == MMC_POWER_OFF) + err = sd_power_off(host); + else + err = sd_power_on(host); + + return err; +} + +static int sd_set_timing(struct realtek_pci_sdmmc *host, + unsigned char timing, bool *ddr_mode) +{ + struct rtsx_pcr *pcr = host->pcr; + int err = 0; + + *ddr_mode = false; + + rtsx_pci_init_cmd(pcr); + + switch (timing) { + case MMC_TIMING_UHS_SDR104: + case MMC_TIMING_UHS_SDR50: + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG1, + 0x0C | SD_ASYNC_FIFO_NOT_RST, + SD_30_MODE | SD_ASYNC_FIFO_NOT_RST); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, + CLK_LOW_FREQ, CLK_LOW_FREQ); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_SOURCE, 0xFF, + CRC_VAR_CLK0 | SD30_FIX_CLK | SAMPLE_VAR_CLK1); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CLK_LOW_FREQ, 0); + break; + + case MMC_TIMING_UHS_DDR50: + *ddr_mode = true; + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG1, + 0x0C | SD_ASYNC_FIFO_NOT_RST, + SD_DDR_MODE | SD_ASYNC_FIFO_NOT_RST); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, + CLK_LOW_FREQ, CLK_LOW_FREQ); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_SOURCE, 0xFF, + CRC_VAR_CLK0 | SD30_FIX_CLK | SAMPLE_VAR_CLK1); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CLK_LOW_FREQ, 0); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_PUSH_POINT_CTL, + DDR_VAR_TX_CMD_DAT, DDR_VAR_TX_CMD_DAT); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_SAMPLE_POINT_CTL, + DDR_VAR_RX_DAT | DDR_VAR_RX_CMD, + DDR_VAR_RX_DAT | DDR_VAR_RX_CMD); + break; + + case MMC_TIMING_MMC_HS: + case MMC_TIMING_SD_HS: + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG1, + 0x0C, SD_20_MODE); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, + CLK_LOW_FREQ, CLK_LOW_FREQ); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_SOURCE, 0xFF, + CRC_FIX_CLK | SD30_VAR_CLK0 | SAMPLE_VAR_CLK1); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CLK_LOW_FREQ, 0); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_PUSH_POINT_CTL, + SD20_TX_SEL_MASK, SD20_TX_14_AHEAD); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_SAMPLE_POINT_CTL, + SD20_RX_SEL_MASK, SD20_RX_14_DELAY); + break; + + default: + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, + SD_CFG1, 0x0C, SD_20_MODE); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, + CLK_LOW_FREQ, CLK_LOW_FREQ); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_SOURCE, 0xFF, + CRC_FIX_CLK | SD30_VAR_CLK0 | SAMPLE_VAR_CLK1); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CLK_LOW_FREQ, 0); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, + SD_PUSH_POINT_CTL, 0xFF, 0); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_SAMPLE_POINT_CTL, + SD20_RX_SEL_MASK, SD20_RX_POS_EDGE); + break; + } + + err = rtsx_pci_send_cmd(pcr, 100); + + return err; +} + +static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct realtek_pci_sdmmc *host = mmc_priv(mmc); + struct rtsx_pcr *pcr = host->pcr; + + if (host->eject) + return; + + mutex_lock(&pcr->pcr_mutex); + + rtsx_pci_start_run(pcr); + + sd_set_bus_width(host, ios->bus_width); + sd_set_power_mode(host, ios->power_mode); + sd_set_timing(host, ios->timing, &host->ddr_mode); + + host->vpclk = false; + host->double_clk = true; + + switch (ios->timing) { + case MMC_TIMING_UHS_SDR104: + case MMC_TIMING_UHS_SDR50: + host->ssc_depth = RTSX_SSC_DEPTH_2M; + host->vpclk = true; + host->double_clk = false; + break; + case MMC_TIMING_UHS_DDR50: + case MMC_TIMING_UHS_SDR25: + host->ssc_depth = RTSX_SSC_DEPTH_1M; + break; + default: + host->ssc_depth = RTSX_SSC_DEPTH_500K; + break; + } + + host->initial_mode = (ios->clock <= 1000000) ? true : false; + + host->clock = ios->clock; + rtsx_pci_switch_clock(pcr, ios->clock, host->ssc_depth, + host->initial_mode, host->double_clk, host->vpclk); + + mutex_unlock(&pcr->pcr_mutex); +} + +static int sdmmc_get_ro(struct mmc_host *mmc) +{ + struct realtek_pci_sdmmc *host = mmc_priv(mmc); + struct rtsx_pcr *pcr = host->pcr; + int ro = 0; + u32 val; + + if (host->eject) + return -ENOMEDIUM; + + mutex_lock(&pcr->pcr_mutex); + + rtsx_pci_start_run(pcr); + + /* Check SD mechanical write-protect switch */ + val = rtsx_pci_readl(pcr, RTSX_BIPR); + dev_dbg(sdmmc_dev(host), "%s: RTSX_BIPR = 0x%08x\n", __func__, val); + if (val & SD_WRITE_PROTECT) + ro = 1; + + mutex_unlock(&pcr->pcr_mutex); + + return ro; +} + +static int sdmmc_get_cd(struct mmc_host *mmc) +{ + struct realtek_pci_sdmmc *host = mmc_priv(mmc); + struct rtsx_pcr *pcr = host->pcr; + int cd = 0; + u32 val; + + if (host->eject) + return -ENOMEDIUM; + + mutex_lock(&pcr->pcr_mutex); + + rtsx_pci_start_run(pcr); + + /* Check SD card detect */ + val = rtsx_pci_card_exist(pcr); + dev_dbg(sdmmc_dev(host), "%s: RTSX_BIPR = 0x%08x\n", __func__, val); + if (val & SD_EXIST) + cd = 1; + + mutex_unlock(&pcr->pcr_mutex); + + return cd; +} + +static int sd_wait_voltage_stable_1(struct realtek_pci_sdmmc *host) +{ + struct rtsx_pcr *pcr = host->pcr; + int err; + u8 stat; + + /* Reference to Signal Voltage Switch Sequence in SD spec. + * Wait for a period of time so that the card can drive SD_CMD and + * SD_DAT[3:0] to low after sending back CMD11 response. + */ + mdelay(1); + + /* SD_CMD, SD_DAT[3:0] should be driven to low by card; + * If either one of SD_CMD,SD_DAT[3:0] is not low, + * abort the voltage switch sequence; + */ + err = rtsx_pci_read_register(pcr, SD_BUS_STAT, &stat); + if (err < 0) + return err; + + if (stat & (SD_CMD_STATUS | SD_DAT3_STATUS | SD_DAT2_STATUS | + SD_DAT1_STATUS | SD_DAT0_STATUS)) + return -EINVAL; + + /* Stop toggle SD clock */ + err = rtsx_pci_write_register(pcr, SD_BUS_STAT, + 0xFF, SD_CLK_FORCE_STOP); + if (err < 0) + return err; + + return 0; +} + +static int sd_wait_voltage_stable_2(struct realtek_pci_sdmmc *host) +{ + struct rtsx_pcr *pcr = host->pcr; + int err; + u8 stat, mask, val; + + /* Wait 1.8V output of voltage regulator in card stable */ + msleep(50); + + /* Toggle SD clock again */ + err = rtsx_pci_write_register(pcr, SD_BUS_STAT, 0xFF, SD_CLK_TOGGLE_EN); + if (err < 0) + return err; + + /* Wait for a period of time so that the card can drive + * SD_DAT[3:0] to high at 1.8V + */ + msleep(20); + + /* SD_CMD, SD_DAT[3:0] should be pulled high by host */ + err = rtsx_pci_read_register(pcr, SD_BUS_STAT, &stat); + if (err < 0) + return err; + + mask = SD_CMD_STATUS | SD_DAT3_STATUS | SD_DAT2_STATUS | + SD_DAT1_STATUS | SD_DAT0_STATUS; + val = SD_CMD_STATUS | SD_DAT3_STATUS | SD_DAT2_STATUS | + SD_DAT1_STATUS | SD_DAT0_STATUS; + if ((stat & mask) != val) { + dev_dbg(sdmmc_dev(host), + "%s: SD_BUS_STAT = 0x%x\n", __func__, stat); + rtsx_pci_write_register(pcr, SD_BUS_STAT, + SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0); + rtsx_pci_write_register(pcr, CARD_CLK_EN, 0xFF, 0); + return -EINVAL; + } + + return 0; +} + +static int sd_change_bank_voltage(struct realtek_pci_sdmmc *host, u8 voltage) +{ + struct rtsx_pcr *pcr = host->pcr; + int err; + + if (voltage == SD_IO_3V3) { + err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24); + if (err < 0) + return err; + } else if (voltage == SD_IO_1V8) { + err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C40 | 0x24); + if (err < 0) + return err; + } else { + return -EINVAL; + } + + return 0; +} + +static int sdmmc_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct realtek_pci_sdmmc *host = mmc_priv(mmc); + struct rtsx_pcr *pcr = host->pcr; + int err = 0; + u8 voltage; + + dev_dbg(sdmmc_dev(host), "%s: signal_voltage = %d\n", + __func__, ios->signal_voltage); + + if (host->eject) + return -ENOMEDIUM; + + mutex_lock(&pcr->pcr_mutex); + + rtsx_pci_start_run(pcr); + + if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) + voltage = SD_IO_3V3; + else + voltage = SD_IO_1V8; + + if (voltage == SD_IO_1V8) { + err = rtsx_pci_write_register(pcr, + SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_B); + if (err < 0) + goto out; + + err = sd_wait_voltage_stable_1(host); + if (err < 0) + goto out; + } + + err = sd_change_bank_voltage(host, voltage); + if (err < 0) + goto out; + + if (voltage == SD_IO_1V8) { + err = sd_wait_voltage_stable_2(host); + if (err < 0) + goto out; + } + + /* Stop toggle SD clock in idle */ + err = rtsx_pci_write_register(pcr, SD_BUS_STAT, + SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0); + +out: + mutex_unlock(&pcr->pcr_mutex); + + return err; +} + +static int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode) +{ + struct realtek_pci_sdmmc *host = mmc_priv(mmc); + struct rtsx_pcr *pcr = host->pcr; + int err = 0; + + if (host->eject) + return -ENOMEDIUM; + + mutex_lock(&pcr->pcr_mutex); + + rtsx_pci_start_run(pcr); + + if (!host->ddr_mode) + err = sd_tuning_rx(host, MMC_SEND_TUNING_BLOCK); + + mutex_unlock(&pcr->pcr_mutex); + + return err; +} + +static const struct mmc_host_ops realtek_pci_sdmmc_ops = { + .request = sdmmc_request, + .set_ios = sdmmc_set_ios, + .get_ro = sdmmc_get_ro, + .get_cd = sdmmc_get_cd, + .start_signal_voltage_switch = sdmmc_switch_voltage, + .execute_tuning = sdmmc_execute_tuning, +}; + +#ifdef CONFIG_PM +static int rtsx_pci_sdmmc_suspend(struct platform_device *pdev, + pm_message_t state) +{ + struct realtek_pci_sdmmc *host = platform_get_drvdata(pdev); + struct mmc_host *mmc = host->mmc; + int err; + + dev_dbg(sdmmc_dev(host), "--> %s\n", __func__); + + err = mmc_suspend_host(mmc); + if (err) + return err; + + return 0; +} + +static int rtsx_pci_sdmmc_resume(struct platform_device *pdev) +{ + struct realtek_pci_sdmmc *host = platform_get_drvdata(pdev); + struct mmc_host *mmc = host->mmc; + + dev_dbg(sdmmc_dev(host), "--> %s\n", __func__); + + return mmc_resume_host(mmc); +} +#else /* CONFIG_PM */ +#define rtsx_pci_sdmmc_suspend NULL +#define rtsx_pci_sdmmc_resume NULL +#endif /* CONFIG_PM */ + +static void init_extra_caps(struct realtek_pci_sdmmc *host) +{ + struct mmc_host *mmc = host->mmc; + struct rtsx_pcr *pcr = host->pcr; + + dev_dbg(sdmmc_dev(host), "pcr->extra_caps = 0x%x\n", pcr->extra_caps); + + if (pcr->extra_caps & EXTRA_CAPS_SD_SDR50) + mmc->caps |= MMC_CAP_UHS_SDR50; + if (pcr->extra_caps & EXTRA_CAPS_SD_SDR104) + mmc->caps |= MMC_CAP_UHS_SDR104; + if (pcr->extra_caps & EXTRA_CAPS_SD_DDR50) + mmc->caps |= MMC_CAP_UHS_DDR50; + if (pcr->extra_caps & EXTRA_CAPS_MMC_HSDDR) + mmc->caps |= MMC_CAP_1_8V_DDR; + if (pcr->extra_caps & EXTRA_CAPS_MMC_8BIT) + mmc->caps |= MMC_CAP_8_BIT_DATA; +} + +static void realtek_init_host(struct realtek_pci_sdmmc *host) +{ + struct mmc_host *mmc = host->mmc; + + mmc->f_min = 250000; + mmc->f_max = 208000000; + mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; + mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED | + MMC_CAP_MMC_HIGHSPEED | MMC_CAP_BUS_WIDTH_TEST | + MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25; + mmc->max_current_330 = 400; + mmc->max_current_180 = 800; + mmc->ops = &realtek_pci_sdmmc_ops; + + init_extra_caps(host); + + mmc->max_segs = 256; + mmc->max_seg_size = 65536; + mmc->max_blk_size = 512; + mmc->max_blk_count = 65535; + mmc->max_req_size = 524288; +} + +static void rtsx_pci_sdmmc_card_event(struct platform_device *pdev) +{ + struct realtek_pci_sdmmc *host = platform_get_drvdata(pdev); + + mmc_detect_change(host->mmc, 0); +} + +static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev) +{ + struct mmc_host *mmc; + struct realtek_pci_sdmmc *host; + struct rtsx_pcr *pcr; + struct pcr_handle *handle = pdev->dev.platform_data; + + if (!handle) + return -ENXIO; + + pcr = handle->pcr; + if (!pcr) + return -ENXIO; + + dev_dbg(&(pdev->dev), ": Realtek PCI-E SDMMC controller found\n"); + + mmc = mmc_alloc_host(sizeof(*host), &pdev->dev); + if (!mmc) + return -ENOMEM; + + host = mmc_priv(mmc); + host->pcr = pcr; + host->mmc = mmc; + host->pdev = pdev; + platform_set_drvdata(pdev, host); + pcr->slots[RTSX_SD_CARD].p_dev = pdev; + pcr->slots[RTSX_SD_CARD].card_event = rtsx_pci_sdmmc_card_event; + + mutex_init(&host->host_mutex); + + realtek_init_host(host); + + mmc_add_host(mmc); + + return 0; +} + +static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev) +{ + struct realtek_pci_sdmmc *host = platform_get_drvdata(pdev); + struct rtsx_pcr *pcr; + struct mmc_host *mmc; + + if (!host) + return 0; + + pcr = host->pcr; + pcr->slots[RTSX_SD_CARD].p_dev = NULL; + pcr->slots[RTSX_SD_CARD].card_event = NULL; + mmc = host->mmc; + host->eject = true; + + mutex_lock(&host->host_mutex); + if (host->mrq) { + dev_dbg(&(pdev->dev), + "%s: Controller removed during transfer\n", + mmc_hostname(mmc)); + + rtsx_pci_complete_unfinished_transfer(pcr); + + host->mrq->cmd->error = -ENOMEDIUM; + if (host->mrq->stop) + host->mrq->stop->error = -ENOMEDIUM; + mmc_request_done(mmc, host->mrq); + } + mutex_unlock(&host->host_mutex); + + mmc_remove_host(mmc); + mmc_free_host(mmc); + + platform_set_drvdata(pdev, NULL); + + dev_dbg(&(pdev->dev), + ": Realtek PCI-E SDMMC controller has been removed\n"); + + return 0; +} + +static struct platform_device_id rtsx_pci_sdmmc_ids[] = { + { + .name = DRV_NAME_RTSX_PCI_SDMMC, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(platform, rtsx_pci_sdmmc_ids); + +static struct platform_driver rtsx_pci_sdmmc_driver = { + .probe = rtsx_pci_sdmmc_drv_probe, + .remove = rtsx_pci_sdmmc_drv_remove, + .id_table = rtsx_pci_sdmmc_ids, + .suspend = rtsx_pci_sdmmc_suspend, + .resume = rtsx_pci_sdmmc_resume, + .driver = { + .owner = THIS_MODULE, + .name = DRV_NAME_RTSX_PCI_SDMMC, + }, +}; +module_platform_driver(rtsx_pci_sdmmc_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Wei WANG "); +MODULE_DESCRIPTION("Realtek PCI-E SD/MMC Card Host Driver"); -- cgit v0.10.2 From b902dd4ecc2cccdd6c033ba5d959d4d6606e55fb Mon Sep 17 00:00:00 2001 From: Wei WANG Date: Fri, 9 Nov 2012 20:53:35 +0800 Subject: drivers/memstick: Add realtek pcie memstick host driver Realtek PCI-E Memstick card host driver is used to access Memstick card, with the help of Realtek PCI-E card reader MFD driver. Signed-off-by: Wei WANG Acked-by: Alex Dubov Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/memstick/host/Kconfig b/drivers/memstick/host/Kconfig index cc0997a..4f7a17f 100644 --- a/drivers/memstick/host/Kconfig +++ b/drivers/memstick/host/Kconfig @@ -42,3 +42,13 @@ config MEMSTICK_R592 To compile this driver as a module, choose M here: the module will be called r592. + +config MEMSTICK_REALTEK_PCI + tristate "Realtek PCI-E Memstick Card Interface Driver" + depends on MFD_RTSX_PCI + help + Say Y here to include driver code to support Memstick card interface + of Realtek PCI-E card reader + + To compile this driver as a module, choose M here: the module will + be called rtsx_pci_ms. diff --git a/drivers/memstick/host/Makefile b/drivers/memstick/host/Makefile index 31ba8d3..af3459d 100644 --- a/drivers/memstick/host/Makefile +++ b/drivers/memstick/host/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_MEMSTICK_TIFM_MS) += tifm_ms.o obj-$(CONFIG_MEMSTICK_JMICRON_38X) += jmb38x_ms.o obj-$(CONFIG_MEMSTICK_R592) += r592.o +obj-$(CONFIG_MEMSTICK_REALTEK_PCI) += rtsx_pci_ms.o diff --git a/drivers/memstick/host/rtsx_pci_ms.c b/drivers/memstick/host/rtsx_pci_ms.c new file mode 100644 index 0000000..f5ddb82 --- /dev/null +++ b/drivers/memstick/host/rtsx_pci_ms.c @@ -0,0 +1,641 @@ +/* Realtek PCI-Express Memstick Card Interface driver + * + * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + * + * Author: + * Wei WANG + * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China + */ + +#include +#include +#include +#include +#include +#include +#include + +struct realtek_pci_ms { + struct platform_device *pdev; + struct rtsx_pcr *pcr; + struct memstick_host *msh; + struct memstick_request *req; + + struct mutex host_mutex; + struct work_struct handle_req; + + u8 ssc_depth; + unsigned int clock; + unsigned char ifmode; + bool eject; +}; + +static inline struct device *ms_dev(struct realtek_pci_ms *host) +{ + return &(host->pdev->dev); +} + +static inline void ms_clear_error(struct realtek_pci_ms *host) +{ + rtsx_pci_write_register(host->pcr, CARD_STOP, + MS_STOP | MS_CLR_ERR, MS_STOP | MS_CLR_ERR); +} + +#ifdef DEBUG + +static void ms_print_debug_regs(struct realtek_pci_ms *host) +{ + struct rtsx_pcr *pcr = host->pcr; + u16 i; + u8 *ptr; + + /* Print MS host internal registers */ + rtsx_pci_init_cmd(pcr); + for (i = 0xFD40; i <= 0xFD44; i++) + rtsx_pci_add_cmd(pcr, READ_REG_CMD, i, 0, 0); + for (i = 0xFD52; i <= 0xFD69; i++) + rtsx_pci_add_cmd(pcr, READ_REG_CMD, i, 0, 0); + rtsx_pci_send_cmd(pcr, 100); + + ptr = rtsx_pci_get_cmd_data(pcr); + for (i = 0xFD40; i <= 0xFD44; i++) + dev_dbg(ms_dev(host), "0x%04X: 0x%02x\n", i, *(ptr++)); + for (i = 0xFD52; i <= 0xFD69; i++) + dev_dbg(ms_dev(host), "0x%04X: 0x%02x\n", i, *(ptr++)); +} + +#else + +#define ms_print_debug_regs(host) + +#endif + +static int ms_power_on(struct realtek_pci_ms *host) +{ + struct rtsx_pcr *pcr = host->pcr; + int err; + + rtsx_pci_init_cmd(pcr); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_SELECT, 0x07, MS_MOD_SEL); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_SHARE_MODE, + CARD_SHARE_MASK, CARD_SHARE_48_MS); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_EN, + MS_CLK_EN, MS_CLK_EN); + err = rtsx_pci_send_cmd(pcr, 100); + if (err < 0) + return err; + + err = rtsx_pci_card_pull_ctl_enable(pcr, RTSX_MS_CARD); + if (err < 0) + return err; + + err = rtsx_pci_card_power_on(pcr, RTSX_MS_CARD); + if (err < 0) + return err; + + /* Wait ms power stable */ + msleep(150); + + err = rtsx_pci_write_register(pcr, CARD_OE, + MS_OUTPUT_EN, MS_OUTPUT_EN); + if (err < 0) + return err; + + return 0; +} + +static int ms_power_off(struct realtek_pci_ms *host) +{ + struct rtsx_pcr *pcr = host->pcr; + int err; + + rtsx_pci_init_cmd(pcr); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_EN, MS_CLK_EN, 0); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_OE, MS_OUTPUT_EN, 0); + + err = rtsx_pci_send_cmd(pcr, 100); + if (err < 0) + return err; + + err = rtsx_pci_card_power_off(pcr, RTSX_MS_CARD); + if (err < 0) + return err; + + return rtsx_pci_card_pull_ctl_disable(pcr, RTSX_MS_CARD); +} + +static int ms_transfer_data(struct realtek_pci_ms *host, unsigned char data_dir, + u8 tpc, u8 cfg, struct scatterlist *sg) +{ + struct rtsx_pcr *pcr = host->pcr; + int err; + unsigned int length = sg->length; + u16 sec_cnt = (u16)(length / 512); + u8 val, trans_mode, dma_dir; + + dev_dbg(ms_dev(host), "%s: tpc = 0x%02x, data_dir = %s, length = %d\n", + __func__, tpc, (data_dir == READ) ? "READ" : "WRITE", + length); + + if (data_dir == READ) { + dma_dir = DMA_DIR_FROM_CARD; + trans_mode = MS_TM_AUTO_READ; + } else { + dma_dir = DMA_DIR_TO_CARD; + trans_mode = MS_TM_AUTO_WRITE; + } + + rtsx_pci_init_cmd(pcr); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_TPC, 0xFF, tpc); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_SECTOR_CNT_H, + 0xFF, (u8)(sec_cnt >> 8)); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_SECTOR_CNT_L, + 0xFF, (u8)sec_cnt); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, IRQSTAT0, + DMA_DONE_INT, DMA_DONE_INT); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC3, 0xFF, (u8)(length >> 24)); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC2, 0xFF, (u8)(length >> 16)); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC1, 0xFF, (u8)(length >> 8)); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC0, 0xFF, (u8)length); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMACTL, + 0x03 | DMA_PACK_SIZE_MASK, dma_dir | DMA_EN | DMA_512); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_DATA_SOURCE, + 0x01, RING_BUFFER); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_TRANSFER, + 0xFF, MS_TRANSFER_START | trans_mode); + rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, MS_TRANSFER, + MS_TRANSFER_END, MS_TRANSFER_END); + + rtsx_pci_send_cmd_no_wait(pcr); + + err = rtsx_pci_transfer_data(pcr, sg, 1, data_dir == READ, 10000); + if (err < 0) { + ms_clear_error(host); + return err; + } + + rtsx_pci_read_register(pcr, MS_TRANS_CFG, &val); + if (val & (MS_INT_CMDNK | MS_INT_ERR | MS_CRC16_ERR | MS_RDY_TIMEOUT)) + return -EIO; + + return 0; +} + +static int ms_write_bytes(struct realtek_pci_ms *host, u8 tpc, + u8 cfg, u8 cnt, u8 *data, u8 *int_reg) +{ + struct rtsx_pcr *pcr = host->pcr; + int err, i; + + dev_dbg(ms_dev(host), "%s: tpc = 0x%02x\n", __func__, tpc); + + if (!data) + return -EINVAL; + + rtsx_pci_init_cmd(pcr); + + for (i = 0; i < cnt; i++) + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, + PPBUF_BASE2 + i, 0xFF, data[i]); + if (cnt % 2) + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, + PPBUF_BASE2 + i, 0xFF, 0xFF); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_TPC, 0xFF, tpc); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_BYTE_CNT, 0xFF, cnt); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_DATA_SOURCE, + 0x01, PINGPONG_BUFFER); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_TRANSFER, + 0xFF, MS_TRANSFER_START | MS_TM_WRITE_BYTES); + rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, MS_TRANSFER, + MS_TRANSFER_END, MS_TRANSFER_END); + if (int_reg) + rtsx_pci_add_cmd(pcr, READ_REG_CMD, MS_TRANS_CFG, 0, 0); + + err = rtsx_pci_send_cmd(pcr, 5000); + if (err < 0) { + u8 val; + + rtsx_pci_read_register(pcr, MS_TRANS_CFG, &val); + dev_dbg(ms_dev(host), "MS_TRANS_CFG: 0x%02x\n", val); + + if (int_reg) + *int_reg = val & 0x0F; + + ms_print_debug_regs(host); + + ms_clear_error(host); + + if (!(tpc & 0x08)) { + if (val & MS_CRC16_ERR) + return -EIO; + } else { + if (!(val & 0x80)) { + if (val & (MS_INT_ERR | MS_INT_CMDNK)) + return -EIO; + } + } + + return -ETIMEDOUT; + } + + if (int_reg) { + u8 *ptr = rtsx_pci_get_cmd_data(pcr) + 1; + *int_reg = *ptr & 0x0F; + } + + return 0; +} + +static int ms_read_bytes(struct realtek_pci_ms *host, u8 tpc, + u8 cfg, u8 cnt, u8 *data, u8 *int_reg) +{ + struct rtsx_pcr *pcr = host->pcr; + int err, i; + u8 *ptr; + + dev_dbg(ms_dev(host), "%s: tpc = 0x%02x\n", __func__, tpc); + + if (!data) + return -EINVAL; + + rtsx_pci_init_cmd(pcr); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_TPC, 0xFF, tpc); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_BYTE_CNT, 0xFF, cnt); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_DATA_SOURCE, + 0x01, PINGPONG_BUFFER); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_TRANSFER, + 0xFF, MS_TRANSFER_START | MS_TM_READ_BYTES); + rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, MS_TRANSFER, + MS_TRANSFER_END, MS_TRANSFER_END); + for (i = 0; i < cnt - 1; i++) + rtsx_pci_add_cmd(pcr, READ_REG_CMD, PPBUF_BASE2 + i, 0, 0); + if (cnt % 2) + rtsx_pci_add_cmd(pcr, READ_REG_CMD, PPBUF_BASE2 + cnt, 0, 0); + else + rtsx_pci_add_cmd(pcr, READ_REG_CMD, + PPBUF_BASE2 + cnt - 1, 0, 0); + if (int_reg) + rtsx_pci_add_cmd(pcr, READ_REG_CMD, MS_TRANS_CFG, 0, 0); + + err = rtsx_pci_send_cmd(pcr, 5000); + if (err < 0) { + u8 val; + + rtsx_pci_read_register(pcr, MS_TRANS_CFG, &val); + dev_dbg(ms_dev(host), "MS_TRANS_CFG: 0x%02x\n", val); + + if (int_reg) + *int_reg = val & 0x0F; + + ms_print_debug_regs(host); + + ms_clear_error(host); + + if (!(tpc & 0x08)) { + if (val & MS_CRC16_ERR) + return -EIO; + } else { + if (!(val & 0x80)) { + if (val & (MS_INT_ERR | MS_INT_CMDNK)) + return -EIO; + } + } + + return -ETIMEDOUT; + } + + ptr = rtsx_pci_get_cmd_data(pcr) + 1; + for (i = 0; i < cnt; i++) + data[i] = *ptr++; + + if (int_reg) + *int_reg = *ptr & 0x0F; + + return 0; +} + +static int rtsx_pci_ms_issue_cmd(struct realtek_pci_ms *host) +{ + struct memstick_request *req = host->req; + int err = 0; + u8 cfg = 0, int_reg; + + dev_dbg(ms_dev(host), "%s\n", __func__); + + if (req->need_card_int) { + if (host->ifmode != MEMSTICK_SERIAL) + cfg = WAIT_INT; + } + + if (req->long_data) { + err = ms_transfer_data(host, req->data_dir, + req->tpc, cfg, &(req->sg)); + } else { + if (req->data_dir == READ) { + err = ms_read_bytes(host, req->tpc, cfg, + req->data_len, req->data, &int_reg); + } else { + err = ms_write_bytes(host, req->tpc, cfg, + req->data_len, req->data, &int_reg); + } + } + if (err < 0) + return err; + + if (req->need_card_int && (host->ifmode == MEMSTICK_SERIAL)) { + err = ms_read_bytes(host, MS_TPC_GET_INT, + NO_WAIT_INT, 1, &int_reg, NULL); + if (err < 0) + return err; + } + + if (req->need_card_int) { + dev_dbg(ms_dev(host), "int_reg: 0x%02x\n", int_reg); + + if (int_reg & MS_INT_CMDNK) + req->int_reg |= MEMSTICK_INT_CMDNAK; + if (int_reg & MS_INT_BREQ) + req->int_reg |= MEMSTICK_INT_BREQ; + if (int_reg & MS_INT_ERR) + req->int_reg |= MEMSTICK_INT_ERR; + if (int_reg & MS_INT_CED) + req->int_reg |= MEMSTICK_INT_CED; + } + + return 0; +} + +static void rtsx_pci_ms_handle_req(struct work_struct *work) +{ + struct realtek_pci_ms *host = container_of(work, + struct realtek_pci_ms, handle_req); + struct rtsx_pcr *pcr = host->pcr; + struct memstick_host *msh = host->msh; + int rc; + + mutex_lock(&pcr->pcr_mutex); + + rtsx_pci_start_run(pcr); + + rtsx_pci_switch_clock(host->pcr, host->clock, host->ssc_depth, + false, true, false); + rtsx_pci_write_register(pcr, CARD_SELECT, 0x07, MS_MOD_SEL); + rtsx_pci_write_register(pcr, CARD_SHARE_MODE, + CARD_SHARE_MASK, CARD_SHARE_48_MS); + + if (!host->req) { + do { + rc = memstick_next_req(msh, &host->req); + dev_dbg(ms_dev(host), "next req %d\n", rc); + + if (!rc) + host->req->error = rtsx_pci_ms_issue_cmd(host); + } while (!rc); + } + + mutex_unlock(&pcr->pcr_mutex); +} + +static void rtsx_pci_ms_request(struct memstick_host *msh) +{ + struct realtek_pci_ms *host = memstick_priv(msh); + + dev_dbg(ms_dev(host), "--> %s\n", __func__); + + schedule_work(&host->handle_req); +} + +static int rtsx_pci_ms_set_param(struct memstick_host *msh, + enum memstick_param param, int value) +{ + struct realtek_pci_ms *host = memstick_priv(msh); + struct rtsx_pcr *pcr = host->pcr; + unsigned int clock = 0; + u8 ssc_depth = 0; + int err; + + dev_dbg(ms_dev(host), "%s: param = %d, value = %d\n", + __func__, param, value); + + switch (param) { + case MEMSTICK_POWER: + if (value == MEMSTICK_POWER_ON) + err = ms_power_on(host); + else if (value == MEMSTICK_POWER_OFF) + err = ms_power_off(host); + else + return -EINVAL; + break; + + case MEMSTICK_INTERFACE: + if (value == MEMSTICK_SERIAL) { + clock = 19000000; + ssc_depth = RTSX_SSC_DEPTH_500K; + + err = rtsx_pci_write_register(pcr, MS_CFG, + 0x18, MS_BUS_WIDTH_1); + if (err < 0) + return err; + } else if (value == MEMSTICK_PAR4) { + clock = 39000000; + ssc_depth = RTSX_SSC_DEPTH_1M; + + err = rtsx_pci_write_register(pcr, MS_CFG, + 0x58, MS_BUS_WIDTH_4 | PUSH_TIME_ODD); + if (err < 0) + return err; + } else { + return -EINVAL; + } + + err = rtsx_pci_switch_clock(pcr, clock, + ssc_depth, false, true, false); + if (err < 0) + return err; + + host->ssc_depth = ssc_depth; + host->clock = clock; + host->ifmode = value; + break; + } + + return 0; +} + +#ifdef CONFIG_PM + +static int rtsx_pci_ms_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct realtek_pci_ms *host = platform_get_drvdata(pdev); + struct memstick_host *msh = host->msh; + + dev_dbg(ms_dev(host), "--> %s\n", __func__); + + memstick_suspend_host(msh); + return 0; +} + +static int rtsx_pci_ms_resume(struct platform_device *pdev) +{ + struct realtek_pci_ms *host = platform_get_drvdata(pdev); + struct memstick_host *msh = host->msh; + + dev_dbg(ms_dev(host), "--> %s\n", __func__); + + memstick_resume_host(msh); + return 0; +} + +#else /* CONFIG_PM */ + +#define rtsx_pci_ms_suspend NULL +#define rtsx_pci_ms_resume NULL + +#endif /* CONFIG_PM */ + +static void rtsx_pci_ms_card_event(struct platform_device *pdev) +{ + struct realtek_pci_ms *host = platform_get_drvdata(pdev); + + memstick_detect_change(host->msh); +} + +static int rtsx_pci_ms_drv_probe(struct platform_device *pdev) +{ + struct memstick_host *msh; + struct realtek_pci_ms *host; + struct rtsx_pcr *pcr; + struct pcr_handle *handle = pdev->dev.platform_data; + int rc; + + if (!handle) + return -ENXIO; + + pcr = handle->pcr; + if (!pcr) + return -ENXIO; + + dev_dbg(&(pdev->dev), + ": Realtek PCI-E Memstick controller found\n"); + + msh = memstick_alloc_host(sizeof(*host), &pdev->dev); + if (!msh) + return -ENOMEM; + + host = memstick_priv(msh); + host->pcr = pcr; + host->msh = msh; + host->pdev = pdev; + platform_set_drvdata(pdev, host); + pcr->slots[RTSX_MS_CARD].p_dev = pdev; + pcr->slots[RTSX_MS_CARD].card_event = rtsx_pci_ms_card_event; + + mutex_init(&host->host_mutex); + + INIT_WORK(&host->handle_req, rtsx_pci_ms_handle_req); + msh->request = rtsx_pci_ms_request; + msh->set_param = rtsx_pci_ms_set_param; + msh->caps = MEMSTICK_CAP_PAR4; + + rc = memstick_add_host(msh); + if (rc) { + memstick_free_host(msh); + return rc; + } + + return 0; +} + +static int rtsx_pci_ms_drv_remove(struct platform_device *pdev) +{ + struct realtek_pci_ms *host = platform_get_drvdata(pdev); + struct rtsx_pcr *pcr; + struct memstick_host *msh; + int rc; + + if (!host) + return 0; + + pcr = host->pcr; + pcr->slots[RTSX_MS_CARD].p_dev = NULL; + pcr->slots[RTSX_MS_CARD].card_event = NULL; + msh = host->msh; + host->eject = true; + + mutex_lock(&host->host_mutex); + if (host->req) { + dev_dbg(&(pdev->dev), + "%s: Controller removed during transfer\n", + dev_name(&msh->dev)); + + rtsx_pci_complete_unfinished_transfer(pcr); + + host->req->error = -ENOMEDIUM; + do { + rc = memstick_next_req(msh, &host->req); + if (!rc) + host->req->error = -ENOMEDIUM; + } while (!rc); + } + mutex_unlock(&host->host_mutex); + + memstick_remove_host(msh); + memstick_free_host(msh); + + platform_set_drvdata(pdev, NULL); + + dev_dbg(&(pdev->dev), + ": Realtek PCI-E Memstick controller has been removed\n"); + + return 0; +} + +static struct platform_device_id rtsx_pci_ms_ids[] = { + { + .name = DRV_NAME_RTSX_PCI_MS, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(platform, rtsx_pci_ms_ids); + +static struct platform_driver rtsx_pci_ms_driver = { + .probe = rtsx_pci_ms_drv_probe, + .remove = rtsx_pci_ms_drv_remove, + .id_table = rtsx_pci_ms_ids, + .suspend = rtsx_pci_ms_suspend, + .resume = rtsx_pci_ms_resume, + .driver = { + .owner = THIS_MODULE, + .name = DRV_NAME_RTSX_PCI_MS, + }, +}; +module_platform_driver(rtsx_pci_ms_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Wei WANG "); +MODULE_DESCRIPTION("Realtek PCI-E Memstick Card Host Driver"); -- cgit v0.10.2 From 04bfd1dfb2c0ef236553d205bd95be02792c3396 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 15 Nov 2012 17:32:53 -0800 Subject: drivers: mfd: fix dependencies for MFD_RTSX_PCI We need to include MFD_CORE if this option is enabled, otherwise we get build errors. Cc: Wei WANG Cc: Arnd Bergmann Cc: Borislav Petkov Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 867af07..2c10938 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -66,6 +66,7 @@ config MFD_SM501_GPIO config MFD_RTSX_PCI tristate "Support for Realtek PCI-E card reader" depends on PCI + select MFD_CORE help This supports for Realtek PCI-Express card reader including rts5209, rts5229, rtl8411, etc. Realtek card reader supports access to many -- cgit v0.10.2 From ebf1b764aa5cb3b4bfe2e96674f1b559f7c37e64 Mon Sep 17 00:00:00 2001 From: Mark Rusk Date: Tue, 6 Nov 2012 14:33:13 -0600 Subject: misc: hpilo: ignore auxiliary HP iLO BMC's This patch ignores auxiliary HP Lights-Out (iLO) management controllers. All HP iLO controllers that have had the PCI subsystem device ID set to 0x1979 by the BIOS are ignored. Also changes default number of channels to 16 and bumps the version of the module from 1.3 to 1.4. Signed-off-by: Mark Rusk ---- drivers/misc/hpilo.c | 15 +++++++++++---- 1 files changed, 11 insertions(+), 4 deletions(-) Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/hpilo.c b/drivers/misc/hpilo.c index 12ccdf9..b362d93 100644 --- a/drivers/misc/hpilo.c +++ b/drivers/misc/hpilo.c @@ -30,7 +30,7 @@ static struct class *ilo_class; static unsigned int ilo_major; -static unsigned int max_ccb = MIN_CCB; +static unsigned int max_ccb = 16; static char ilo_hwdev[MAX_ILO_DEV]; static inline int get_entry_id(int entry) @@ -725,6 +725,9 @@ static void ilo_remove(struct pci_dev *pdev) int i, minor; struct ilo_hwinfo *ilo_hw = pci_get_drvdata(pdev); + if (!ilo_hw) + return; + clear_device(ilo_hw); minor = MINOR(ilo_hw->cdev.dev); @@ -751,9 +754,13 @@ static void ilo_remove(struct pci_dev *pdev) static int __devinit ilo_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - int devnum, minor, start, error; + int devnum, minor, start, error = 0; struct ilo_hwinfo *ilo_hw; + /* Ignore subsystem_device = 0x1979 (set by BIOS) */ + if (pdev->subsystem_device == 0x1979) + goto out; + if (max_ccb > MAX_CCB) max_ccb = MAX_CCB; else if (max_ccb < MIN_CCB) @@ -892,14 +899,14 @@ static void __exit ilo_exit(void) class_destroy(ilo_class); } -MODULE_VERSION("1.3"); +MODULE_VERSION("1.4"); MODULE_ALIAS(ILO_NAME); MODULE_DESCRIPTION(ILO_NAME); MODULE_AUTHOR("David Altobelli "); MODULE_LICENSE("GPL v2"); module_param(max_ccb, uint, 0444); -MODULE_PARM_DESC(max_ccb, "Maximum number of HP iLO channels to attach (8)"); +MODULE_PARM_DESC(max_ccb, "Maximum number of HP iLO channels to attach (16)"); module_init(ilo_init); module_exit(ilo_exit); -- cgit v0.10.2 From 644a9d3b66e6983c2c1f3b24c3006d49b184c871 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 16 Nov 2012 17:17:50 +0800 Subject: misc: apds9802als: Fix the logic checking timeout in als_wait_for_data_ready() In the case of timeout waiting for data ready, the retry variable is -1. This also fixes a bug: current code returns -ETIMEDOUT if latest retry success ( which means retry is 0 when exiting the while loop ). Signed-off-by: Axel Lin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/apds9802als.c b/drivers/misc/apds9802als.c index 0314773..94923d2 100644 --- a/drivers/misc/apds9802als.c +++ b/drivers/misc/apds9802als.c @@ -68,7 +68,7 @@ static int als_wait_for_data_ready(struct device *dev) ret = i2c_smbus_read_byte_data(client, 0x86); } while (!(ret & 0x80) && retry--); - if (!retry) { + if (retry < 0) { dev_warn(dev, "timeout waiting for data ready\n"); return -ETIMEDOUT; } -- cgit v0.10.2 From 99ba2fd297ed475dc6782e9029d4da041a85706a Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 19 Nov 2012 10:19:46 -0200 Subject: w1: mxc_w1: Adapt the clock name to the new clock framework With the new i.mx clock framework the mxc_w1 clock is registered as: clk_register_clkdev(clk[owire_gate], NULL, "mxc_w1.0"); So we do not need to pass "owire" string and can use NULL instead. While at it, also fix the clock error handling code. Acked-by: Sascha Hauer Acked-by: Evgeniy Polyakov Signed-off-by: Fabio Estevam ----- Changes since v2: - Add Ack's Changes since v1: - Fix clock error handling drivers/w1/masters/mxc_w1.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/w1/masters/mxc_w1.c b/drivers/w1/masters/mxc_w1.c index 1cc61a7..12c1ab8 100644 --- a/drivers/w1/masters/mxc_w1.c +++ b/drivers/w1/masters/mxc_w1.c @@ -117,9 +117,9 @@ static int __devinit mxc_w1_probe(struct platform_device *pdev) if (!mdev) return -ENOMEM; - mdev->clk = clk_get(&pdev->dev, "owire"); - if (!mdev->clk) { - err = -ENODEV; + mdev->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(mdev->clk)) { + err = PTR_ERR(mdev->clk); goto failed_clk; } -- cgit v0.10.2 From fd21bfcc2d6e8b7fef20f05deef318b0ab7f8004 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 19 Nov 2012 10:19:48 -0200 Subject: w1: mxc_w1: Convert to platform driver Using module_platform_driver() makes the code smaller and cleaner. Signed-off-by: Fabio Estevam Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/w1/masters/mxc_w1.c b/drivers/w1/masters/mxc_w1.c index 12c1ab8..3fb6c24 100644 --- a/drivers/w1/masters/mxc_w1.c +++ b/drivers/w1/masters/mxc_w1.c @@ -191,21 +191,9 @@ static struct platform_driver mxc_w1_driver = { .name = "mxc_w1", }, .probe = mxc_w1_probe, - .remove = mxc_w1_remove, + .remove = __devexit_p(mxc_w1_remove), }; - -static int __init mxc_w1_init(void) -{ - return platform_driver_register(&mxc_w1_driver); -} - -static void mxc_w1_exit(void) -{ - platform_driver_unregister(&mxc_w1_driver); -} - -module_init(mxc_w1_init); -module_exit(mxc_w1_exit); +module_platform_driver(mxc_w1_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Freescale Semiconductors Inc"); -- cgit v0.10.2 From 128485daadc53ff0570132c0c3ed70a6f0610bf6 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 19 Nov 2012 10:19:47 -0200 Subject: w1: mxc_w1: Fix comment We are dealing with mxc_w1 registers. While at it use dev_err() instead. Signed-off-by: Fabio Estevam Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/w1/masters/mxc_w1.c b/drivers/w1/masters/mxc_w1.c index 3fb6c24..53f89fa 100644 --- a/drivers/w1/masters/mxc_w1.c +++ b/drivers/w1/masters/mxc_w1.c @@ -134,7 +134,7 @@ static int __devinit mxc_w1_probe(struct platform_device *pdev) mdev->regs = ioremap(res->start, resource_size(res)); if (!mdev->regs) { - printk(KERN_ERR "Cannot map frame buffer registers\n"); + dev_err(&pdev->dev, "Cannot map mxc_w1 registers\n"); goto failed_ioremap; } -- cgit v0.10.2 From f91a66c97b38a504827803bb93f83a7b85e50e5a Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 19 Nov 2012 13:21:14 -0500 Subject: w1: remove use of __devexit_p CONFIG_HOTPLUG is going away as an option so __devexit_p is no longer needed. Signed-off-by: Bill Pemberton Cc: Evgeniy Polyakov Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/w1/masters/matrox_w1.c b/drivers/w1/masters/matrox_w1.c index f667c26..0a3c423 100644 --- a/drivers/w1/masters/matrox_w1.c +++ b/drivers/w1/masters/matrox_w1.c @@ -55,7 +55,7 @@ static struct pci_driver matrox_w1_pci_driver = { .name = "matrox_w1", .id_table = matrox_w1_tbl, .probe = matrox_w1_probe, - .remove = __devexit_p(matrox_w1_remove), + .remove = matrox_w1_remove, }; /* diff --git a/drivers/w1/masters/omap_hdq.c b/drivers/w1/masters/omap_hdq.c index ca8e60b..652ca7f 100644 --- a/drivers/w1/masters/omap_hdq.c +++ b/drivers/w1/masters/omap_hdq.c @@ -74,7 +74,7 @@ static int __devexit omap_hdq_remove(struct platform_device *pdev); static struct platform_driver omap_hdq_driver = { .probe = omap_hdq_probe, - .remove = __devexit_p(omap_hdq_remove), + .remove = omap_hdq_remove, .driver = { .name = "omap_hdq", }, -- cgit v0.10.2 From 479e2bcecdf19ae44940d38248a3e2f9fd8f2c44 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 19 Nov 2012 13:21:43 -0500 Subject: w1: remove use of __devinit CONFIG_HOTPLUG is going away as an option so __devinit is no longer needed. Signed-off-by: Bill Pemberton Cc: Evgeniy Polyakov Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/w1/masters/matrox_w1.c b/drivers/w1/masters/matrox_w1.c index 0a3c423..1197f7e 100644 --- a/drivers/w1/masters/matrox_w1.c +++ b/drivers/w1/masters/matrox_w1.c @@ -48,7 +48,7 @@ static struct pci_device_id matrox_w1_tbl[] = { }; MODULE_DEVICE_TABLE(pci, matrox_w1_tbl); -static int __devinit matrox_w1_probe(struct pci_dev *, const struct pci_device_id *); +static int matrox_w1_probe(struct pci_dev *, const struct pci_device_id *); static void __devexit matrox_w1_remove(struct pci_dev *); static struct pci_driver matrox_w1_pci_driver = { @@ -152,7 +152,7 @@ static void matrox_w1_hw_init(struct matrox_device *dev) matrox_w1_write_reg(dev, MATROX_GET_CONTROL, 0x00); } -static int __devinit matrox_w1_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +static int matrox_w1_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct matrox_device *dev; int err; diff --git a/drivers/w1/masters/mxc_w1.c b/drivers/w1/masters/mxc_w1.c index 53f89fa..23d3917 100644 --- a/drivers/w1/masters/mxc_w1.c +++ b/drivers/w1/masters/mxc_w1.c @@ -103,7 +103,7 @@ static u8 mxc_w1_ds2_touch_bit(void *data, u8 bit) return ((__raw_readb(ctrl_addr)) >> 3) & 0x1; } -static int __devinit mxc_w1_probe(struct platform_device *pdev) +static int mxc_w1_probe(struct platform_device *pdev) { struct mxc_w1_device *mdev; struct resource *res; diff --git a/drivers/w1/masters/omap_hdq.c b/drivers/w1/masters/omap_hdq.c index 652ca7f..d3bdcc3 100644 --- a/drivers/w1/masters/omap_hdq.c +++ b/drivers/w1/masters/omap_hdq.c @@ -69,7 +69,7 @@ struct hdq_data { int init_trans; }; -static int __devinit omap_hdq_probe(struct platform_device *pdev); +static int omap_hdq_probe(struct platform_device *pdev); static int __devexit omap_hdq_remove(struct platform_device *pdev); static struct platform_driver omap_hdq_driver = { @@ -537,7 +537,7 @@ static void omap_w1_write_byte(void *_hdq, u8 byte) } } -static int __devinit omap_hdq_probe(struct platform_device *pdev) +static int omap_hdq_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct hdq_data *hdq_data; -- cgit v0.10.2 From 82849a93aad04c5a438d811081341b245fdade8c Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 19 Nov 2012 13:26:23 -0500 Subject: w1: remove use of __devexit CONFIG_HOTPLUG is going away as an option so __devexit is no longer needed. Signed-off-by: Bill Pemberton Cc: Evgeniy Polyakov Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/w1/masters/matrox_w1.c b/drivers/w1/masters/matrox_w1.c index 1197f7e..d8667b0 100644 --- a/drivers/w1/masters/matrox_w1.c +++ b/drivers/w1/masters/matrox_w1.c @@ -49,7 +49,7 @@ static struct pci_device_id matrox_w1_tbl[] = { MODULE_DEVICE_TABLE(pci, matrox_w1_tbl); static int matrox_w1_probe(struct pci_dev *, const struct pci_device_id *); -static void __devexit matrox_w1_remove(struct pci_dev *); +static void matrox_w1_remove(struct pci_dev *); static struct pci_driver matrox_w1_pci_driver = { .name = "matrox_w1", @@ -220,7 +220,7 @@ err_out_free_device: return err; } -static void __devexit matrox_w1_remove(struct pci_dev *pdev) +static void matrox_w1_remove(struct pci_dev *pdev) { struct matrox_device *dev = pci_get_drvdata(pdev); diff --git a/drivers/w1/masters/mxc_w1.c b/drivers/w1/masters/mxc_w1.c index 23d3917..d338b56 100644 --- a/drivers/w1/masters/mxc_w1.c +++ b/drivers/w1/masters/mxc_w1.c @@ -167,7 +167,7 @@ failed_clk: /* * disassociate the w1 device from the driver */ -static int __devexit mxc_w1_remove(struct platform_device *pdev) +static int mxc_w1_remove(struct platform_device *pdev) { struct mxc_w1_device *mdev = platform_get_drvdata(pdev); struct resource *res; diff --git a/drivers/w1/masters/omap_hdq.c b/drivers/w1/masters/omap_hdq.c index d3bdcc3..184dbce 100644 --- a/drivers/w1/masters/omap_hdq.c +++ b/drivers/w1/masters/omap_hdq.c @@ -70,7 +70,7 @@ struct hdq_data { }; static int omap_hdq_probe(struct platform_device *pdev); -static int __devexit omap_hdq_remove(struct platform_device *pdev); +static int omap_hdq_remove(struct platform_device *pdev); static struct platform_driver omap_hdq_driver = { .probe = omap_hdq_probe, @@ -613,7 +613,7 @@ err_w1: return ret; } -static int __devexit omap_hdq_remove(struct platform_device *pdev) +static int omap_hdq_remove(struct platform_device *pdev) { struct hdq_data *hdq_data = platform_get_drvdata(pdev); -- cgit v0.10.2 From 2c9e9fdc0b2d55886609f0503fb91f96dfec6948 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 19 Nov 2012 13:19:15 -0500 Subject: w1: remove CONFIG_HOTPLUG ifdefs Remove conditional code based on CONFIG_HOTPLUG being false. It's always on now in preparation of it going away as an option. Signed-off-by: Bill Pemberton Cc: Evgeniy Polyakov Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index 1a57437..7994d933 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c @@ -551,7 +551,6 @@ void w1_destroy_master_attributes(struct w1_master *master) sysfs_remove_group(&master->dev.kobj, &w1_master_defattr_group); } -#ifdef CONFIG_HOTPLUG static int w1_uevent(struct device *dev, struct kobj_uevent_env *env) { struct w1_master *md = NULL; @@ -587,12 +586,6 @@ static int w1_uevent(struct device *dev, struct kobj_uevent_env *env) end: return err; } -#else -static int w1_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - return 0; -} -#endif static int __w1_attach_slave_device(struct w1_slave *sl) { -- cgit v0.10.2 From 5bd647144151082f0e8beb58741e27e6dbd23827 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sun, 18 Nov 2012 15:13:14 +0200 Subject: mei: compact code for mei bus message creation 1. replace boilerplate code for filling up the bus message header with a common wrapper function 2. shorten variable names and use temporal variables to save some screen space Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index 4fcb0bb..02784af 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c @@ -43,6 +43,7 @@ const char *mei_dev_state_str(int state) } + /** * mei_io_list_flush - removes list entry belonging to cl. * @@ -331,25 +332,20 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled) void mei_host_start_message(struct mei_device *dev) { struct mei_msg_hdr *mei_hdr; - struct hbm_host_version_request *host_start_req; + struct hbm_host_version_request *start_req; + const size_t len = sizeof(struct hbm_host_version_request); + + mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len); /* host start message */ - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; - mei_hdr->host_addr = 0; - mei_hdr->me_addr = 0; - mei_hdr->length = sizeof(struct hbm_host_version_request); - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - - host_start_req = - (struct hbm_host_version_request *) &dev->wr_msg_buf[1]; - memset(host_start_req, 0, sizeof(struct hbm_host_version_request)); - host_start_req->hbm_cmd = HOST_START_REQ_CMD; - host_start_req->host_version.major_version = HBM_MAJOR_VERSION; - host_start_req->host_version.minor_version = HBM_MINOR_VERSION; + start_req = (struct hbm_host_version_request *)&dev->wr_msg_buf[1]; + memset(start_req, 0, len); + start_req->hbm_cmd = HOST_START_REQ_CMD; + start_req->host_version.major_version = HBM_MAJOR_VERSION; + start_req->host_version.minor_version = HBM_MINOR_VERSION; + dev->recvd_msg = false; - if (mei_write_message(dev, mei_hdr, (unsigned char *)host_start_req, - mei_hdr->length)) { + if (mei_write_message(dev, mei_hdr, (unsigned char *)start_req, len)) { dev_dbg(&dev->pdev->dev, "write send version message to FW fail.\n"); dev->dev_state = MEI_DEV_RESETING; mei_reset(dev, 1); @@ -369,20 +365,16 @@ void mei_host_start_message(struct mei_device *dev) void mei_host_enum_clients_message(struct mei_device *dev) { struct mei_msg_hdr *mei_hdr; - struct hbm_host_enum_request *host_enum_req; - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; + struct hbm_host_enum_request *enum_req; + const size_t len = sizeof(struct hbm_host_enum_request); /* enumerate clients */ - mei_hdr->host_addr = 0; - mei_hdr->me_addr = 0; - mei_hdr->length = sizeof(struct hbm_host_enum_request); - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - - host_enum_req = (struct hbm_host_enum_request *) &dev->wr_msg_buf[1]; - memset(host_enum_req, 0, sizeof(struct hbm_host_enum_request)); - host_enum_req->hbm_cmd = HOST_ENUM_REQ_CMD; - if (mei_write_message(dev, mei_hdr, (unsigned char *)host_enum_req, - mei_hdr->length)) { + mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len); + + enum_req = (struct hbm_host_enum_request *) &dev->wr_msg_buf[1]; + memset(enum_req, 0, sizeof(struct hbm_host_enum_request)); + enum_req->hbm_cmd = HOST_ENUM_REQ_CMD; + + if (mei_write_message(dev, mei_hdr, (unsigned char *)enum_req, len)) { dev->dev_state = MEI_DEV_RESETING; dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n"); mei_reset(dev, 1); @@ -443,33 +435,31 @@ void mei_allocate_me_clients_storage(struct mei_device *dev) */ int mei_host_client_properties(struct mei_device *dev) { - struct mei_msg_hdr *mei_header; - struct hbm_props_request *host_cli_req; + + struct mei_msg_hdr *mei_hdr; + struct hbm_props_request *prop_req; + const size_t len = sizeof(struct hbm_props_request); + int b; u8 client_num = dev->me_client_presentation_num; + prop_req = (struct hbm_props_request *)&dev->wr_msg_buf[1]; + b = dev->me_client_index; b = find_next_bit(dev->me_clients_map, MEI_CLIENTS_MAX, b); if (b < MEI_CLIENTS_MAX) { dev->me_clients[client_num].client_id = b; dev->me_clients[client_num].mei_flow_ctrl_creds = 0; - mei_header = (struct mei_msg_hdr *)&dev->wr_msg_buf[0]; - mei_header->host_addr = 0; - mei_header->me_addr = 0; - mei_header->length = sizeof(struct hbm_props_request); - mei_header->msg_complete = 1; - mei_header->reserved = 0; + mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len); - host_cli_req = (struct hbm_props_request *)&dev->wr_msg_buf[1]; - memset(host_cli_req, 0, sizeof(struct hbm_props_request)); + memset(prop_req, 0, sizeof(struct hbm_props_request)); - host_cli_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD; - host_cli_req->address = b; + prop_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD; + prop_req->address = b; - if (mei_write_message(dev, mei_header, - (unsigned char *)host_cli_req, - mei_header->length)) { + if (mei_write_message(dev, mei_hdr, + (unsigned char *)prop_req, len)) { dev->dev_state = MEI_DEV_RESETING; dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n"); mei_reset(dev, 1); diff --git a/drivers/misc/mei/interface.c b/drivers/misc/mei/interface.c index 6b50cf0..8de8547 100644 --- a/drivers/misc/mei/interface.c +++ b/drivers/misc/mei/interface.c @@ -292,28 +292,23 @@ int mei_flow_ctrl_reduce(struct mei_device *dev, struct mei_cl *cl) int mei_send_flow_control(struct mei_device *dev, struct mei_cl *cl) { struct mei_msg_hdr *mei_hdr; - struct hbm_flow_control *mei_flow_control; - - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; - mei_hdr->host_addr = 0; - mei_hdr->me_addr = 0; - mei_hdr->length = sizeof(struct hbm_flow_control); - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - - mei_flow_control = (struct hbm_flow_control *) &dev->wr_msg_buf[1]; - memset(mei_flow_control, 0, sizeof(*mei_flow_control)); - mei_flow_control->host_addr = cl->host_client_id; - mei_flow_control->me_addr = cl->me_client_id; - mei_flow_control->hbm_cmd = MEI_FLOW_CONTROL_CMD; - memset(mei_flow_control->reserved, 0, - sizeof(mei_flow_control->reserved)); + struct hbm_flow_control *flow_ctrl; + const size_t len = sizeof(struct hbm_flow_control); + + mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len); + + flow_ctrl = (struct hbm_flow_control *)&dev->wr_msg_buf[1]; + memset(flow_ctrl, 0, len); + flow_ctrl->hbm_cmd = MEI_FLOW_CONTROL_CMD; + flow_ctrl->host_addr = cl->host_client_id; + flow_ctrl->me_addr = cl->me_client_id; + /* FIXME: reserved !? */ + memset(flow_ctrl->reserved, 0, sizeof(flow_ctrl->reserved)); dev_dbg(&dev->pdev->dev, "sending flow control host client = %d, ME client = %d\n", cl->host_client_id, cl->me_client_id); return mei_write_message(dev, mei_hdr, - (unsigned char *) mei_flow_control, - sizeof(struct hbm_flow_control)); + (unsigned char *) flow_ctrl, len); } /** @@ -353,23 +348,18 @@ int mei_disconnect(struct mei_device *dev, struct mei_cl *cl) { struct mei_msg_hdr *mei_hdr; struct hbm_client_connect_request *req; + const size_t len = sizeof(struct hbm_client_connect_request); - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; - mei_hdr->host_addr = 0; - mei_hdr->me_addr = 0; - mei_hdr->length = sizeof(struct hbm_client_connect_request); - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; + mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len); req = (struct hbm_client_connect_request *)&dev->wr_msg_buf[1]; - memset(req, 0, sizeof(*req)); + memset(req, 0, len); + req->hbm_cmd = CLIENT_DISCONNECT_REQ_CMD; req->host_addr = cl->host_client_id; req->me_addr = cl->me_client_id; - req->hbm_cmd = CLIENT_DISCONNECT_REQ_CMD; req->reserved = 0; - return mei_write_message(dev, mei_hdr, (unsigned char *)req, - sizeof(struct hbm_client_connect_request)); + return mei_write_message(dev, mei_hdr, (unsigned char *)req, len); } /** @@ -383,23 +373,16 @@ int mei_disconnect(struct mei_device *dev, struct mei_cl *cl) int mei_connect(struct mei_device *dev, struct mei_cl *cl) { struct mei_msg_hdr *mei_hdr; - struct hbm_client_connect_request *mei_cli_connect; - - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; - mei_hdr->host_addr = 0; - mei_hdr->me_addr = 0; - mei_hdr->length = sizeof(struct hbm_client_connect_request); - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - - mei_cli_connect = - (struct hbm_client_connect_request *) &dev->wr_msg_buf[1]; - mei_cli_connect->host_addr = cl->host_client_id; - mei_cli_connect->me_addr = cl->me_client_id; - mei_cli_connect->hbm_cmd = CLIENT_CONNECT_REQ_CMD; - mei_cli_connect->reserved = 0; + struct hbm_client_connect_request *req; + const size_t len = sizeof(struct hbm_client_connect_request); - return mei_write_message(dev, mei_hdr, - (unsigned char *) mei_cli_connect, - sizeof(struct hbm_client_connect_request)); + mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len); + + req = (struct hbm_client_connect_request *) &dev->wr_msg_buf[1]; + req->hbm_cmd = CLIENT_CONNECT_REQ_CMD; + req->host_addr = cl->host_client_id; + req->me_addr = cl->me_client_id; + req->reserved = 0; + + return mei_write_message(dev, mei_hdr, (unsigned char *) req, len); } diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index f882101..14becc0 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -429,39 +429,30 @@ static int same_disconn_addr(struct mei_cl *cl, static void mei_client_disconnect_request(struct mei_device *dev, struct hbm_client_connect_request *disconnect_req) { - struct mei_msg_hdr *mei_hdr; struct hbm_client_connect_response *disconnect_res; - struct mei_cl *cl_pos = NULL; - struct mei_cl *cl_next = NULL; + struct mei_cl *pos, *next; + const size_t len = sizeof(struct hbm_client_connect_response); - list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) { - if (same_disconn_addr(cl_pos, disconnect_req)) { + list_for_each_entry_safe(pos, next, &dev->file_list, link) { + if (same_disconn_addr(pos, disconnect_req)) { dev_dbg(&dev->pdev->dev, "disconnect request host client %d ME client %d.\n", disconnect_req->host_addr, disconnect_req->me_addr); - cl_pos->state = MEI_FILE_DISCONNECTED; - cl_pos->timer_count = 0; - if (cl_pos == &dev->wd_cl) + pos->state = MEI_FILE_DISCONNECTED; + pos->timer_count = 0; + if (pos == &dev->wd_cl) dev->wd_pending = false; - else if (cl_pos == &dev->iamthif_cl) + else if (pos == &dev->iamthif_cl) dev->iamthif_timer = 0; /* prepare disconnect response */ - mei_hdr = - (struct mei_msg_hdr *) &dev->ext_msg_buf[0]; - mei_hdr->host_addr = 0; - mei_hdr->me_addr = 0; - mei_hdr->length = - sizeof(struct hbm_client_connect_response); - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - + (void)mei_hbm_hdr(&dev->ext_msg_buf[0], len); disconnect_res = (struct hbm_client_connect_response *) &dev->ext_msg_buf[1]; - disconnect_res->host_addr = cl_pos->host_client_id; - disconnect_res->me_addr = cl_pos->me_client_id; disconnect_res->hbm_cmd = CLIENT_DISCONNECT_RES_CMD; + disconnect_res->host_addr = pos->host_client_id; + disconnect_res->me_addr = pos->me_client_id; disconnect_res->status = 0; dev->extra_write_index = 2; break; @@ -469,7 +460,6 @@ static void mei_client_disconnect_request(struct mei_device *dev, } } - /** * mei_irq_thread_read_bus_message - bottom half read routine after ISR to * handle the read bus message cmd processing. @@ -488,7 +478,7 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, struct hbm_flow_control *flow_control; struct hbm_props_response *props_res; struct hbm_host_enum_response *enum_res; - struct hbm_host_stop_request *host_stop_req; + struct hbm_host_stop_request *stop_req; int res; @@ -514,26 +504,20 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, return; } } else { + u32 *buf = dev->wr_msg_buf; + const size_t len = sizeof(struct hbm_host_stop_request); + dev->version = version_res->me_max_version; + /* send stop message */ - mei_hdr = (struct mei_msg_hdr *)&dev->wr_msg_buf[0]; - mei_hdr->host_addr = 0; - mei_hdr->me_addr = 0; - mei_hdr->length = sizeof(struct hbm_host_stop_request); - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - - host_stop_req = (struct hbm_host_stop_request *) - &dev->wr_msg_buf[1]; - - memset(host_stop_req, - 0, - sizeof(struct hbm_host_stop_request)); - host_stop_req->hbm_cmd = HOST_STOP_REQ_CMD; - host_stop_req->reason = DRIVER_STOP_REQUEST; + mei_hdr = mei_hbm_hdr(&buf[0], len); + stop_req = (struct hbm_host_stop_request *)&buf[1]; + memset(stop_req, 0, len); + stop_req->hbm_cmd = HOST_STOP_REQ_CMD; + stop_req->reason = DRIVER_STOP_REQUEST; + mei_write_message(dev, mei_hdr, - (unsigned char *) (host_stop_req), - mei_hdr->length); + (unsigned char *)stop_req, len); dev_dbg(&dev->pdev->dev, "version mismatch.\n"); return; } @@ -543,16 +527,14 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, break; case CLIENT_CONNECT_RES_CMD: - connect_res = - (struct hbm_client_connect_response *) mei_msg; + connect_res = (struct hbm_client_connect_response *) mei_msg; mei_client_connect_response(dev, connect_res); dev_dbg(&dev->pdev->dev, "client connect response message received.\n"); wake_up(&dev->wait_recvd_msg); break; case CLIENT_DISCONNECT_RES_CMD: - disconnect_res = - (struct hbm_client_connect_response *) mei_msg; + disconnect_res = (struct hbm_client_connect_response *) mei_msg; mei_client_disconnect_response(dev, disconnect_res); dev_dbg(&dev->pdev->dev, "client disconnect response message received.\n"); wake_up(&dev->wait_recvd_msg); @@ -658,23 +640,21 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, break; case ME_STOP_REQ_CMD: - /* prepare stop request */ - mei_hdr = (struct mei_msg_hdr *) &dev->ext_msg_buf[0]; - mei_hdr->host_addr = 0; - mei_hdr->me_addr = 0; - mei_hdr->length = sizeof(struct hbm_host_stop_request); - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - host_stop_req = - (struct hbm_host_stop_request *) &dev->ext_msg_buf[1]; - memset(host_stop_req, 0, sizeof(struct hbm_host_stop_request)); - host_stop_req->hbm_cmd = HOST_STOP_REQ_CMD; - host_stop_req->reason = DRIVER_STOP_REQUEST; - host_stop_req->reserved[0] = 0; - host_stop_req->reserved[1] = 0; + { + /* prepare stop request: sent in next interrupt event */ + + u32 *buf = dev->ext_msg_buf; + const size_t len = sizeof(struct hbm_host_stop_request); + + mei_hdr = mei_hbm_hdr(&buf[0], len); + stop_req = (struct hbm_host_stop_request *)&buf[1]; + memset(stop_req, 0, len); + stop_req->hbm_cmd = HOST_STOP_REQ_CMD; + stop_req->reason = DRIVER_STOP_REQUEST; + dev->extra_write_index = 2; break; - + } default: BUG(); break; diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index aaee666..e511b84 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -491,4 +491,15 @@ void mei_csr_clear_his(struct mei_device *dev); void mei_enable_interrupts(struct mei_device *dev); void mei_disable_interrupts(struct mei_device *dev); +static inline struct mei_msg_hdr *mei_hbm_hdr(u32 *buf, size_t length) +{ + struct mei_msg_hdr *hdr = (struct mei_msg_hdr *)buf; + hdr->host_addr = 0; + hdr->me_addr = 0; + hdr->length = length; + hdr->msg_complete = 1; + hdr->reserved = 0; + return hdr; +} + #endif -- cgit v0.10.2 From 5fb54fb456f77128f817ab3491d6b131bec480b5 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sun, 18 Nov 2012 15:13:15 +0200 Subject: mei: use structured buffer for extra write buffer The structure of the message is static so we don't have to use and cast the buffer. We can also drop extra_write_index variable as this information can be extracted directly from the message header Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index 02784af..49600d6 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c @@ -288,7 +288,7 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled) mei_me_cl_unlink(dev, &dev->iamthif_cl); mei_amthif_reset_params(dev); - dev->extra_write_index = 0; + memset(&dev->wr_ext_msg, 0, sizeof(dev->wr_ext_msg)); } dev->me_clients_num = 0; diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 14becc0..9224646 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -446,15 +446,14 @@ static void mei_client_disconnect_request(struct mei_device *dev, dev->iamthif_timer = 0; /* prepare disconnect response */ - (void)mei_hbm_hdr(&dev->ext_msg_buf[0], len); + (void)mei_hbm_hdr((u32 *)&dev->wr_ext_msg.hdr, len); disconnect_res = (struct hbm_client_connect_response *) - &dev->ext_msg_buf[1]; + &dev->wr_ext_msg.data; disconnect_res->hbm_cmd = CLIENT_DISCONNECT_RES_CMD; disconnect_res->host_addr = pos->host_client_id; disconnect_res->me_addr = pos->me_client_id; disconnect_res->status = 0; - dev->extra_write_index = 2; break; } } @@ -643,16 +642,13 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, { /* prepare stop request: sent in next interrupt event */ - u32 *buf = dev->ext_msg_buf; const size_t len = sizeof(struct hbm_host_stop_request); - mei_hdr = mei_hbm_hdr(&buf[0], len); - stop_req = (struct hbm_host_stop_request *)&buf[1]; + mei_hdr = mei_hbm_hdr((u32 *)&dev->wr_ext_msg.hdr, len); + stop_req = (struct hbm_host_stop_request *)&dev->wr_ext_msg.data; memset(stop_req, 0, len); stop_req->hbm_cmd = HOST_STOP_REQ_CMD; stop_req->reason = DRIVER_STOP_REQUEST; - - dev->extra_write_index = 2; break; } default: @@ -988,15 +984,11 @@ static int mei_irq_thread_write_handler(struct mei_cl_cb *cmpl_list, wake_up_interruptible(&dev->wait_stop_wd); } - if (dev->extra_write_index) { - dev_dbg(&dev->pdev->dev, "extra_write_index =%d.\n", - dev->extra_write_index); - mei_write_message(dev, - (struct mei_msg_hdr *) &dev->ext_msg_buf[0], - (unsigned char *) &dev->ext_msg_buf[1], - (dev->extra_write_index - 1) * sizeof(u32)); - *slots -= dev->extra_write_index; - dev->extra_write_index = 0; + if (dev->wr_ext_msg.hdr.length) { + mei_write_message(dev, &dev->wr_ext_msg.hdr, + dev->wr_ext_msg.data, dev->wr_ext_msg.hdr.length); + *slots -= mei_data2slots(dev->wr_ext_msg.hdr.length); + dev->wr_ext_msg.hdr.length = 0; } if (dev->dev_state == MEI_DEV_ENABLED) { if (dev->wd_pending && @@ -1263,11 +1255,11 @@ irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id) } /* check slots available for reading */ slots = mei_count_full_read_slots(dev); - dev_dbg(&dev->pdev->dev, "slots =%08x extra_write_index =%08x.\n", - slots, dev->extra_write_index); - while (slots > 0 && !dev->extra_write_index) { - dev_dbg(&dev->pdev->dev, "slots =%08x extra_write_index =%08x.\n", - slots, dev->extra_write_index); + while (slots > 0) { + /* we have urgent data to send so break the read */ + if (dev->wr_ext_msg.hdr.length) + break; + dev_dbg(&dev->pdev->dev, "slots =%08x\n", slots); dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_handler.\n"); rets = mei_irq_thread_read_handler(&complete_list, dev, &slots); if (rets) diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index e511b84..2a38e95 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -192,8 +192,9 @@ struct mei_cl { }; /** - * struct mei_deive - MEI private device struct + * struct mei_device - MEI private device struct * @hbuf_depth - depth of host(write) buffer + * @wr_ext_msg - buffer for hbm control responses (set in read cycle) */ struct mei_device { struct pci_dev *pdev; /* pointer to pci device struct */ @@ -244,11 +245,13 @@ struct mei_device { u16 init_clients_timer; bool need_reset; - u32 extra_write_index; unsigned char rd_msg_buf[MEI_RD_MSG_BUF_SIZE]; /* control messages */ - u32 wr_msg_buf[128]; /* used for control messages */ - u32 ext_msg_buf[8]; /* for control responses */ u32 rd_msg_hdr; + u32 wr_msg_buf[128]; /* used for control messages */ + struct { + struct mei_msg_hdr hdr; + unsigned char data[4]; /* All HBM messages are 4 bytes */ + } wr_ext_msg; /* for control responses */ struct hbm_version version; -- cgit v0.10.2 From ea3b5fb710c6d0b61f4bfbbc48b34b99b9c89bae Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sun, 18 Nov 2012 15:13:16 +0200 Subject: mei: streamline write complete flow function Rename the function _mei_irq_thread_cmpl to mei_irq_thread_write_complete to make clear it deals with writing. Remove cl from the parameter list as it can be extracted from cb block. Extract the common flow from if statements and document the logic properly Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 9224646..85e2722 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -734,90 +734,63 @@ static int _mei_irq_thread_ioctl(struct mei_device *dev, s32 *slots, } /** - * _mei_irq_thread_cmpl - processes completed and no-iamthif operation. + * mei_irq_thread_write_complete - write messages to device. * * @dev: the device structure. * @slots: free slots. - * @cb_pos: callback block. - * @cl: private data of the file object. + * @cb: callback block. * @cmpl_list: complete list. * * returns 0, OK; otherwise, error. */ -static int _mei_irq_thread_cmpl(struct mei_device *dev, s32 *slots, - struct mei_cl_cb *cb_pos, - struct mei_cl *cl, - struct mei_cl_cb *cmpl_list) +static int mei_irq_thread_write_complete(struct mei_device *dev, s32 *slots, + struct mei_cl_cb *cb, struct mei_cl_cb *cmpl_list) { struct mei_msg_hdr *mei_hdr; + struct mei_cl *cl = cb->cl; + size_t len = cb->request_buffer.size - cb->buf_idx; + size_t msg_slots = mei_data2slots(len); + + mei_hdr = (struct mei_msg_hdr *)&dev->wr_msg_buf[0]; + mei_hdr->host_addr = cl->host_client_id; + mei_hdr->me_addr = cl->me_client_id; + mei_hdr->reserved = 0; - if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) + - (cb_pos->request_buffer.size - cb_pos->buf_idx))) { - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; - mei_hdr->host_addr = cl->host_client_id; - mei_hdr->me_addr = cl->me_client_id; - mei_hdr->length = cb_pos->request_buffer.size - cb_pos->buf_idx; + if (*slots >= msg_slots) { + mei_hdr->length = len; mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - dev_dbg(&dev->pdev->dev, "cb_pos->request_buffer.size =%d" - "mei_hdr->msg_complete = %d\n", - cb_pos->request_buffer.size, - mei_hdr->msg_complete); - dev_dbg(&dev->pdev->dev, "cb_pos->buf_idx =%lu\n", - cb_pos->buf_idx); - dev_dbg(&dev->pdev->dev, "mei_hdr->length =%d\n", - mei_hdr->length); - *slots -= mei_data2slots(mei_hdr->length); - if (mei_write_message(dev, mei_hdr, - (unsigned char *) - (cb_pos->request_buffer.data + - cb_pos->buf_idx), - mei_hdr->length)) { - cl->status = -ENODEV; - list_move_tail(&cb_pos->list, &cmpl_list->list); - return -ENODEV; - } else { - if (mei_flow_ctrl_reduce(dev, cl)) - return -ENODEV; - cl->status = 0; - cb_pos->buf_idx += mei_hdr->length; - list_move_tail(&cb_pos->list, &dev->write_waiting_list.list); - } + /* Split the message only if we can write the whole host buffer */ } else if (*slots == dev->hbuf_depth) { - /* buffer is still empty */ - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; - mei_hdr->host_addr = cl->host_client_id; - mei_hdr->me_addr = cl->me_client_id; - mei_hdr->length = - (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr); + msg_slots = *slots; + len = (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr); + mei_hdr->length = len; mei_hdr->msg_complete = 0; - mei_hdr->reserved = 0; - *slots -= mei_data2slots(mei_hdr->length); - if (mei_write_message(dev, mei_hdr, - (unsigned char *) - (cb_pos->request_buffer.data + - cb_pos->buf_idx), - mei_hdr->length)) { - cl->status = -ENODEV; - list_move_tail(&cb_pos->list, &cmpl_list->list); - return -ENODEV; - } else { - cb_pos->buf_idx += mei_hdr->length; - dev_dbg(&dev->pdev->dev, - "cb_pos->request_buffer.size =%d" - " mei_hdr->msg_complete = %d\n", - cb_pos->request_buffer.size, - mei_hdr->msg_complete); - dev_dbg(&dev->pdev->dev, "cb_pos->buf_idx =%lu\n", - cb_pos->buf_idx); - dev_dbg(&dev->pdev->dev, "mei_hdr->length =%d\n", - mei_hdr->length); - } - return -EMSGSIZE; } else { - return -EBADMSG; + /* wait for next time the host buffer is empty */ + return 0; } + dev_dbg(&dev->pdev->dev, "buf: size = %d idx = %lu\n", + cb->request_buffer.size, cb->buf_idx); + dev_dbg(&dev->pdev->dev, "msg: len = %d complete = %d\n", + mei_hdr->length, mei_hdr->msg_complete); + + *slots -= msg_slots; + if (mei_write_message(dev, mei_hdr, + cb->request_buffer.data + cb->buf_idx, len)) { + cl->status = -ENODEV; + list_move_tail(&cb->list, &cmpl_list->list); + return -ENODEV; + } + + if (mei_flow_ctrl_reduce(dev, cl)) + return -ENODEV; + + cl->status = 0; + cb->buf_idx += mei_hdr->length; + if (mei_hdr->msg_complete) + list_move_tail(&cb->list, &dev->write_waiting_list.list); + return 0; } @@ -1059,8 +1032,8 @@ static int mei_irq_thread_write_handler(struct mei_cl_cb *cmpl_list, cl->host_client_id); continue; } - ret = _mei_irq_thread_cmpl(dev, slots, pos, - cl, cmpl_list); + ret = mei_irq_thread_write_complete(dev, slots, pos, + cmpl_list); if (ret) return ret; -- cgit v0.10.2 From 24c656e55f3985b6f5c0e2264243f7076f376193 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sun, 18 Nov 2012 15:13:17 +0200 Subject: mei: streamline amthif write complete function Rename the function mei_amthif_irq_process_completed to mei_amthif_irq_write_complete Remove cl from the parameter list as it can be extracted from cb block. Extract the common flow from if statements and document the logic properly Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c index 095d059..18794ae 100644 --- a/drivers/misc/mei/amthif.c +++ b/drivers/misc/mei/amthif.c @@ -431,74 +431,64 @@ unsigned int mei_amthif_poll(struct mei_device *dev, * * returns 0, OK; otherwise, error. */ -int mei_amthif_irq_process_completed(struct mei_device *dev, s32 *slots, - struct mei_cl_cb *cb_pos, - struct mei_cl *cl, - struct mei_cl_cb *cmpl_list) +int mei_amthif_irq_write_complete(struct mei_device *dev, s32 *slots, + struct mei_cl_cb *cb, struct mei_cl_cb *cmpl_list) { struct mei_msg_hdr *mei_hdr; + struct mei_cl *cl = cb->cl; + size_t len = dev->iamthif_msg_buf_size - dev->iamthif_msg_buf_index; + size_t msg_slots = mei_data2slots(len); - if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) + - dev->iamthif_msg_buf_size - - dev->iamthif_msg_buf_index)) { - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; - mei_hdr->host_addr = cl->host_client_id; - mei_hdr->me_addr = cl->me_client_id; - mei_hdr->length = dev->iamthif_msg_buf_size - - dev->iamthif_msg_buf_index; + mei_hdr = (struct mei_msg_hdr *)&dev->wr_msg_buf[0]; + mei_hdr->host_addr = cl->host_client_id; + mei_hdr->me_addr = cl->me_client_id; + mei_hdr->reserved = 0; + + if (*slots >= msg_slots) { + mei_hdr->length = len; mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; + /* Split the message only if we can write the whole host buffer */ + } else if (*slots == dev->hbuf_depth) { + msg_slots = *slots; + len = (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr); + mei_hdr->length = len; + mei_hdr->msg_complete = 0; + } else { + /* wait for next time the host buffer is empty */ + return 0; + } - *slots -= mei_data2slots(mei_hdr->length); + dev_dbg(&dev->pdev->dev, "msg: len = %d complete = %d\n", + mei_hdr->length, mei_hdr->msg_complete); - if (mei_write_message(dev, mei_hdr, - (dev->iamthif_msg_buf + - dev->iamthif_msg_buf_index), - mei_hdr->length)) { + *slots -= msg_slots; + if (mei_write_message(dev, mei_hdr, + dev->iamthif_msg_buf + dev->iamthif_msg_buf_index, + mei_hdr->length)) { dev->iamthif_state = MEI_IAMTHIF_IDLE; cl->status = -ENODEV; - list_del(&cb_pos->list); + list_del(&cb->list); return -ENODEV; - } else { - if (mei_flow_ctrl_reduce(dev, cl)) - return -ENODEV; - dev->iamthif_msg_buf_index += mei_hdr->length; - cb_pos->buf_idx = dev->iamthif_msg_buf_index; - cl->status = 0; - dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL; - dev->iamthif_flow_control_pending = true; - /* save iamthif cb sent to amthi client */ - dev->iamthif_current_cb = cb_pos; - list_move_tail(&cb_pos->list, - &dev->write_waiting_list.list); + } - } - } else if (*slots == dev->hbuf_depth) { - /* buffer is still empty */ - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; - mei_hdr->host_addr = cl->host_client_id; - mei_hdr->me_addr = cl->me_client_id; - mei_hdr->length = - (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr); - mei_hdr->msg_complete = 0; - mei_hdr->reserved = 0; + if (mei_flow_ctrl_reduce(dev, cl)) + return -ENODEV; - *slots -= mei_data2slots(mei_hdr->length); + dev->iamthif_msg_buf_index += mei_hdr->length; + cl->status = 0; - if (mei_write_message(dev, mei_hdr, - (dev->iamthif_msg_buf + - dev->iamthif_msg_buf_index), - mei_hdr->length)) { - cl->status = -ENODEV; - list_del(&cb_pos->list); - } else { - dev->iamthif_msg_buf_index += mei_hdr->length; - } - return -EMSGSIZE; - } else { - return -EBADMSG; + if (mei_hdr->msg_complete) { + dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL; + dev->iamthif_flow_control_pending = true; + + /* save iamthif cb sent to amthi client */ + cb->buf_idx = dev->iamthif_msg_buf_index; + dev->iamthif_current_cb = cb; + + list_move_tail(&cb->list, &dev->write_waiting_list.list); } + return 0; } diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 85e2722..d30db38 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -1046,8 +1046,8 @@ static int mei_irq_thread_write_handler(struct mei_cl_cb *cmpl_list, cl->host_client_id); continue; } - ret = mei_amthif_irq_process_completed(dev, slots, pos, - cl, cmpl_list); + ret = mei_amthif_irq_write_complete(dev, slots, + pos, cmpl_list); if (ret) return ret; diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 2a38e95..17d00aa 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -407,10 +407,8 @@ void mei_amthif_run_next_cmd(struct mei_device *dev); int mei_amthif_read_message(struct mei_cl_cb *complete_list, struct mei_device *dev, struct mei_msg_hdr *mei_hdr); -int mei_amthif_irq_process_completed(struct mei_device *dev, s32 *slots, - struct mei_cl_cb *cb_pos, - struct mei_cl *cl, - struct mei_cl_cb *cmpl_list); +int mei_amthif_irq_write_complete(struct mei_device *dev, s32 *slots, + struct mei_cl_cb *cb, struct mei_cl_cb *cmpl_list); void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb); int mei_amthif_irq_read_message(struct mei_cl_cb *complete_list, -- cgit v0.10.2 From 9a84d616980215d1d9222173c60329b57680483b Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sun, 18 Nov 2012 15:13:18 +0200 Subject: mei: don't mix read and write slots Do not pass read slots pointer into function mei_irq_thread_write_handler, the write slots management is handled internally in the write handler Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index d30db38..cccb63a 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -901,27 +901,27 @@ end: * mei_irq_thread_write_handler - bottom half write routine after * ISR to handle the write processing. * - * @cmpl_list: An instance of our list structure * @dev: the device structure - * @slots: slots to write. + * @cmpl_list: An instance of our list structure * * returns 0 on success, <0 on failure. */ -static int mei_irq_thread_write_handler(struct mei_cl_cb *cmpl_list, - struct mei_device *dev, s32 *slots) +static int mei_irq_thread_write_handler(struct mei_device *dev, + struct mei_cl_cb *cmpl_list) { struct mei_cl *cl; struct mei_cl_cb *pos = NULL, *next = NULL; struct mei_cl_cb *list; + s32 slots; int ret; if (!mei_hbuf_is_empty(dev)) { dev_dbg(&dev->pdev->dev, "host buffer is not empty.\n"); return 0; } - *slots = mei_hbuf_empty_slots(dev); - if (*slots <= 0) + slots = mei_hbuf_empty_slots(dev); + if (slots <= 0) return -EMSGSIZE; /* complete all waiting for write CB */ @@ -945,7 +945,7 @@ static int mei_irq_thread_write_handler(struct mei_cl_cb *cmpl_list, if (cl == &dev->iamthif_cl) { dev_dbg(&dev->pdev->dev, "check iamthif flow control.\n"); if (dev->iamthif_flow_control_pending) { - ret = mei_amthif_irq_read(dev, slots); + ret = mei_amthif_irq_read(dev, &slots); if (ret) return ret; } @@ -960,7 +960,7 @@ static int mei_irq_thread_write_handler(struct mei_cl_cb *cmpl_list, if (dev->wr_ext_msg.hdr.length) { mei_write_message(dev, &dev->wr_ext_msg.hdr, dev->wr_ext_msg.data, dev->wr_ext_msg.hdr.length); - *slots -= mei_data2slots(dev->wr_ext_msg.hdr.length); + slots -= mei_data2slots(dev->wr_ext_msg.hdr.length); dev->wr_ext_msg.hdr.length = 0; } if (dev->dev_state == MEI_DEV_ENABLED) { @@ -974,9 +974,9 @@ static int mei_irq_thread_write_handler(struct mei_cl_cb *cmpl_list, dev->wd_pending = false; if (dev->wd_state == MEI_WD_RUNNING) - *slots -= mei_data2slots(MEI_WD_START_MSG_SIZE); + slots -= mei_data2slots(MEI_WD_START_MSG_SIZE); else - *slots -= mei_data2slots(MEI_WD_STOP_MSG_SIZE); + slots -= mei_data2slots(MEI_WD_STOP_MSG_SIZE); } } @@ -991,14 +991,16 @@ static int mei_irq_thread_write_handler(struct mei_cl_cb *cmpl_list, switch (pos->fop_type) { case MEI_FOP_CLOSE: /* send disconnect message */ - ret = _mei_irq_thread_close(dev, slots, pos, cl, cmpl_list); + ret = _mei_irq_thread_close(dev, &slots, pos, + cl, cmpl_list); if (ret) return ret; break; case MEI_FOP_READ: /* send flow control message */ - ret = _mei_irq_thread_read(dev, slots, pos, cl, cmpl_list); + ret = _mei_irq_thread_read(dev, &slots, pos, + cl, cmpl_list); if (ret) return ret; @@ -1007,7 +1009,8 @@ static int mei_irq_thread_write_handler(struct mei_cl_cb *cmpl_list, /* connect message */ if (mei_other_client_is_connecting(dev, cl)) continue; - ret = _mei_irq_thread_ioctl(dev, slots, pos, cl, cmpl_list); + ret = _mei_irq_thread_ioctl(dev, &slots, pos, + cl, cmpl_list); if (ret) return ret; @@ -1032,7 +1035,7 @@ static int mei_irq_thread_write_handler(struct mei_cl_cb *cmpl_list, cl->host_client_id); continue; } - ret = mei_irq_thread_write_complete(dev, slots, pos, + ret = mei_irq_thread_write_complete(dev, &slots, pos, cmpl_list); if (ret) return ret; @@ -1046,7 +1049,7 @@ static int mei_irq_thread_write_handler(struct mei_cl_cb *cmpl_list, cl->host_client_id); continue; } - ret = mei_amthif_irq_write_complete(dev, slots, + ret = mei_amthif_irq_write_complete(dev, &slots, pos, cmpl_list); if (ret) return ret; @@ -1238,7 +1241,7 @@ irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id) if (rets) goto end; } - rets = mei_irq_thread_write_handler(&complete_list, dev, &slots); + rets = mei_irq_thread_write_handler(dev, &complete_list); end: dev_dbg(&dev->pdev->dev, "end of bottom half function.\n"); dev->host_hw_state = mei_hcsr_read(dev); -- cgit v0.10.2 From be9d87a790765bcc85d8bdab8a9be31cf7457b28 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sun, 18 Nov 2012 15:13:19 +0200 Subject: mei: simplify write complete loop in irq handler extract the common, hence non conditional code from the if-else statment Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index cccb63a..e5aa0ed 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -1027,34 +1027,21 @@ static int mei_irq_thread_write_handler(struct mei_device *dev, cl = pos->cl; if (cl == NULL) continue; + if (mei_flow_ctrl_creds(dev, cl) <= 0) { + dev_dbg(&dev->pdev->dev, + "No flow control credentials for client %d, not sending.\n", + cl->host_client_id); + continue; + } - if (cl != &dev->iamthif_cl) { - if (mei_flow_ctrl_creds(dev, cl) <= 0) { - dev_dbg(&dev->pdev->dev, - "No flow control credentials for client %d, not sending.\n", - cl->host_client_id); - continue; - } - ret = mei_irq_thread_write_complete(dev, &slots, pos, - cmpl_list); - if (ret) - return ret; - - } else if (cl == &dev->iamthif_cl) { - /* IAMTHIF IOCTL */ - dev_dbg(&dev->pdev->dev, "complete amthi write cb.\n"); - if (mei_flow_ctrl_creds(dev, cl) <= 0) { - dev_dbg(&dev->pdev->dev, - "No flow control credentials for amthi client %d.\n", - cl->host_client_id); - continue; - } + if (cl == &dev->iamthif_cl) ret = mei_amthif_irq_write_complete(dev, &slots, pos, cmpl_list); - if (ret) - return ret; - - } + else + ret = mei_irq_thread_write_complete(dev, &slots, pos, + cmpl_list); + if (ret) + return ret; } return 0; -- cgit v0.10.2 From c1174c0edf546805a0ebc10d5d6154edbb56e1cf Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Sun, 18 Nov 2012 15:13:20 +0200 Subject: mei: Simplify the ME client enumeration code After enumerating all ME clients we call the client init functions for all matching UUIDs from a separate context. This remove the hackish cascading client initialisation process that was interleaving properties and connection command replies. Signed-off-by: Samuel Ortiz Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index 49600d6..a54cd55 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c @@ -423,54 +423,87 @@ void mei_allocate_me_clients_storage(struct mei_device *dev) dev->me_clients = clients; return ; } -/** - * host_client_properties - reads properties for client - * - * @dev: the device structure - * - * returns: - * < 0 - Error. - * = 0 - no more clients. - * = 1 - still have clients to send properties request. - */ -int mei_host_client_properties(struct mei_device *dev) + +void mei_host_client_init(struct work_struct *work) +{ + struct mei_device *dev = container_of(work, + struct mei_device, init_work); + struct mei_client_properties *client_props; + int i; + + mutex_lock(&dev->device_lock); + + bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX); + dev->open_handle_count = 0; + + /* + * Reserving the first three client IDs + * 0: Reserved for MEI Bus Message communications + * 1: Reserved for Watchdog + * 2: Reserved for AMTHI + */ + bitmap_set(dev->host_clients_map, 0, 3); + + for (i = 0; i < dev->me_clients_num; i++) { + client_props = &dev->me_clients[i].props; + + if (!uuid_le_cmp(client_props->protocol_name, mei_amthi_guid)) + mei_amthif_host_init(dev); + else if (!uuid_le_cmp(client_props->protocol_name, mei_wd_guid)) + mei_wd_host_init(dev); + } + + dev->dev_state = MEI_DEV_ENABLED; + + mutex_unlock(&dev->device_lock); +} + +int mei_host_client_enumerate(struct mei_device *dev) { struct mei_msg_hdr *mei_hdr; struct hbm_props_request *prop_req; const size_t len = sizeof(struct hbm_props_request); + unsigned long next_client_index; + u8 client_num; - int b; - u8 client_num = dev->me_client_presentation_num; - prop_req = (struct hbm_props_request *)&dev->wr_msg_buf[1]; + client_num = dev->me_client_presentation_num; - b = dev->me_client_index; - b = find_next_bit(dev->me_clients_map, MEI_CLIENTS_MAX, b); - if (b < MEI_CLIENTS_MAX) { - dev->me_clients[client_num].client_id = b; - dev->me_clients[client_num].mei_flow_ctrl_creds = 0; - mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len); + next_client_index = find_next_bit(dev->me_clients_map, MEI_CLIENTS_MAX, + dev->me_client_index); + /* We got all client properties */ + if (next_client_index == MEI_CLIENTS_MAX) { + schedule_work(&dev->init_work); - memset(prop_req, 0, sizeof(struct hbm_props_request)); + return 0; + } - prop_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD; - prop_req->address = b; + dev->me_clients[client_num].client_id = next_client_index; + dev->me_clients[client_num].mei_flow_ctrl_creds = 0; + + mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len); + prop_req = (struct hbm_props_request *)&dev->wr_msg_buf[1]; + + memset(prop_req, 0, sizeof(struct hbm_props_request)); - if (mei_write_message(dev, mei_hdr, - (unsigned char *)prop_req, len)) { - dev->dev_state = MEI_DEV_RESETING; - dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n"); - mei_reset(dev, 1); - return -EIO; - } - dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; - dev->me_client_index = b; - return 1; + prop_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD; + prop_req->address = next_client_index; + + if (mei_write_message(dev, mei_hdr, (unsigned char *) prop_req, + mei_hdr->length)) { + dev->dev_state = MEI_DEV_RESETING; + dev_err(&dev->pdev->dev, "Properties request command failed\n"); + mei_reset(dev, 1); + + return -EIO; } + dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; + dev->me_client_index = next_client_index; + return 0; } diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index e5aa0ed..04fa213 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -252,8 +252,6 @@ static void mei_client_connect_response(struct mei_device *dev, dev_dbg(&dev->pdev->dev, "successfully connected to WD client.\n"); mei_watchdog_register(dev); - /* next step in the state maching */ - mei_amthif_host_init(dev); return; } @@ -470,6 +468,7 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, struct mei_msg_hdr *mei_hdr) { struct mei_bus_message *mei_msg; + struct mei_me_client *me_client; struct hbm_host_version_response *version_res; struct hbm_client_connect_response *connect_res; struct hbm_client_connect_response *disconnect_res; @@ -478,8 +477,6 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, struct hbm_props_response *props_res; struct hbm_host_enum_response *enum_res; struct hbm_host_stop_request *stop_req; - int res; - /* read the message to our buffer */ BUG_ON(mei_hdr->length >= sizeof(dev->rd_msg_buf)); @@ -547,64 +544,37 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, case HOST_CLIENT_PROPERTIES_RES_CMD: props_res = (struct hbm_props_response *)mei_msg; + me_client = &dev->me_clients[dev->me_client_presentation_num]; + if (props_res->status || !dev->me_clients) { dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message wrong status.\n"); mei_reset(dev, 1); return; } - if (dev->me_clients[dev->me_client_presentation_num] - .client_id == props_res->address) { - dev->me_clients[dev->me_client_presentation_num].props - = props_res->client_properties; + if (me_client->client_id != props_res->address) { + dev_err(&dev->pdev->dev, + "Host client properties reply mismatch\n"); + mei_reset(dev, 1); - if (dev->dev_state == MEI_DEV_INIT_CLIENTS && - dev->init_clients_state == - MEI_CLIENT_PROPERTIES_MESSAGE) { - dev->me_client_index++; - dev->me_client_presentation_num++; - - /** Send Client Properties request **/ - res = mei_host_client_properties(dev); - if (res < 0) { - dev_dbg(&dev->pdev->dev, "mei_host_client_properties() failed"); - return; - } else if (!res) { - /* - * No more clients to send to. - * Clear Map for indicating now ME clients - * with associated host client - */ - bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX); - dev->open_handle_count = 0; - - /* - * Reserving the first three client IDs - * Client Id 0 - Reserved for MEI Bus Message communications - * Client Id 1 - Reserved for Watchdog - * Client ID 2 - Reserved for AMTHI - */ - bitmap_set(dev->host_clients_map, 0, 3); - dev->dev_state = MEI_DEV_ENABLED; - - /* if wd initialization fails, initialization the AMTHI client, - * otherwise the AMTHI client will be initialized after the WD client connect response - * will be received - */ - if (mei_wd_host_init(dev)) - mei_amthif_host_init(dev); - } + return; + } - } else { - dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message"); - mei_reset(dev, 1); - return; - } - } else { - dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message for wrong client ID\n"); + if (dev->dev_state != MEI_DEV_INIT_CLIENTS || + dev->init_clients_state != MEI_CLIENT_PROPERTIES_MESSAGE) { + dev_err(&dev->pdev->dev, + "Unexpected client properties reply\n"); mei_reset(dev, 1); + return; } + + me_client->props = props_res->client_properties; + dev->me_client_index++; + dev->me_client_presentation_num++; + + mei_host_client_enumerate(dev); + break; case HOST_ENUM_RES_CMD: @@ -618,7 +588,8 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, mei_allocate_me_clients_storage(dev); dev->init_clients_state = MEI_CLIENT_PROPERTIES_MESSAGE; - mei_host_client_properties(dev); + + mei_host_client_enumerate(dev); } else { dev_dbg(&dev->pdev->dev, "reset due to received host enumeration clients response bus message.\n"); mei_reset(dev, 1); diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 251aaff..7c9c381 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -829,6 +829,8 @@ static int __devinit mei_probe(struct pci_dev *pdev, goto disable_msi; } INIT_DELAYED_WORK(&dev->timer_work, mei_timer); + INIT_WORK(&dev->init_work, mei_host_client_init); + if (mei_hw_init(dev)) { dev_err(&pdev->dev, "init hw failure.\n"); err = -ENODEV; diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 17d00aa..25da045 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -287,6 +287,8 @@ struct mei_device { bool iamthif_flow_control_pending; bool iamthif_ioctl; bool iamthif_canceled; + + struct work_struct init_work; }; static inline unsigned long mei_secs_to_jiffies(unsigned long sec) @@ -363,7 +365,8 @@ static inline bool mei_cl_cmp_id(const struct mei_cl *cl1, */ void mei_host_start_message(struct mei_device *dev); void mei_host_enum_clients_message(struct mei_device *dev); -int mei_host_client_properties(struct mei_device *dev); +int mei_host_client_enumerate(struct mei_device *dev); +void mei_host_client_init(struct work_struct *work); /* * MEI interrupt functions prototype -- cgit v0.10.2 From 9306a8b0c29e11d823b258f5796353a4fe3e3be3 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 19 Nov 2012 13:20:25 -0500 Subject: mei: remove use of __devexit_p CONFIG_HOTPLUG is going away as an option so __devexit_p is no longer needed. Signed-off-by: Bill Pemberton Cc: Tomas Winkler Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 7c9c381..f432b8d 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -1023,8 +1023,8 @@ static struct pci_driver mei_driver = { .name = KBUILD_MODNAME, .id_table = mei_pci_tbl, .probe = mei_probe, - .remove = __devexit_p(mei_remove), - .shutdown = __devexit_p(mei_remove), + .remove = mei_remove, + .shutdown = mei_remove, .driver.pm = MEI_PM_OPS, }; -- cgit v0.10.2 From 989623c7d687d3996d5676a6e1474dc7f01bf158 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 21 Nov 2012 12:46:40 -0800 Subject: hv: hv_balloon: mark a function static This resolves the following sparse warning: drivers/hv/hv_balloon.c:548:6: sparse: symbol 'free_balloon_pages' was not declared. Should it be static? Reported-by: Xie ChanglongX Cc: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c index bbc4973..f6c0011 100644 --- a/drivers/hv/hv_balloon.c +++ b/drivers/hv/hv_balloon.c @@ -545,7 +545,7 @@ static void post_status(struct hv_dynmem_device *dm) -void free_balloon_pages(struct hv_dynmem_device *dm, +static void free_balloon_pages(struct hv_dynmem_device *dm, union dm_mem_page_range *range_array) { int num_pages = range_array->finfo.page_cnt; -- cgit v0.10.2 From 2d6bed9ca93e98685bc5038d686984fd449cd978 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 19 Nov 2012 13:21:23 -0500 Subject: drivers/misc: remove use of __devexit_p MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CONFIG_HOTPLUG is going away as an option so __devexit_p is no longer needed. Signed-off-by: Bill Pemberton Cc: "Michał Mirosław" Cc: Wolfram Sang Cc: Eric Piel Cc: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/ad525x_dpot-i2c.c b/drivers/misc/ad525x_dpot-i2c.c index 8208262..7254a98 100644 --- a/drivers/misc/ad525x_dpot-i2c.c +++ b/drivers/misc/ad525x_dpot-i2c.c @@ -109,7 +109,7 @@ static struct i2c_driver ad_dpot_i2c_driver = { .owner = THIS_MODULE, }, .probe = ad_dpot_i2c_probe, - .remove = __devexit_p(ad_dpot_i2c_remove), + .remove = ad_dpot_i2c_remove, .id_table = ad_dpot_id, }; diff --git a/drivers/misc/ad525x_dpot-spi.c b/drivers/misc/ad525x_dpot-spi.c index f623175..67e3073 100644 --- a/drivers/misc/ad525x_dpot-spi.c +++ b/drivers/misc/ad525x_dpot-spi.c @@ -131,7 +131,7 @@ static struct spi_driver ad_dpot_spi_driver = { .owner = THIS_MODULE, }, .probe = ad_dpot_spi_probe, - .remove = __devexit_p(ad_dpot_spi_remove), + .remove = ad_dpot_spi_remove, .id_table = ad_dpot_spi_id, }; diff --git a/drivers/misc/apds9802als.c b/drivers/misc/apds9802als.c index 94923d2..0132d15 100644 --- a/drivers/misc/apds9802als.c +++ b/drivers/misc/apds9802als.c @@ -326,7 +326,7 @@ static struct i2c_driver apds9802als_driver = { .pm = APDS9802ALS_PM_OPS, }, .probe = apds9802als_probe, - .remove = __devexit_p(apds9802als_remove), + .remove = apds9802als_remove, .suspend = apds9802als_suspend, .resume = apds9802als_resume, .id_table = apds9802als_id, diff --git a/drivers/misc/apds990x.c b/drivers/misc/apds990x.c index ee74244..f955d54 100644 --- a/drivers/misc/apds990x.c +++ b/drivers/misc/apds990x.c @@ -1275,7 +1275,7 @@ static struct i2c_driver apds990x_driver = { .pm = &apds990x_pm_ops, }, .probe = apds990x_probe, - .remove = __devexit_p(apds990x_remove), + .remove = apds990x_remove, .id_table = apds990x_id, }; diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c index 5bb1877..191c2ce 100644 --- a/drivers/misc/atmel-ssc.c +++ b/drivers/misc/atmel-ssc.c @@ -152,7 +152,7 @@ static int __devexit ssc_remove(struct platform_device *pdev) } static struct platform_driver ssc_driver = { - .remove = __devexit_p(ssc_remove), + .remove = ssc_remove, .driver = { .name = "ssc", .owner = THIS_MODULE, diff --git a/drivers/misc/bh1770glc.c b/drivers/misc/bh1770glc.c index 3d56ae7..c4b65e2 100644 --- a/drivers/misc/bh1770glc.c +++ b/drivers/misc/bh1770glc.c @@ -1395,7 +1395,7 @@ static struct i2c_driver bh1770_driver = { .pm = &bh1770_pm_ops, }, .probe = bh1770_probe, - .remove = __devexit_p(bh1770_remove), + .remove = bh1770_remove, .id_table = bh1770_id, }; diff --git a/drivers/misc/bh1780gli.c b/drivers/misc/bh1780gli.c index f1f9877..54f6f39 100644 --- a/drivers/misc/bh1780gli.c +++ b/drivers/misc/bh1780gli.c @@ -248,7 +248,7 @@ static const struct i2c_device_id bh1780_id[] = { static struct i2c_driver bh1780_driver = { .probe = bh1780_probe, - .remove = __devexit_p(bh1780_remove), + .remove = bh1780_remove, .id_table = bh1780_id, .driver = { .name = "bh1780", diff --git a/drivers/misc/bmp085-i2c.c b/drivers/misc/bmp085-i2c.c index a4f33c9..08cd795 100644 --- a/drivers/misc/bmp085-i2c.c +++ b/drivers/misc/bmp085-i2c.c @@ -71,7 +71,7 @@ static struct i2c_driver bmp085_i2c_driver = { }, .id_table = bmp085_id, .probe = bmp085_i2c_probe, - .remove = __devexit_p(bmp085_i2c_remove), + .remove = bmp085_i2c_remove, .detect = bmp085_i2c_detect, .address_list = normal_i2c diff --git a/drivers/misc/bmp085-spi.c b/drivers/misc/bmp085-spi.c index 5e982af..ed34885 100644 --- a/drivers/misc/bmp085-spi.c +++ b/drivers/misc/bmp085-spi.c @@ -70,7 +70,7 @@ static struct spi_driver bmp085_spi_driver = { }, .id_table = bmp085_id, .probe = bmp085_spi_probe, - .remove = __devexit_p(bmp085_spi_remove) + .remove = bmp085_spi_remove }; module_spi_driver(bmp085_spi_driver); diff --git a/drivers/misc/cb710/core.c b/drivers/misc/cb710/core.c index 9d5eed7..489c468 100644 --- a/drivers/misc/cb710/core.c +++ b/drivers/misc/cb710/core.c @@ -332,7 +332,7 @@ static struct pci_driver cb710_driver = { .name = KBUILD_MODNAME, .id_table = cb710_pci_tbl, .probe = cb710_probe, - .remove = __devexit_p(cb710_remove_one), + .remove = cb710_remove_one, #ifdef CONFIG_PM .suspend = cb710_suspend, .resume = cb710_resume, diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index ab1ad41..3c36997 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -680,7 +680,7 @@ static struct i2c_driver at24_driver = { .owner = THIS_MODULE, }, .probe = at24_probe, - .remove = __devexit_p(at24_remove), + .remove = at24_remove, .id_table = at24_ids, }; diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c index 4ed93dd..fcb237e 100644 --- a/drivers/misc/eeprom/at25.c +++ b/drivers/misc/eeprom/at25.c @@ -477,7 +477,7 @@ static struct spi_driver at25_driver = { .owner = THIS_MODULE, }, .probe = at25_probe, - .remove = __devexit_p(at25_remove), + .remove = at25_remove, }; module_spi_driver(at25_driver); diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c index ce3fe36..3dc14ea 100644 --- a/drivers/misc/eeprom/eeprom_93xx46.c +++ b/drivers/misc/eeprom/eeprom_93xx46.c @@ -389,7 +389,7 @@ static struct spi_driver eeprom_93xx46_driver = { .owner = THIS_MODULE, }, .probe = eeprom_93xx46_probe, - .remove = __devexit_p(eeprom_93xx46_remove), + .remove = eeprom_93xx46_remove, }; module_spi_driver(eeprom_93xx46_driver); diff --git a/drivers/misc/fsa9480.c b/drivers/misc/fsa9480.c index ac96c3a..38b52b9 100644 --- a/drivers/misc/fsa9480.c +++ b/drivers/misc/fsa9480.c @@ -533,7 +533,7 @@ static struct i2c_driver fsa9480_i2c_driver = { .name = "fsa9480", }, .probe = fsa9480_probe, - .remove = __devexit_p(fsa9480_remove), + .remove = fsa9480_remove, .resume = fsa9480_resume, .suspend = fsa9480_suspend, .id_table = fsa9480_id, diff --git a/drivers/misc/hpilo.c b/drivers/misc/hpilo.c index b362d93..47a9ce6 100644 --- a/drivers/misc/hpilo.c +++ b/drivers/misc/hpilo.c @@ -859,7 +859,7 @@ static struct pci_driver ilo_driver = { .name = ILO_NAME, .id_table = ilo_devices, .probe = ilo_probe, - .remove = __devexit_p(ilo_remove), + .remove = ilo_remove, }; static int __init ilo_init(void) diff --git a/drivers/misc/ibmasm/module.c b/drivers/misc/ibmasm/module.c index 168d800..f34a92f 100644 --- a/drivers/misc/ibmasm/module.c +++ b/drivers/misc/ibmasm/module.c @@ -198,7 +198,7 @@ static struct pci_driver ibmasm_driver = { .name = DRIVER_NAME, .id_table = ibmasm_pci_table, .probe = ibmasm_init_one, - .remove = __devexit_p(ibmasm_remove_one), + .remove = ibmasm_remove_one, }; static void __exit ibmasm_exit (void) diff --git a/drivers/misc/ioc4.c b/drivers/misc/ioc4.c index 6a77106..794a7e0 100644 --- a/drivers/misc/ioc4.c +++ b/drivers/misc/ioc4.c @@ -466,7 +466,7 @@ static struct pci_driver ioc4_driver = { .name = "IOC4", .id_table = ioc4_id_table, .probe = ioc4_probe, - .remove = __devexit_p(ioc4_remove), + .remove = ioc4_remove, }; MODULE_DEVICE_TABLE(pci, ioc4_id_table); diff --git a/drivers/misc/isl29003.c b/drivers/misc/isl29003.c index eb5de2e..bef5307 100644 --- a/drivers/misc/isl29003.c +++ b/drivers/misc/isl29003.c @@ -451,7 +451,7 @@ static struct i2c_driver isl29003_driver = { .suspend = isl29003_suspend, .resume = isl29003_resume, .probe = isl29003_probe, - .remove = __devexit_p(isl29003_remove), + .remove = isl29003_remove, .id_table = isl29003_id, }; diff --git a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c index 60ec868..403804c 100644 --- a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c +++ b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c @@ -280,7 +280,7 @@ static struct i2c_driver lis3lv02d_i2c_driver = { .of_match_table = of_match_ptr(lis3lv02d_i2c_dt_ids), }, .probe = lis3lv02d_i2c_probe, - .remove = __devexit_p(lis3lv02d_i2c_remove), + .remove = lis3lv02d_i2c_remove, .id_table = lis3lv02d_id, }; diff --git a/drivers/misc/lis3lv02d/lis3lv02d_spi.c b/drivers/misc/lis3lv02d/lis3lv02d_spi.c index ccb6475..0e415c3 100644 --- a/drivers/misc/lis3lv02d/lis3lv02d_spi.c +++ b/drivers/misc/lis3lv02d/lis3lv02d_spi.c @@ -144,7 +144,7 @@ static struct spi_driver lis302dl_spi_driver = { .of_match_table = of_match_ptr(lis302dl_spi_dt_ids), }, .probe = lis302dl_spi_probe, - .remove = __devexit_p(lis302dl_spi_remove), + .remove = lis302dl_spi_remove, }; module_spi_driver(lis302dl_spi_driver); diff --git a/drivers/misc/pch_phub.c b/drivers/misc/pch_phub.c index c9f20da..5581774 100644 --- a/drivers/misc/pch_phub.c +++ b/drivers/misc/pch_phub.c @@ -888,7 +888,7 @@ static struct pci_driver pch_phub_driver = { .name = "pch_phub", .id_table = pch_phub_pcidev_id, .probe = pch_phub_probe, - .remove = __devexit_p(pch_phub_remove), + .remove = pch_phub_remove, .suspend = pch_phub_suspend, .resume = pch_phub_resume }; diff --git a/drivers/misc/phantom.c b/drivers/misc/phantom.c index 21b28fc..79038e9 100644 --- a/drivers/misc/phantom.c +++ b/drivers/misc/phantom.c @@ -499,7 +499,7 @@ static struct pci_driver phantom_pci_driver = { .name = "phantom", .id_table = phantom_pci_tbl, .probe = phantom_probe, - .remove = __devexit_p(phantom_remove), + .remove = phantom_remove, .suspend = phantom_suspend, .resume = phantom_resume }; diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c index 4999b34..3c5d746 100644 --- a/drivers/misc/pti.c +++ b/drivers/misc/pti.c @@ -901,7 +901,7 @@ static struct pci_driver pti_pci_driver = { .name = PCINAME, .id_table = pci_ids, .probe = pti_pci_probe, - .remove = __devexit_p(pti_pci_remove), + .remove = pti_pci_remove, }; /** diff --git a/drivers/misc/ti_dac7512.c b/drivers/misc/ti_dac7512.c index 5acbba1..85989ca 100644 --- a/drivers/misc/ti_dac7512.c +++ b/drivers/misc/ti_dac7512.c @@ -79,7 +79,7 @@ static struct spi_driver dac7512_driver = { .owner = THIS_MODULE, }, .probe = dac7512_probe, - .remove = __devexit_p(dac7512_remove), + .remove = dac7512_remove, }; module_spi_driver(dac7512_driver); diff --git a/drivers/misc/tsl2550.c b/drivers/misc/tsl2550.c index 0beb298..09ffb0b 100644 --- a/drivers/misc/tsl2550.c +++ b/drivers/misc/tsl2550.c @@ -450,7 +450,7 @@ static struct i2c_driver tsl2550_driver = { .suspend = tsl2550_suspend, .resume = tsl2550_resume, .probe = tsl2550_probe, - .remove = __devexit_p(tsl2550_remove), + .remove = tsl2550_remove, .id_table = tsl2550_id, }; -- cgit v0.10.2 From 80c8ae289266529445fad030fabf5fcf01ccda0d Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 19 Nov 2012 13:23:05 -0500 Subject: misc: remove use of __devinit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CONFIG_HOTPLUG is going away as an option so __devinit is no longer needed. Signed-off-by: Bill Pemberton Cc: "Michał Mirosław" Cc: Eric Piel Cc: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/ad525x_dpot-i2c.c b/drivers/misc/ad525x_dpot-i2c.c index 7254a98..c7bc84d 100644 --- a/drivers/misc/ad525x_dpot-i2c.c +++ b/drivers/misc/ad525x_dpot-i2c.c @@ -51,7 +51,7 @@ static const struct ad_dpot_bus_ops bops = { .write_r8d16 = write_r8d16, }; -static int __devinit ad_dpot_i2c_probe(struct i2c_client *client, +static int ad_dpot_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct ad_dpot_bus_data bdata = { diff --git a/drivers/misc/ad525x_dpot-spi.c b/drivers/misc/ad525x_dpot-spi.c index 67e3073..240c598 100644 --- a/drivers/misc/ad525x_dpot-spi.c +++ b/drivers/misc/ad525x_dpot-spi.c @@ -75,7 +75,7 @@ static const struct ad_dpot_bus_ops bops = { .write_r8d8 = write16, .write_r8d16 = write24, }; -static int __devinit ad_dpot_spi_probe(struct spi_device *spi) +static int ad_dpot_spi_probe(struct spi_device *spi) { struct ad_dpot_bus_data bdata = { .client = spi, diff --git a/drivers/misc/ad525x_dpot.c b/drivers/misc/ad525x_dpot.c index 6938f1b..8f99e8e 100644 --- a/drivers/misc/ad525x_dpot.c +++ b/drivers/misc/ad525x_dpot.c @@ -641,7 +641,7 @@ static const struct attribute_group ad525x_group_commands = { .attrs = ad525x_attributes_commands, }; -__devinit int ad_dpot_add_files(struct device *dev, +int ad_dpot_add_files(struct device *dev, unsigned features, unsigned rdac) { int err = sysfs_create_file(&dev->kobj, @@ -685,7 +685,7 @@ inline void ad_dpot_remove_files(struct device *dev, } } -int __devinit ad_dpot_probe(struct device *dev, +int ad_dpot_probe(struct device *dev, struct ad_dpot_bus_data *bdata, unsigned long devid, const char *name) { diff --git a/drivers/misc/apds990x.c b/drivers/misc/apds990x.c index f955d54..b2aaf3f0 100644 --- a/drivers/misc/apds990x.c +++ b/drivers/misc/apds990x.c @@ -1047,7 +1047,7 @@ static struct attribute_group apds990x_attribute_group[] = { {.attrs = sysfs_attrs_ctrl }, }; -static int __devinit apds990x_probe(struct i2c_client *client, +static int apds990x_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct apds990x_chip *chip; diff --git a/drivers/misc/bh1770glc.c b/drivers/misc/bh1770glc.c index c4b65e2..003e8d9 100644 --- a/drivers/misc/bh1770glc.c +++ b/drivers/misc/bh1770glc.c @@ -1162,7 +1162,7 @@ static struct attribute_group bh1770_attribute_group = { .attrs = sysfs_attrs }; -static int __devinit bh1770_probe(struct i2c_client *client, +static int bh1770_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct bh1770_chip *chip; diff --git a/drivers/misc/bh1780gli.c b/drivers/misc/bh1780gli.c index 54f6f39..3004904 100644 --- a/drivers/misc/bh1780gli.c +++ b/drivers/misc/bh1780gli.c @@ -144,7 +144,7 @@ static const struct attribute_group bh1780_attr_group = { .attrs = bh1780_attributes, }; -static int __devinit bh1780_probe(struct i2c_client *client, +static int bh1780_probe(struct i2c_client *client, const struct i2c_device_id *id) { int ret; diff --git a/drivers/misc/bmp085-i2c.c b/drivers/misc/bmp085-i2c.c index 08cd795..3abfcec 100644 --- a/drivers/misc/bmp085-i2c.c +++ b/drivers/misc/bmp085-i2c.c @@ -36,7 +36,7 @@ static int bmp085_i2c_detect(struct i2c_client *client, return bmp085_detect(&client->dev); } -static int __devinit bmp085_i2c_probe(struct i2c_client *client, +static int bmp085_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { int err; diff --git a/drivers/misc/bmp085-spi.c b/drivers/misc/bmp085-spi.c index ed34885..d6a5265 100644 --- a/drivers/misc/bmp085-spi.c +++ b/drivers/misc/bmp085-spi.c @@ -22,7 +22,7 @@ #include #include "bmp085.h" -static int __devinit bmp085_spi_probe(struct spi_device *client) +static int bmp085_spi_probe(struct spi_device *client) { int err; struct regmap *regmap; diff --git a/drivers/misc/bmp085.c b/drivers/misc/bmp085.c index 62e4182..849e2fe 100644 --- a/drivers/misc/bmp085.c +++ b/drivers/misc/bmp085.c @@ -420,7 +420,7 @@ struct regmap_config bmp085_regmap_config = { }; EXPORT_SYMBOL_GPL(bmp085_regmap_config); -__devinit int bmp085_probe(struct device *dev, struct regmap *regmap) +int bmp085_probe(struct device *dev, struct regmap *regmap) { struct bmp085_data *data; int err = 0; diff --git a/drivers/misc/cb710/core.c b/drivers/misc/cb710/core.c index 489c468..4fc9c37 100644 --- a/drivers/misc/cb710/core.c +++ b/drivers/misc/cb710/core.c @@ -30,7 +30,7 @@ void cb710_pci_update_config_reg(struct pci_dev *pdev, EXPORT_SYMBOL_GPL(cb710_pci_update_config_reg); /* Some magic writes based on Windows driver init code */ -static int __devinit cb710_pci_configure(struct pci_dev *pdev) +static int cb710_pci_configure(struct pci_dev *pdev) { unsigned int devfn = PCI_DEVFN(PCI_SLOT(pdev->devfn), 0); struct pci_dev *pdev0; @@ -96,7 +96,7 @@ static void cb710_release_slot(struct device *dev) #endif } -static int __devinit cb710_register_slot(struct cb710_chip *chip, +static int cb710_register_slot(struct cb710_chip *chip, unsigned slot_mask, unsigned io_offset, const char *name) { int nr = chip->slots; @@ -201,7 +201,7 @@ static int cb710_resume(struct pci_dev *pdev) #endif /* CONFIG_PM */ -static int __devinit cb710_probe(struct pci_dev *pdev, +static int cb710_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct cb710_chip *chip; diff --git a/drivers/misc/cs5535-mfgpt.c b/drivers/misc/cs5535-mfgpt.c index f505a40..9858f36 100644 --- a/drivers/misc/cs5535-mfgpt.c +++ b/drivers/misc/cs5535-mfgpt.c @@ -246,7 +246,7 @@ EXPORT_SYMBOL_GPL(cs5535_mfgpt_write); * Jordan tells me that he and Mitch once played w/ it, but it's unclear * what the results of that were (and they experienced some instability). */ -static void __devinit reset_all_timers(void) +static void reset_all_timers(void) { uint32_t val, dummy; @@ -262,7 +262,7 @@ static void __devinit reset_all_timers(void) * In other cases (such as with VSAless OpenFirmware), the system firmware * leaves timers available for us to use. */ -static int __devinit scan_timers(struct cs5535_mfgpt_chip *mfgpt) +static int scan_timers(struct cs5535_mfgpt_chip *mfgpt) { struct cs5535_mfgpt_timer timer = { .chip = mfgpt }; unsigned long flags; @@ -289,7 +289,7 @@ static int __devinit scan_timers(struct cs5535_mfgpt_chip *mfgpt) return timers; } -static int __devinit cs5535_mfgpt_probe(struct platform_device *pdev) +static int cs5535_mfgpt_probe(struct platform_device *pdev) { struct resource *res; int err = -EIO, t; diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c index 3dc14ea..3dd9005 100644 --- a/drivers/misc/eeprom/eeprom_93xx46.c +++ b/drivers/misc/eeprom/eeprom_93xx46.c @@ -309,7 +309,7 @@ static ssize_t eeprom_93xx46_store_erase(struct device *dev, } static DEVICE_ATTR(erase, S_IWUSR, NULL, eeprom_93xx46_store_erase); -static int __devinit eeprom_93xx46_probe(struct spi_device *spi) +static int eeprom_93xx46_probe(struct spi_device *spi) { struct eeprom_93xx46_platform_data *pd; struct eeprom_93xx46_dev *edev; diff --git a/drivers/misc/fsa9480.c b/drivers/misc/fsa9480.c index 38b52b9..2baa52f 100644 --- a/drivers/misc/fsa9480.c +++ b/drivers/misc/fsa9480.c @@ -407,7 +407,7 @@ static int fsa9480_irq_init(struct fsa9480_usbsw *usbsw) return 0; } -static int __devinit fsa9480_probe(struct i2c_client *client, +static int fsa9480_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); diff --git a/drivers/misc/hpilo.c b/drivers/misc/hpilo.c index 47a9ce6..621c7a3 100644 --- a/drivers/misc/hpilo.c +++ b/drivers/misc/hpilo.c @@ -686,7 +686,7 @@ static void ilo_unmap_device(struct pci_dev *pdev, struct ilo_hwinfo *hw) pci_iounmap(pdev, hw->mmio_vaddr); } -static int __devinit ilo_map_device(struct pci_dev *pdev, struct ilo_hwinfo *hw) +static int ilo_map_device(struct pci_dev *pdev, struct ilo_hwinfo *hw) { int error = -ENOMEM; @@ -751,7 +751,7 @@ static void ilo_remove(struct pci_dev *pdev) ilo_hwdev[(minor / max_ccb)] = 0; } -static int __devinit ilo_probe(struct pci_dev *pdev, +static int ilo_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { int devnum, minor, start, error = 0; diff --git a/drivers/misc/ibmasm/module.c b/drivers/misc/ibmasm/module.c index f34a92f..380e429 100644 --- a/drivers/misc/ibmasm/module.c +++ b/drivers/misc/ibmasm/module.c @@ -62,7 +62,7 @@ module_param(ibmasm_debug, int , S_IRUGO | S_IWUSR); MODULE_PARM_DESC(ibmasm_debug, " Set debug mode on or off"); -static int __devinit ibmasm_init_one(struct pci_dev *pdev, const struct pci_device_id *id) +static int ibmasm_init_one(struct pci_dev *pdev, const struct pci_device_id *id) { int result; struct service_processor *sp; diff --git a/drivers/misc/ioc4.c b/drivers/misc/ioc4.c index 794a7e0..3ef92dc 100644 --- a/drivers/misc/ioc4.c +++ b/drivers/misc/ioc4.c @@ -139,7 +139,7 @@ ioc4_unregister_submodule(struct ioc4_submodule *is) * even though the following code utilizes external interrupt registers * to perform the speed calculation. */ -static void __devinit +static void ioc4_clock_calibrate(struct ioc4_driver_data *idd) { union ioc4_int_out int_out; @@ -231,7 +231,7 @@ ioc4_clock_calibrate(struct ioc4_driver_data *idd) * on the same PCI bus at slot number 3 to differentiate IO9 from IO10. * If neither is present, it's a PCI-RT. */ -static unsigned int __devinit +static unsigned int ioc4_variant(struct ioc4_driver_data *idd) { struct pci_dev *pdev = NULL; @@ -279,7 +279,7 @@ ioc4_load_modules(struct work_struct *work) static DECLARE_WORK(ioc4_load_modules_work, ioc4_load_modules); /* Adds a new instance of an IOC4 card */ -static int __devinit +static int ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) { struct ioc4_driver_data *idd; diff --git a/drivers/misc/isl29003.c b/drivers/misc/isl29003.c index bef5307..9fd4c0c 100644 --- a/drivers/misc/isl29003.c +++ b/drivers/misc/isl29003.c @@ -365,7 +365,7 @@ static int isl29003_init_client(struct i2c_client *client) * I2C layer */ -static int __devinit isl29003_probe(struct i2c_client *client, +static int isl29003_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); diff --git a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c index 403804c..66f0483 100644 --- a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c +++ b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c @@ -114,7 +114,7 @@ static struct of_device_id lis3lv02d_i2c_dt_ids[] = { MODULE_DEVICE_TABLE(of, lis3lv02d_i2c_dt_ids); #endif -static int __devinit lis3lv02d_i2c_probe(struct i2c_client *client, +static int lis3lv02d_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { int ret = 0; diff --git a/drivers/misc/lis3lv02d/lis3lv02d_spi.c b/drivers/misc/lis3lv02d/lis3lv02d_spi.c index 0e415c3..66a751d 100644 --- a/drivers/misc/lis3lv02d/lis3lv02d_spi.c +++ b/drivers/misc/lis3lv02d/lis3lv02d_spi.c @@ -69,7 +69,7 @@ static struct of_device_id lis302dl_spi_dt_ids[] = { MODULE_DEVICE_TABLE(of, lis302dl_spi_dt_ids); #endif -static int __devinit lis302dl_spi_probe(struct spi_device *spi) +static int lis302dl_spi_probe(struct spi_device *spi) { int ret; diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index f432b8d..4782c58 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -743,7 +743,7 @@ static struct miscdevice mei_misc_device = { * * returns true if ME Interface is valid, false otherwise */ -static bool __devinit mei_quirk_probe(struct pci_dev *pdev, +static bool mei_quirk_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { u32 reg; @@ -765,7 +765,7 @@ static bool __devinit mei_quirk_probe(struct pci_dev *pdev, * * returns 0 on success, <0 on failure. */ -static int __devinit mei_probe(struct pci_dev *pdev, +static int mei_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct mei_device *dev; diff --git a/drivers/misc/pch_phub.c b/drivers/misc/pch_phub.c index 5581774..3896cff 100644 --- a/drivers/misc/pch_phub.c +++ b/drivers/misc/pch_phub.c @@ -666,7 +666,7 @@ static struct bin_attribute pch_bin_attr = { .write = pch_phub_bin_write, }; -static int __devinit pch_phub_probe(struct pci_dev *pdev, +static int pch_phub_probe(struct pci_dev *pdev, const struct pci_device_id *id) { int retval; diff --git a/drivers/misc/phantom.c b/drivers/misc/phantom.c index 79038e9..394150d 100644 --- a/drivers/misc/phantom.c +++ b/drivers/misc/phantom.c @@ -324,7 +324,7 @@ static irqreturn_t phantom_isr(int irq, void *data) * Init and deinit driver */ -static unsigned int __devinit phantom_get_free(void) +static unsigned int phantom_get_free(void) { unsigned int i; @@ -335,7 +335,7 @@ static unsigned int __devinit phantom_get_free(void) return i; } -static int __devinit phantom_probe(struct pci_dev *pdev, +static int phantom_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) { struct phantom_device *pht; diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c index 3c5d746..e1a898e 100644 --- a/drivers/misc/pti.c +++ b/drivers/misc/pti.c @@ -796,7 +796,7 @@ static const struct tty_port_operations tty_port_ops = { * 0 for success * otherwise, error */ -static int __devinit pti_pci_probe(struct pci_dev *pdev, +static int pti_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { unsigned int a; diff --git a/drivers/misc/spear13xx_pcie_gadget.c b/drivers/misc/spear13xx_pcie_gadget.c index 123ed98..7850320 100644 --- a/drivers/misc/spear13xx_pcie_gadget.c +++ b/drivers/misc/spear13xx_pcie_gadget.c @@ -711,7 +711,7 @@ static void spear13xx_pcie_device_init(struct spear_pcie_gadget_config *config) spear_dbi_write_reg(config, PCI_INTERRUPT_LINE, 1, 1); } -static int __devinit spear_pcie_gadget_probe(struct platform_device *pdev) +static int spear_pcie_gadget_probe(struct platform_device *pdev) { struct resource *res0, *res1; unsigned int status = 0; diff --git a/drivers/misc/ti_dac7512.c b/drivers/misc/ti_dac7512.c index 85989ca..1222f86 100644 --- a/drivers/misc/ti_dac7512.c +++ b/drivers/misc/ti_dac7512.c @@ -54,7 +54,7 @@ static const struct attribute_group dac7512_attr_group = { .attrs = dac7512_attributes, }; -static int __devinit dac7512_probe(struct spi_device *spi) +static int dac7512_probe(struct spi_device *spi) { int ret; diff --git a/drivers/misc/tsl2550.c b/drivers/misc/tsl2550.c index 09ffb0b..18bce70 100644 --- a/drivers/misc/tsl2550.c +++ b/drivers/misc/tsl2550.c @@ -347,7 +347,7 @@ static int tsl2550_init_client(struct i2c_client *client) */ static struct i2c_driver tsl2550_driver; -static int __devinit tsl2550_probe(struct i2c_client *client, +static int tsl2550_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); -- cgit v0.10.2 From 2c68506412e96d0e306be6057e824478a2deccbd Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 19 Nov 2012 13:24:38 -0500 Subject: misc: remove use of __devinitdata CONFIG_HOTPLUG is going away as an option so __devinitdata is no longer needed. Signed-off-by: Bill Pemberton Cc: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/phantom.c b/drivers/misc/phantom.c index 394150d..0357763 100644 --- a/drivers/misc/phantom.c +++ b/drivers/misc/phantom.c @@ -487,7 +487,7 @@ static int phantom_resume(struct pci_dev *pdev) #define phantom_resume NULL #endif -static struct pci_device_id phantom_pci_tbl[] __devinitdata = { +static struct pci_device_id phantom_pci_tbl[] = { { .vendor = PCI_VENDOR_ID_PLX, .device = PCI_DEVICE_ID_PLX_9050, .subvendor = PCI_VENDOR_ID_PLX, .subdevice = PCI_DEVICE_ID_PLX_9050, .class = PCI_CLASS_BRIDGE_OTHER << 8, .class_mask = 0xffff00 }, -- cgit v0.10.2 From b328bfec519875851c4b3d95cd22371aad0a657e Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 19 Nov 2012 13:25:10 -0500 Subject: misc: remove use of __devinitconst CONFIG_HOTPLUG is going away as an option so __devinitconst is no longer needed. Signed-off-by: Bill Pemberton Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c index e1a898e..37d4b5e 100644 --- a/drivers/misc/pti.c +++ b/drivers/misc/pti.c @@ -76,7 +76,7 @@ struct pti_dev { */ static DEFINE_MUTEX(alloclock); -static const struct pci_device_id pci_ids[] __devinitconst = { +static const struct pci_device_id pci_ids[] = { {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x82B)}, {0} }; -- cgit v0.10.2 From 486a5c28c2e7d6a80c393ac7d612b77d80447b84 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 19 Nov 2012 13:26:02 -0500 Subject: misc: remove use of __devexit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CONFIG_HOTPLUG is going away as an option so __devexit is no longer needed. Signed-off-by: Bill Pemberton Cc: "Michał Mirosław" Cc: Wolfram Sang Cc: Eric Piel Cc: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/ad525x_dpot-i2c.c b/drivers/misc/ad525x_dpot-i2c.c index c7bc84d..705b881 100644 --- a/drivers/misc/ad525x_dpot-i2c.c +++ b/drivers/misc/ad525x_dpot-i2c.c @@ -68,7 +68,7 @@ static int ad_dpot_i2c_probe(struct i2c_client *client, return ad_dpot_probe(&client->dev, &bdata, id->driver_data, id->name); } -static int __devexit ad_dpot_i2c_remove(struct i2c_client *client) +static int ad_dpot_i2c_remove(struct i2c_client *client) { return ad_dpot_remove(&client->dev); } diff --git a/drivers/misc/ad525x_dpot-spi.c b/drivers/misc/ad525x_dpot-spi.c index 240c598..9da04ed 100644 --- a/drivers/misc/ad525x_dpot-spi.c +++ b/drivers/misc/ad525x_dpot-spi.c @@ -87,7 +87,7 @@ static int ad_dpot_spi_probe(struct spi_device *spi) spi_get_device_id(spi)->name); } -static int __devexit ad_dpot_spi_remove(struct spi_device *spi) +static int ad_dpot_spi_remove(struct spi_device *spi) { return ad_dpot_remove(&spi->dev); } diff --git a/drivers/misc/apds9802als.c b/drivers/misc/apds9802als.c index 0132d15..d648b08 100644 --- a/drivers/misc/apds9802als.c +++ b/drivers/misc/apds9802als.c @@ -254,7 +254,7 @@ als_error1: return res; } -static int __devexit apds9802als_remove(struct i2c_client *client) +static int apds9802als_remove(struct i2c_client *client) { struct als_data *data = i2c_get_clientdata(client); diff --git a/drivers/misc/apds990x.c b/drivers/misc/apds990x.c index b2aaf3f0..0e67f82 100644 --- a/drivers/misc/apds990x.c +++ b/drivers/misc/apds990x.c @@ -1181,7 +1181,7 @@ fail1: return err; } -static int __devexit apds990x_remove(struct i2c_client *client) +static int apds990x_remove(struct i2c_client *client) { struct apds990x_chip *chip = i2c_get_clientdata(client); diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c index 191c2ce..c58f9ab 100644 --- a/drivers/misc/atmel-ssc.c +++ b/drivers/misc/atmel-ssc.c @@ -137,7 +137,7 @@ out: return retval; } -static int __devexit ssc_remove(struct platform_device *pdev) +static int ssc_remove(struct platform_device *pdev) { struct ssc_device *ssc = platform_get_drvdata(pdev); diff --git a/drivers/misc/bh1770glc.c b/drivers/misc/bh1770glc.c index 003e8d9..2ed8fc3 100644 --- a/drivers/misc/bh1770glc.c +++ b/drivers/misc/bh1770glc.c @@ -1285,7 +1285,7 @@ fail1: return err; } -static int __devexit bh1770_remove(struct i2c_client *client) +static int bh1770_remove(struct i2c_client *client) { struct bh1770_chip *chip = i2c_get_clientdata(client); diff --git a/drivers/misc/bh1780gli.c b/drivers/misc/bh1780gli.c index 3004904..cf03d0a 100644 --- a/drivers/misc/bh1780gli.c +++ b/drivers/misc/bh1780gli.c @@ -185,7 +185,7 @@ err_op_failed: return ret; } -static int __devexit bh1780_remove(struct i2c_client *client) +static int bh1780_remove(struct i2c_client *client) { struct bh1780_data *ddata; diff --git a/drivers/misc/cb710/core.c b/drivers/misc/cb710/core.c index 4fc9c37..2e50f81 100644 --- a/drivers/misc/cb710/core.c +++ b/drivers/misc/cb710/core.c @@ -305,7 +305,7 @@ unreg_mmc: return err; } -static void __devexit cb710_remove_one(struct pci_dev *pdev) +static void cb710_remove_one(struct pci_dev *pdev) { struct cb710_chip *chip = pci_get_drvdata(pdev); unsigned long flags; diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index 3c36997..2baeec5 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -656,7 +656,7 @@ err_out: return err; } -static int __devexit at24_remove(struct i2c_client *client) +static int at24_remove(struct i2c_client *client) { struct at24_data *at24; int i; diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c index fcb237e..b08cf8a 100644 --- a/drivers/misc/eeprom/at25.c +++ b/drivers/misc/eeprom/at25.c @@ -459,7 +459,7 @@ fail: return err; } -static int __devexit at25_remove(struct spi_device *spi) +static int at25_remove(struct spi_device *spi) { struct at25_data *at25; diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c index 3dd9005..a6b5d5e 100644 --- a/drivers/misc/eeprom/eeprom_93xx46.c +++ b/drivers/misc/eeprom/eeprom_93xx46.c @@ -370,7 +370,7 @@ fail: return err; } -static int __devexit eeprom_93xx46_remove(struct spi_device *spi) +static int eeprom_93xx46_remove(struct spi_device *spi) { struct eeprom_93xx46_dev *edev = dev_get_drvdata(&spi->dev); diff --git a/drivers/misc/fsa9480.c b/drivers/misc/fsa9480.c index 2baa52f..e8cbb1c 100644 --- a/drivers/misc/fsa9480.c +++ b/drivers/misc/fsa9480.c @@ -462,7 +462,7 @@ fail1: return ret; } -static int __devexit fsa9480_remove(struct i2c_client *client) +static int fsa9480_remove(struct i2c_client *client) { struct fsa9480_usbsw *usbsw = i2c_get_clientdata(client); if (client->irq) diff --git a/drivers/misc/ibmasm/module.c b/drivers/misc/ibmasm/module.c index 380e429..0346d87 100644 --- a/drivers/misc/ibmasm/module.c +++ b/drivers/misc/ibmasm/module.c @@ -163,7 +163,7 @@ error_resources: return result; } -static void __devexit ibmasm_remove_one(struct pci_dev *pdev) +static void ibmasm_remove_one(struct pci_dev *pdev) { struct service_processor *sp = (struct service_processor *)pci_get_drvdata(pdev); diff --git a/drivers/misc/ioc4.c b/drivers/misc/ioc4.c index 3ef92dc..06f6ad2 100644 --- a/drivers/misc/ioc4.c +++ b/drivers/misc/ioc4.c @@ -415,7 +415,7 @@ out: } /* Removes a particular instance of an IOC4 card. */ -static void __devexit +static void ioc4_remove(struct pci_dev *pdev) { struct ioc4_submodule *is; diff --git a/drivers/misc/isl29003.c b/drivers/misc/isl29003.c index 9fd4c0c..29b306c 100644 --- a/drivers/misc/isl29003.c +++ b/drivers/misc/isl29003.c @@ -401,7 +401,7 @@ exit_kfree: return err; } -static int __devexit isl29003_remove(struct i2c_client *client) +static int isl29003_remove(struct i2c_client *client) { sysfs_remove_group(&client->dev.kobj, &isl29003_attr_group); isl29003_set_power_state(client, 0); diff --git a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c index 66f0483..7c97550 100644 --- a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c +++ b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c @@ -191,7 +191,7 @@ fail: return ret; } -static int __devexit lis3lv02d_i2c_remove(struct i2c_client *client) +static int lis3lv02d_i2c_remove(struct i2c_client *client) { struct lis3lv02d *lis3 = i2c_get_clientdata(client); struct lis3lv02d_platform_data *pdata = client->dev.platform_data; diff --git a/drivers/misc/lis3lv02d/lis3lv02d_spi.c b/drivers/misc/lis3lv02d/lis3lv02d_spi.c index 66a751d..9aa2bd2 100644 --- a/drivers/misc/lis3lv02d/lis3lv02d_spi.c +++ b/drivers/misc/lis3lv02d/lis3lv02d_spi.c @@ -100,7 +100,7 @@ static int lis302dl_spi_probe(struct spi_device *spi) return lis3lv02d_init_device(&lis3_dev); } -static int __devexit lis302dl_spi_remove(struct spi_device *spi) +static int lis302dl_spi_remove(struct spi_device *spi) { struct lis3lv02d *lis3 = spi_get_drvdata(spi); lis3lv02d_joystick_disable(lis3); diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 4782c58..43fb52f 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -882,7 +882,7 @@ end: * mei_remove is called by the PCI subsystem to alert the driver * that it should release a PCI device. */ -static void __devexit mei_remove(struct pci_dev *pdev) +static void mei_remove(struct pci_dev *pdev) { struct mei_device *dev; diff --git a/drivers/misc/pch_phub.c b/drivers/misc/pch_phub.c index 3896cff..931e635 100644 --- a/drivers/misc/pch_phub.c +++ b/drivers/misc/pch_phub.c @@ -819,7 +819,7 @@ err_pci_enable_dev: return ret; } -static void __devexit pch_phub_remove(struct pci_dev *pdev) +static void pch_phub_remove(struct pci_dev *pdev) { struct pch_phub_reg *chip = pci_get_drvdata(pdev); diff --git a/drivers/misc/phantom.c b/drivers/misc/phantom.c index 0357763..68b7c77 100644 --- a/drivers/misc/phantom.c +++ b/drivers/misc/phantom.c @@ -435,7 +435,7 @@ err: return retval; } -static void __devexit phantom_remove(struct pci_dev *pdev) +static void phantom_remove(struct pci_dev *pdev) { struct phantom_device *pht = pci_get_drvdata(pdev); unsigned int minor = MINOR(pht->cdev.dev); diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c index 37d4b5e..7003031 100644 --- a/drivers/misc/pti.c +++ b/drivers/misc/pti.c @@ -879,7 +879,7 @@ err: * PCI bus. * @pdev: variable containing pci info of PTI. */ -static void __devexit pti_pci_remove(struct pci_dev *pdev) +static void pti_pci_remove(struct pci_dev *pdev) { struct pti_dev *drv_data = pci_get_drvdata(pdev); diff --git a/drivers/misc/spear13xx_pcie_gadget.c b/drivers/misc/spear13xx_pcie_gadget.c index 7850320..7deb25d 100644 --- a/drivers/misc/spear13xx_pcie_gadget.c +++ b/drivers/misc/spear13xx_pcie_gadget.c @@ -853,7 +853,7 @@ err_rel_res0: return status; } -static int __devexit spear_pcie_gadget_remove(struct platform_device *pdev) +static int spear_pcie_gadget_remove(struct platform_device *pdev) { struct resource *res0, *res1; static struct pcie_gadget_target *target; diff --git a/drivers/misc/ti_dac7512.c b/drivers/misc/ti_dac7512.c index 1222f86..1d86407 100644 --- a/drivers/misc/ti_dac7512.c +++ b/drivers/misc/ti_dac7512.c @@ -67,7 +67,7 @@ static int dac7512_probe(struct spi_device *spi) return sysfs_create_group(&spi->dev.kobj, &dac7512_attr_group); } -static int __devexit dac7512_remove(struct spi_device *spi) +static int dac7512_remove(struct spi_device *spi) { sysfs_remove_group(&spi->dev.kobj, &dac7512_attr_group); return 0; diff --git a/drivers/misc/tsl2550.c b/drivers/misc/tsl2550.c index 18bce70..1e7bc0e 100644 --- a/drivers/misc/tsl2550.c +++ b/drivers/misc/tsl2550.c @@ -405,7 +405,7 @@ exit: return err; } -static int __devexit tsl2550_remove(struct i2c_client *client) +static int tsl2550_remove(struct i2c_client *client) { sysfs_remove_group(&client->dev.kobj, &tsl2550_attr_group); -- cgit v0.10.2 From 4dde2d2f3a3b09d282eb399d24fb261ae50425ef Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 19 Nov 2012 13:19:58 -0500 Subject: char: remove use of __devexit_p CONFIG_HOTPLUG is going away as an option so __devexit_p is no longer needed. Signed-off-by: Bill Pemberton Cc: Mattia Dongili Cc: platform-driver-x86@vger.kernel.org Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index 9b4f011..34f0db3 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -1491,7 +1491,7 @@ static struct platform_driver sonypi_driver = { .pm = SONYPI_PM, }, .probe = sonypi_probe, - .remove = __devexit_p(sonypi_remove), + .remove = sonypi_remove, .shutdown = sonypi_shutdown, }; diff --git a/drivers/char/tb0219.c b/drivers/char/tb0219.c index ad26418..6bfe2af 100644 --- a/drivers/char/tb0219.c +++ b/drivers/char/tb0219.c @@ -334,7 +334,7 @@ static struct platform_device *tb0219_platform_device; static struct platform_driver tb0219_device_driver = { .probe = tb0219_probe, - .remove = __devexit_p(tb0219_remove), + .remove = tb0219_remove, .driver = { .name = "TB0219", .owner = THIS_MODULE, -- cgit v0.10.2 From 2223cbec33ef3a26e7678be89de75cb60c4c257b Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 19 Nov 2012 13:22:51 -0500 Subject: char: remove use of __devinit CONFIG_HOTPLUG is going away as an option so __devinit is no longer needed. Signed-off-by: Bill Pemberton Cc: Geoff Levand Cc: Mattia Dongili Cc: Amit Shah Cc: openipmi-developer@lists.sourceforge.net Cc: linuxppc-dev@lists.ozlabs.org Cc: cbe-oss-dev@lists.ozlabs.org Cc: platform-driver-x86@vger.kernel.org Cc: virtualization@lists.linux-foundation.org Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 32a6c7e..1a465a4 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1836,7 +1836,7 @@ static int hotmod_handler(const char *val, struct kernel_param *kp) return rv; } -static int __devinit hardcode_find_bmc(void) +static int hardcode_find_bmc(void) { int ret = -ENODEV; int i; @@ -2023,7 +2023,7 @@ struct SPMITable { s8 spmi_id[1]; /* A '\0' terminated array starts here. */ }; -static int __devinit try_init_spmi(struct SPMITable *spmi) +static int try_init_spmi(struct SPMITable *spmi) { struct smi_info *info; @@ -2106,7 +2106,7 @@ static int __devinit try_init_spmi(struct SPMITable *spmi) return 0; } -static void __devinit spmi_find_bmc(void) +static void spmi_find_bmc(void) { acpi_status status; struct SPMITable *spmi; @@ -2128,7 +2128,7 @@ static void __devinit spmi_find_bmc(void) } } -static int __devinit ipmi_pnp_probe(struct pnp_dev *dev, +static int ipmi_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) { struct acpi_device *acpi_dev; @@ -2258,7 +2258,7 @@ struct dmi_ipmi_data { u8 slave_addr; }; -static int __devinit decode_dmi(const struct dmi_header *dm, +static int decode_dmi(const struct dmi_header *dm, struct dmi_ipmi_data *dmi) { const u8 *data = (const u8 *)dm; @@ -2320,7 +2320,7 @@ static int __devinit decode_dmi(const struct dmi_header *dm, return 0; } -static void __devinit try_init_dmi(struct dmi_ipmi_data *ipmi_data) +static void try_init_dmi(struct dmi_ipmi_data *ipmi_data) { struct smi_info *info; @@ -2388,7 +2388,7 @@ static void __devinit try_init_dmi(struct dmi_ipmi_data *ipmi_data) kfree(info); } -static void __devinit dmi_find_bmc(void) +static void dmi_find_bmc(void) { const struct dmi_device *dev = NULL; struct dmi_ipmi_data data; @@ -2424,7 +2424,7 @@ static void ipmi_pci_cleanup(struct smi_info *info) pci_disable_device(pdev); } -static int __devinit ipmi_pci_probe_regspacing(struct smi_info *info) +static int ipmi_pci_probe_regspacing(struct smi_info *info) { if (info->si_type == SI_KCS) { unsigned char status; @@ -2456,7 +2456,7 @@ static int __devinit ipmi_pci_probe_regspacing(struct smi_info *info) return DEFAULT_REGSPACING; } -static int __devinit ipmi_pci_probe(struct pci_dev *pdev, +static int ipmi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { int rv; @@ -2551,7 +2551,7 @@ static struct pci_driver ipmi_pci_driver = { #endif /* CONFIG_PCI */ static struct of_device_id ipmi_match[]; -static int __devinit ipmi_probe(struct platform_device *dev) +static int ipmi_probe(struct platform_device *dev) { #ifdef CONFIG_OF const struct of_device_id *match; @@ -3059,7 +3059,7 @@ static __devinitdata struct ipmi_default_vals { .port = 0 } }; -static void __devinit default_find_bmc(void) +static void default_find_bmc(void) { struct smi_info *info; int i; @@ -3359,7 +3359,7 @@ static int try_smi_init(struct smi_info *new_smi) return rv; } -static int __devinit init_ipmi_si(void) +static int init_ipmi_si(void) { int i; char *str; diff --git a/drivers/char/ps3flash.c b/drivers/char/ps3flash.c index 6abdde4..588063ac 100644 --- a/drivers/char/ps3flash.c +++ b/drivers/char/ps3flash.c @@ -363,7 +363,7 @@ static struct miscdevice ps3flash_misc = { .fops = &ps3flash_fops, }; -static int __devinit ps3flash_probe(struct ps3_system_bus_device *_dev) +static int ps3flash_probe(struct ps3_system_bus_device *_dev) { struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core); struct ps3flash_private *priv; diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index 34f0db3..861efa4 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -1164,7 +1164,7 @@ static struct acpi_driver sonypi_acpi_driver = { }; #endif -static int __devinit sonypi_create_input_devices(struct platform_device *pdev) +static int sonypi_create_input_devices(struct platform_device *pdev) { struct input_dev *jog_dev; struct input_dev *key_dev; @@ -1225,7 +1225,7 @@ static int __devinit sonypi_create_input_devices(struct platform_device *pdev) return error; } -static int __devinit sonypi_setup_ioports(struct sonypi_device *dev, +static int sonypi_setup_ioports(struct sonypi_device *dev, const struct sonypi_ioport_list *ioport_list) { /* try to detect if sony-laptop is being used and thus @@ -1265,7 +1265,7 @@ static int __devinit sonypi_setup_ioports(struct sonypi_device *dev, return -EBUSY; } -static int __devinit sonypi_setup_irq(struct sonypi_device *dev, +static int sonypi_setup_irq(struct sonypi_device *dev, const struct sonypi_irq_list *irq_list) { while (irq_list->irq) { @@ -1282,7 +1282,7 @@ static int __devinit sonypi_setup_irq(struct sonypi_device *dev, return -EBUSY; } -static void __devinit sonypi_display_info(void) +static void sonypi_display_info(void) { printk(KERN_INFO "sonypi: detected type%d model, " "verbose = %d, fnkeyinit = %s, camera = %s, " @@ -1304,7 +1304,7 @@ static void __devinit sonypi_display_info(void) sonypi_misc_device.minor); } -static int __devinit sonypi_probe(struct platform_device *dev) +static int sonypi_probe(struct platform_device *dev) { const struct sonypi_ioport_list *ioport_list; const struct sonypi_irq_list *irq_list; diff --git a/drivers/char/tb0219.c b/drivers/char/tb0219.c index 6bfe2af..76e3aea 100644 --- a/drivers/char/tb0219.c +++ b/drivers/char/tb0219.c @@ -284,7 +284,7 @@ static void tb0219_pci_irq_init(void) vr41xx_set_irq_level(TB0219_PCI_SLOT3_PIN, IRQ_LEVEL_LOW); } -static int __devinit tb0219_probe(struct platform_device *dev) +static int tb0219_probe(struct platform_device *dev) { int retval; diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 8ab9c3d..90493d4 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1846,7 +1846,7 @@ static void remove_controlq_data(struct ports_device *portdev) * config space to see how many ports the host has spawned. We * initialize each port found. */ -static int __devinit virtcons_probe(struct virtio_device *vdev) +static int virtcons_probe(struct virtio_device *vdev) { struct ports_device *portdev; int err; diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c index 2c5d15b..547ed74 100644 --- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c +++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c @@ -595,7 +595,7 @@ static const struct file_operations hwicap_fops = { .llseek = noop_llseek, }; -static int __devinit hwicap_setup(struct device *dev, int id, +static int hwicap_setup(struct device *dev, int id, const struct resource *regs_res, const struct hwicap_driver_config *config, const struct config_registers *config_regs) @@ -740,7 +740,7 @@ static int __devexit hwicap_remove(struct device *dev) } #ifdef CONFIG_OF -static int __devinit hwicap_of_probe(struct platform_device *op, +static int hwicap_of_probe(struct platform_device *op, const struct hwicap_driver_config *config) { struct resource res; @@ -786,7 +786,7 @@ static inline int hwicap_of_probe(struct platform_device *op, #endif /* CONFIG_OF */ static const struct of_device_id __devinitconst hwicap_of_match[]; -static int __devinit hwicap_drv_probe(struct platform_device *pdev) +static int hwicap_drv_probe(struct platform_device *pdev) { const struct of_device_id *match; struct resource *res; -- cgit v0.10.2 From 0bbed20e0518f6b9d46b7fe2bd044e3398a6dc40 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 19 Nov 2012 13:24:36 -0500 Subject: char: remove use of __devinitdata CONFIG_HOTPLUG is going away as an option so __devinitdata is no longer needed. Signed-off-by: Bill Pemberton Cc: David Airlie Cc: Kent Yoder Cc: Rajiv Andrade Cc: Marcel Selhorst Cc: Sirrix AG Cc: openipmi-developer@lists.sourceforge.net Cc: tpmdd-devel@lists.sourceforge.net Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c index fd79351..9c022df 100644 --- a/drivers/char/agp/ali-agp.c +++ b/drivers/char/agp/ali-agp.c @@ -249,7 +249,7 @@ static const struct agp_bridge_driver ali_m1541_bridge = { }; -static struct agp_device_ids ali_agp_device_ids[] __devinitdata = +static struct agp_device_ids ali_agp_device_ids[] = { { .device_id = PCI_DEVICE_ID_AL_M1541, diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c index f7e8878..3c7a265 100644 --- a/drivers/char/agp/amd-k7-agp.c +++ b/drivers/char/agp/amd-k7-agp.c @@ -388,7 +388,7 @@ static const struct agp_bridge_driver amd_irongate_driver = { .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; -static struct agp_device_ids amd_agp_device_ids[] __devinitdata = +static struct agp_device_ids amd_agp_device_ids[] = { { .device_id = PCI_DEVICE_ID_AMD_FE_GATE_7006, diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c index dc30e22..d1c4c23 100644 --- a/drivers/char/agp/ati-agp.c +++ b/drivers/char/agp/ati-agp.c @@ -445,7 +445,7 @@ static const struct agp_bridge_driver ati_generic_bridge = { }; -static struct agp_device_ids ati_agp_device_ids[] __devinitdata = +static struct agp_device_ids ati_agp_device_ids[] = { { .device_id = PCI_DEVICE_ID_ATI_RS100, diff --git a/drivers/char/agp/sis-agp.c b/drivers/char/agp/sis-agp.c index 08704ae..c93c9e5e 100644 --- a/drivers/char/agp/sis-agp.c +++ b/drivers/char/agp/sis-agp.c @@ -17,8 +17,8 @@ #define PCI_DEVICE_ID_SI_662 0x0662 #define PCI_DEVICE_ID_SI_671 0x0671 -static bool __devinitdata agp_sis_force_delay = 0; -static int __devinitdata agp_sis_agp_spec = -1; +static bool agp_sis_force_delay = 0; +static int agp_sis_agp_spec = -1; static int sis_fetch_size(void) { @@ -148,7 +148,7 @@ static struct agp_bridge_driver sis_driver = { }; // chipsets that require the 'delay hack' -static int sis_broken_chipsets[] __devinitdata = { +static int sis_broken_chipsets[] = { PCI_DEVICE_ID_SI_648, PCI_DEVICE_ID_SI_746, 0 // terminator diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c index a32c492..af02da4 100644 --- a/drivers/char/agp/uninorth-agp.c +++ b/drivers/char/agp/uninorth-agp.c @@ -557,7 +557,7 @@ const struct agp_bridge_driver u3_agp_driver = { .needs_scratch_page = true, }; -static struct agp_device_ids uninorth_agp_device_ids[] __devinitdata = { +static struct agp_device_ids uninorth_agp_device_ids[] = { { .device_id = PCI_DEVICE_ID_APPLE_UNI_N_AGP, .chipset_name = "UniNorth", diff --git a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c index 8bc3849..97706834 100644 --- a/drivers/char/agp/via-agp.c +++ b/drivers/char/agp/via-agp.c @@ -224,7 +224,7 @@ static const struct agp_bridge_driver via_driver = { .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; -static struct agp_device_ids via_agp_device_ids[] __devinitdata = +static struct agp_device_ids via_agp_device_ids[] = { { .device_id = PCI_DEVICE_ID_VIA_82C597_0, diff --git a/drivers/char/hw_random/n2-drv.c b/drivers/char/hw_random/n2-drv.c index ebd48f0..fd57d8a 100644 --- a/drivers/char/hw_random/n2-drv.c +++ b/drivers/char/hw_random/n2-drv.c @@ -25,7 +25,7 @@ #define DRV_MODULE_VERSION "0.2" #define DRV_MODULE_RELDATE "July 27, 2011" -static char version[] __devinitdata = +static char version[] = DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; MODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 1a465a4..e55a7ad 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -3047,7 +3047,7 @@ static inline void wait_for_timer_and_thread(struct smi_info *smi_info) } } -static __devinitdata struct ipmi_default_vals +static struct ipmi_default_vals { int type; int port; diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c index efc4ab3..3b032db 100644 --- a/drivers/char/tpm/tpm_ibmvtpm.c +++ b/drivers/char/tpm/tpm_ibmvtpm.c @@ -32,7 +32,7 @@ static const char tpm_ibmvtpm_driver_name[] = "tpm_ibmvtpm"; -static struct vio_device_id tpm_ibmvtpm_device_table[] __devinitdata = { +static struct vio_device_id tpm_ibmvtpm_device_table[] = { { "IBM,vtpm", "IBM,vtpm"}, { "", "" } }; diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 6bdf267..25fee27 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -769,7 +769,7 @@ static int tpm_tis_pnp_resume(struct pnp_dev *dev) return ret; } -static struct pnp_device_id tpm_pnp_tbl[] __devinitdata = { +static struct pnp_device_id tpm_pnp_tbl[] = { {"PNP0C31", 0}, /* TPM */ {"ATM1200", 0}, /* Atmel */ {"IFX0102", 0}, /* Infineon */ -- cgit v0.10.2 From aa89ed9e369b345ef3737c56e7c8934af2df4aa6 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 19 Nov 2012 13:25:02 -0500 Subject: char: remove use of __devinitconst CONFIG_HOTPLUG is going away as an option so __devinitconst is no longer needed. Signed-off-by: Bill Pemberton Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/char/mbcs.c b/drivers/char/mbcs.c index f74e892..e5d3e3f 100644 --- a/drivers/char/mbcs.c +++ b/drivers/char/mbcs.c @@ -799,7 +799,7 @@ static int mbcs_remove(struct cx_dev *dev) return 0; } -static const struct cx_device_id __devinitconst mbcs_id_table[] = { +static const struct cx_device_id mbcs_id_table[] = { { .part_num = MBCS_PART_NUM, .mfg_num = MBCS_MFG_NUM, diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c index 547ed74..d10085f 100644 --- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c +++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c @@ -785,7 +785,7 @@ static inline int hwicap_of_probe(struct platform_device *op, } #endif /* CONFIG_OF */ -static const struct of_device_id __devinitconst hwicap_of_match[]; +static const struct of_device_id hwicap_of_match[]; static int hwicap_drv_probe(struct platform_device *pdev) { const struct of_device_id *match; @@ -829,7 +829,7 @@ static int __devexit hwicap_drv_remove(struct platform_device *pdev) #ifdef CONFIG_OF /* Match table for device tree binding */ -static const struct of_device_id __devinitconst hwicap_of_match[] = { +static const struct of_device_id hwicap_of_match[] = { { .compatible = "xlnx,opb-hwicap-1.00.b", .data = &buffer_icap_config}, { .compatible = "xlnx,xps-hwicap-1.00.a", .data = &fifo_icap_config}, {}, -- cgit v0.10.2 From 39af33fc458543fd6daaf154e109eba22ab89a8f Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 19 Nov 2012 13:26:26 -0500 Subject: char: remove use of __devexit CONFIG_HOTPLUG is going away as an option so __devexit is no longer needed. Signed-off-by: Bill Pemberton Cc: David Airlie Cc: Olof Johansson Cc: Mattia Dongili Cc: Kent Yoder Cc: Rajiv Andrade Cc: Marcel Selhorst Cc: Sirrix AG Cc: linuxppc-dev@lists.ozlabs.org Cc: linux-arm-kernel@lists.infradead.org Cc: openipmi-developer@lists.sourceforge.net Cc: platform-driver-x86@vger.kernel.org Cc: tpmdd-devel@lists.sourceforge.net Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c index 9c022df..4784935 100644 --- a/drivers/char/agp/ali-agp.c +++ b/drivers/char/agp/ali-agp.c @@ -374,7 +374,7 @@ found: return agp_add_bridge(bridge); } -static void __devexit agp_ali_remove(struct pci_dev *pdev) +static void agp_ali_remove(struct pci_dev *pdev) { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c index 3c7a265..1b21011 100644 --- a/drivers/char/agp/amd-k7-agp.c +++ b/drivers/char/agp/amd-k7-agp.c @@ -480,7 +480,7 @@ static int __devinit agp_amdk7_probe(struct pci_dev *pdev, return agp_add_bridge(bridge); } -static void __devexit agp_amdk7_remove(struct pci_dev *pdev) +static void agp_amdk7_remove(struct pci_dev *pdev) { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index 444f8b6..061d462 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c @@ -579,7 +579,7 @@ static int __devinit agp_amd64_probe(struct pci_dev *pdev, return 0; } -static void __devexit agp_amd64_remove(struct pci_dev *pdev) +static void agp_amd64_remove(struct pci_dev *pdev) { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c index d1c4c23..ed04335 100644 --- a/drivers/char/agp/ati-agp.c +++ b/drivers/char/agp/ati-agp.c @@ -533,7 +533,7 @@ found: return agp_add_bridge(bridge); } -static void __devexit agp_ati_remove(struct pci_dev *pdev) +static void agp_ati_remove(struct pci_dev *pdev) { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); diff --git a/drivers/char/agp/efficeon-agp.c b/drivers/char/agp/efficeon-agp.c index d607f53..55f3e33 100644 --- a/drivers/char/agp/efficeon-agp.c +++ b/drivers/char/agp/efficeon-agp.c @@ -407,7 +407,7 @@ static int __devinit agp_efficeon_probe(struct pci_dev *pdev, return agp_add_bridge(bridge); } -static void __devexit agp_efficeon_remove(struct pci_dev *pdev) +static void agp_efficeon_remove(struct pci_dev *pdev) { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c index 75b763c..d328b66 100644 --- a/drivers/char/agp/i460-agp.c +++ b/drivers/char/agp/i460-agp.c @@ -611,7 +611,7 @@ static int __devinit agp_intel_i460_probe(struct pci_dev *pdev, return agp_add_bridge(bridge); } -static void __devexit agp_intel_i460_remove(struct pci_dev *pdev) +static void agp_intel_i460_remove(struct pci_dev *pdev) { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index b130df0..f3a8f52 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -819,7 +819,7 @@ found_gmch: return err; } -static void __devexit agp_intel_remove(struct pci_dev *pdev) +static void agp_intel_remove(struct pci_dev *pdev) { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c index b9734a9..66e0868 100644 --- a/drivers/char/agp/nvidia-agp.c +++ b/drivers/char/agp/nvidia-agp.c @@ -388,7 +388,7 @@ static int __devinit agp_nvidia_probe(struct pci_dev *pdev, return agp_add_bridge(bridge); } -static void __devexit agp_nvidia_remove(struct pci_dev *pdev) +static void agp_nvidia_remove(struct pci_dev *pdev) { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c index 3a5af2f..a18791d 100644 --- a/drivers/char/agp/sgi-agp.c +++ b/drivers/char/agp/sgi-agp.c @@ -327,7 +327,7 @@ static int __devinit agp_sgi_init(void) return 0; } -static void __devexit agp_sgi_cleanup(void) +static void agp_sgi_cleanup(void) { kfree(sgi_tioca_agp_bridges); sgi_tioca_agp_bridges = NULL; diff --git a/drivers/char/agp/sis-agp.c b/drivers/char/agp/sis-agp.c index c93c9e5e..93d1d31 100644 --- a/drivers/char/agp/sis-agp.c +++ b/drivers/char/agp/sis-agp.c @@ -211,7 +211,7 @@ static int __devinit agp_sis_probe(struct pci_dev *pdev, return agp_add_bridge(bridge); } -static void __devexit agp_sis_remove(struct pci_dev *pdev) +static void agp_sis_remove(struct pci_dev *pdev) { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); diff --git a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c index f02f9b0..26020fb 100644 --- a/drivers/char/agp/sworks-agp.c +++ b/drivers/char/agp/sworks-agp.c @@ -518,7 +518,7 @@ static int __devinit agp_serverworks_probe(struct pci_dev *pdev, return agp_add_bridge(bridge); } -static void __devexit agp_serverworks_remove(struct pci_dev *pdev) +static void agp_serverworks_remove(struct pci_dev *pdev) { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c index af02da4..011967a 100644 --- a/drivers/char/agp/uninorth-agp.c +++ b/drivers/char/agp/uninorth-agp.c @@ -663,7 +663,7 @@ static int __devinit agp_uninorth_probe(struct pci_dev *pdev, return agp_add_bridge(bridge); } -static void __devexit agp_uninorth_remove(struct pci_dev *pdev) +static void agp_uninorth_remove(struct pci_dev *pdev) { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); diff --git a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c index 97706834..6818595 100644 --- a/drivers/char/agp/via-agp.c +++ b/drivers/char/agp/via-agp.c @@ -485,7 +485,7 @@ static int __devinit agp_via_probe(struct pci_dev *pdev, return agp_add_bridge(bridge); } -static void __devexit agp_via_remove(struct pci_dev *pdev) +static void agp_via_remove(struct pci_dev *pdev) { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); diff --git a/drivers/char/hw_random/atmel-rng.c b/drivers/char/hw_random/atmel-rng.c index 731c904..5a4a6e7 100644 --- a/drivers/char/hw_random/atmel-rng.c +++ b/drivers/char/hw_random/atmel-rng.c @@ -98,7 +98,7 @@ err_enable: return ret; } -static int __devexit atmel_trng_remove(struct platform_device *pdev) +static int atmel_trng_remove(struct platform_device *pdev) { struct atmel_trng *trng = platform_get_drvdata(pdev); diff --git a/drivers/char/hw_random/bcm63xx-rng.c b/drivers/char/hw_random/bcm63xx-rng.c index aec6a42..ae95bcb 100644 --- a/drivers/char/hw_random/bcm63xx-rng.c +++ b/drivers/char/hw_random/bcm63xx-rng.c @@ -145,7 +145,7 @@ out: return ret; } -static int __devexit bcm63xx_rng_remove(struct platform_device *pdev) +static int bcm63xx_rng_remove(struct platform_device *pdev) { struct hwrng *rng = platform_get_drvdata(pdev); struct bcm63xx_rng_priv *priv = to_rng_priv(rng); diff --git a/drivers/char/hw_random/exynos-rng.c b/drivers/char/hw_random/exynos-rng.c index 232ba9c..bdc852e 100644 --- a/drivers/char/hw_random/exynos-rng.c +++ b/drivers/char/hw_random/exynos-rng.c @@ -134,7 +134,7 @@ static int __devinit exynos_rng_probe(struct platform_device *pdev) return hwrng_register(&exynos_rng->rng); } -static int __devexit exynos_rng_remove(struct platform_device *pdev) +static int exynos_rng_remove(struct platform_device *pdev) { struct exynos_rng *exynos_rng = platform_get_drvdata(pdev); diff --git a/drivers/char/hw_random/n2-drv.c b/drivers/char/hw_random/n2-drv.c index fd57d8a..d68a72a 100644 --- a/drivers/char/hw_random/n2-drv.c +++ b/drivers/char/hw_random/n2-drv.c @@ -719,7 +719,7 @@ out: return err; } -static int __devexit n2rng_remove(struct platform_device *op) +static int n2rng_remove(struct platform_device *op) { struct n2rng *np = dev_get_drvdata(&op->dev); diff --git a/drivers/char/hw_random/pasemi-rng.c b/drivers/char/hw_random/pasemi-rng.c index 3a63267..a1f7040 100644 --- a/drivers/char/hw_random/pasemi-rng.c +++ b/drivers/char/hw_random/pasemi-rng.c @@ -122,7 +122,7 @@ static int __devinit rng_probe(struct platform_device *ofdev) return err; } -static int __devexit rng_remove(struct platform_device *dev) +static int rng_remove(struct platform_device *dev) { void __iomem *rng_regs = (void __iomem *)pasemi_rng.priv; diff --git a/drivers/char/hw_random/picoxcell-rng.c b/drivers/char/hw_random/picoxcell-rng.c index 97bd891..d4b24c1 100644 --- a/drivers/char/hw_random/picoxcell-rng.c +++ b/drivers/char/hw_random/picoxcell-rng.c @@ -151,7 +151,7 @@ err_enable: return ret; } -static int __devexit picoxcell_trng_remove(struct platform_device *pdev) +static int picoxcell_trng_remove(struct platform_device *pdev) { hwrng_unregister(&picoxcell_trng); clk_disable(rng_clk); diff --git a/drivers/char/hw_random/ppc4xx-rng.c b/drivers/char/hw_random/ppc4xx-rng.c index c51762c..af6506a 100644 --- a/drivers/char/hw_random/ppc4xx-rng.c +++ b/drivers/char/hw_random/ppc4xx-rng.c @@ -111,7 +111,7 @@ static int __devinit ppc4xx_rng_probe(struct platform_device *dev) return err; } -static int __devexit ppc4xx_rng_remove(struct platform_device *dev) +static int ppc4xx_rng_remove(struct platform_device *dev) { void __iomem *rng_regs = (void __iomem *) ppc4xx_rng.priv; diff --git a/drivers/char/hw_random/timeriomem-rng.c b/drivers/char/hw_random/timeriomem-rng.c index f1a1618..3a1abc9 100644 --- a/drivers/char/hw_random/timeriomem-rng.c +++ b/drivers/char/hw_random/timeriomem-rng.c @@ -130,7 +130,7 @@ failed: return ret; } -static int __devexit timeriomem_rng_remove(struct platform_device *pdev) +static int timeriomem_rng_remove(struct platform_device *pdev) { del_timer_sync(&timeriomem_rng_timer); hwrng_unregister(&timeriomem_rng_ops); diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c index 5708299..621f595 100644 --- a/drivers/char/hw_random/virtio-rng.c +++ b/drivers/char/hw_random/virtio-rng.c @@ -119,7 +119,7 @@ static int virtrng_probe(struct virtio_device *vdev) return probe_common(vdev); } -static void __devexit virtrng_remove(struct virtio_device *vdev) +static void virtrng_remove(struct virtio_device *vdev) { remove_common(vdev); } diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index e55a7ad..20ab5b3 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -2228,7 +2228,7 @@ err_free: return -EINVAL; } -static void __devexit ipmi_pnp_remove(struct pnp_dev *dev) +static void ipmi_pnp_remove(struct pnp_dev *dev) { struct smi_info *info = pnp_get_drvdata(dev); @@ -2529,7 +2529,7 @@ static int ipmi_pci_probe(struct pci_dev *pdev, return 0; } -static void __devexit ipmi_pci_remove(struct pci_dev *pdev) +static void ipmi_pci_remove(struct pci_dev *pdev) { struct smi_info *info = pci_get_drvdata(pdev); cleanup_one_si(info); @@ -2635,7 +2635,7 @@ static int ipmi_probe(struct platform_device *dev) return 0; } -static int __devexit ipmi_remove(struct platform_device *dev) +static int ipmi_remove(struct platform_device *dev) { #ifdef CONFIG_OF cleanup_one_si(dev_get_drvdata(&dev->dev)); diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index 861efa4..d780295 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -1428,7 +1428,7 @@ static int sonypi_probe(struct platform_device *dev) return error; } -static int __devexit sonypi_remove(struct platform_device *dev) +static int sonypi_remove(struct platform_device *dev) { sonypi_disable(); diff --git a/drivers/char/tb0219.c b/drivers/char/tb0219.c index 76e3aea..34c63f8 100644 --- a/drivers/char/tb0219.c +++ b/drivers/char/tb0219.c @@ -318,7 +318,7 @@ static int tb0219_probe(struct platform_device *dev) return 0; } -static int __devexit tb0219_remove(struct platform_device *dev) +static int tb0219_remove(struct platform_device *dev) { _machine_restart = old_machine_restart; diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c index 5a831ae..78983b7 100644 --- a/drivers/char/tpm/tpm_i2c_infineon.c +++ b/drivers/char/tpm/tpm_i2c_infineon.c @@ -656,7 +656,7 @@ static int __devinit tpm_tis_i2c_probe(struct i2c_client *client, return rc; } -static int __devexit tpm_tis_i2c_remove(struct i2c_client *client) +static int tpm_tis_i2c_remove(struct i2c_client *client) { struct tpm_chip *chip = tpm_dev.chip; release_locality(chip, chip->vendor.locality, 1); diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c index 3b032db..5a72f39 100644 --- a/drivers/char/tpm/tpm_ibmvtpm.c +++ b/drivers/char/tpm/tpm_ibmvtpm.c @@ -267,7 +267,7 @@ static int ibmvtpm_crq_send_init(struct ibmvtpm_dev *ibmvtpm) * Return value: * 0 */ -static int __devexit tpm_ibmvtpm_remove(struct vio_dev *vdev) +static int tpm_ibmvtpm_remove(struct vio_dev *vdev) { struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(&vdev->dev); int rc = 0; diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c index 3251a44..4dd5f8a 100644 --- a/drivers/char/tpm/tpm_infineon.c +++ b/drivers/char/tpm/tpm_infineon.c @@ -594,7 +594,7 @@ err_last: return rc; } -static __devexit void tpm_inf_pnp_remove(struct pnp_dev *dev) +static void tpm_inf_pnp_remove(struct pnp_dev *dev) { struct tpm_chip *chip = pnp_get_drvdata(dev); diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 25fee27..a599cc2 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -783,7 +783,7 @@ static struct pnp_device_id tpm_pnp_tbl[] = { }; MODULE_DEVICE_TABLE(pnp, tpm_pnp_tbl); -static __devexit void tpm_tis_pnp_remove(struct pnp_dev *dev) +static void tpm_tis_pnp_remove(struct pnp_dev *dev) { struct tpm_chip *chip = pnp_get_drvdata(dev); diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c index d10085f..5224da5 100644 --- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c +++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c @@ -717,7 +717,7 @@ static struct hwicap_driver_config fifo_icap_config = { .reset = fifo_icap_reset, }; -static int __devexit hwicap_remove(struct device *dev) +static int hwicap_remove(struct device *dev) { struct hwicap_drvdata *drvdata; @@ -822,7 +822,7 @@ static int hwicap_drv_probe(struct platform_device *pdev) &buffer_icap_config, regs); } -static int __devexit hwicap_drv_remove(struct platform_device *pdev) +static int hwicap_drv_remove(struct platform_device *pdev) { return hwicap_remove(&pdev->dev); } -- cgit v0.10.2 From 5a59509b4753c281d3003eb996c8137bef62e5a9 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 19 Nov 2012 13:21:07 -0500 Subject: uio: remove use of __devexit_p CONFIG_HOTPLUG is going away as an option so __devexit_p is no longer needed. Signed-off-by: Bill Pemberton Cc: "Hans J. Koch" Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/uio/uio_pruss.c b/drivers/uio/uio_pruss.c index 33a7a27..d877d64 100644 --- a/drivers/uio/uio_pruss.c +++ b/drivers/uio/uio_pruss.c @@ -220,7 +220,7 @@ static int __devexit pruss_remove(struct platform_device *dev) static struct platform_driver pruss_driver = { .probe = pruss_probe, - .remove = __devexit_p(pruss_remove), + .remove = pruss_remove, .driver = { .name = DRV_NAME, .owner = THIS_MODULE, -- cgit v0.10.2 From b17b75bb524c6c0dfa5ee4a33591b8a7dcc034d2 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 19 Nov 2012 13:21:49 -0500 Subject: uio: remove use of __devinit CONFIG_HOTPLUG is going away as an option so __devinit is no longer needed. Signed-off-by: Bill Pemberton Cc: "Hans J. Koch" Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/uio/uio_aec.c b/drivers/uio/uio_aec.c index 72b22d4..1548982 100644 --- a/drivers/uio/uio_aec.c +++ b/drivers/uio/uio_aec.c @@ -78,7 +78,7 @@ static void print_board_data(struct pci_dev *pdev, struct uio_info *i) ioread8(i->priv + 0x07)); } -static int __devinit probe(struct pci_dev *pdev, const struct pci_device_id *id) +static int probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct uio_info *info; int ret; diff --git a/drivers/uio/uio_cif.c b/drivers/uio/uio_cif.c index a84a451..674783f 100644 --- a/drivers/uio/uio_cif.c +++ b/drivers/uio/uio_cif.c @@ -40,7 +40,7 @@ static irqreturn_t hilscher_handler(int irq, struct uio_info *dev_info) return IRQ_HANDLED; } -static int __devinit hilscher_pci_probe(struct pci_dev *dev, +static int hilscher_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { struct uio_info *info; diff --git a/drivers/uio/uio_netx.c b/drivers/uio/uio_netx.c index a879fd5..6a4ba5e 100644 --- a/drivers/uio/uio_netx.c +++ b/drivers/uio/uio_netx.c @@ -48,7 +48,7 @@ static irqreturn_t netx_handler(int irq, struct uio_info *dev_info) return IRQ_HANDLED; } -static int __devinit netx_pci_probe(struct pci_dev *dev, +static int netx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { struct uio_info *info; diff --git a/drivers/uio/uio_pci_generic.c b/drivers/uio/uio_pci_generic.c index 0bd08ef..14aa10c 100644 --- a/drivers/uio/uio_pci_generic.c +++ b/drivers/uio/uio_pci_generic.c @@ -53,7 +53,7 @@ static irqreturn_t irqhandler(int irq, struct uio_info *info) return IRQ_HANDLED; } -static int __devinit probe(struct pci_dev *pdev, +static int probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct uio_pci_generic_dev *gdev; diff --git a/drivers/uio/uio_pruss.c b/drivers/uio/uio_pruss.c index d877d64..098d3d0 100644 --- a/drivers/uio/uio_pruss.c +++ b/drivers/uio/uio_pruss.c @@ -112,7 +112,7 @@ static void pruss_cleanup(struct platform_device *dev, kfree(gdev); } -static int __devinit pruss_probe(struct platform_device *dev) +static int pruss_probe(struct platform_device *dev) { struct uio_info *p; struct uio_pruss_dev *gdev; diff --git a/drivers/uio/uio_sercos3.c b/drivers/uio/uio_sercos3.c index a187fa1..2e87808 100644 --- a/drivers/uio/uio_sercos3.c +++ b/drivers/uio/uio_sercos3.c @@ -116,7 +116,7 @@ static int sercos3_setup_iomem(struct pci_dev *dev, struct uio_info *info, return 0; } -static int __devinit sercos3_pci_probe(struct pci_dev *dev, +static int sercos3_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { struct uio_info *info; -- cgit v0.10.2 From d46f743822ee6e890a6e7971e089a020e6c0000a Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 19 Nov 2012 13:24:33 -0500 Subject: uio: remove use of __devinitdata CONFIG_HOTPLUG is going away as an option so __devinitdata is no longer needed. Signed-off-by: Bill Pemberton Cc: "Hans J. Koch" Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/uio/uio_cif.c b/drivers/uio/uio_cif.c index 674783f..7dd6fc6 100644 --- a/drivers/uio/uio_cif.c +++ b/drivers/uio/uio_cif.c @@ -112,7 +112,7 @@ static void hilscher_pci_remove(struct pci_dev *dev) kfree (info); } -static struct pci_device_id hilscher_pci_ids[] __devinitdata = { +static struct pci_device_id hilscher_pci_ids[] = { { .vendor = PCI_VENDOR_ID_PLX, .device = PCI_DEVICE_ID_PLX_9030, diff --git a/drivers/uio/uio_sercos3.c b/drivers/uio/uio_sercos3.c index 2e87808..81a10a5 100644 --- a/drivers/uio/uio_sercos3.c +++ b/drivers/uio/uio_sercos3.c @@ -197,7 +197,7 @@ static void sercos3_pci_remove(struct pci_dev *dev) kfree(info); } -static struct pci_device_id sercos3_pci_ids[] __devinitdata = { +static struct pci_device_id sercos3_pci_ids[] = { { .vendor = PCI_VENDOR_ID_PLX, .device = PCI_DEVICE_ID_PLX_9030, -- cgit v0.10.2 From 9b96c3124b66a959ba061dbca339944a81686cd2 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 19 Nov 2012 13:26:19 -0500 Subject: uio: remove use of __devexit CONFIG_HOTPLUG is going away as an option so __devexit is no longer needed. Signed-off-by: Bill Pemberton Cc: "Hans J. Koch" Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/uio/uio_pruss.c b/drivers/uio/uio_pruss.c index 098d3d0..cce0f78 100644 --- a/drivers/uio/uio_pruss.c +++ b/drivers/uio/uio_pruss.c @@ -209,7 +209,7 @@ out_free: return ret; } -static int __devexit pruss_remove(struct platform_device *dev) +static int pruss_remove(struct platform_device *dev) { struct uio_pruss_dev *gdev = platform_get_drvdata(dev); -- cgit v0.10.2 From 24fce61b0b7f1bc94970036db1f1d65b0770d168 Mon Sep 17 00:00:00 2001 From: Damian Hobson-Garcia Date: Fri, 16 Nov 2012 14:46:09 +0900 Subject: drivers: uio_dmem_genirq: Don't mix address spaces for dynamic region vaddr Assigning the virtual address returned from dma_alloc_coherent to the the internal_addr element of uioinfo produces the following sparse errors since internal_addr is a void __iomem * and dma_alloc_coherent returns void *. + drivers/uio/uio_dmem_genirq.c:65:39: sparse: incorrect type in assignment (different address spaces) drivers/uio/uio_dmem_genirq.c:65:39: expected void [noderef] *internal_addr drivers/uio/uio_dmem_genirq.c:65:39: got void *[assigned] addr + drivers/uio/uio_dmem_genirq.c:93:17: sparse: incorrect type in argument 3 (different address spaces) drivers/uio/uio_dmem_genirq.c:93:17: expected void *vaddr drivers/uio/uio_dmem_genirq.c:93:17: got void [noderef] *internal_addr Store the void * in the driver's private data instead. Reported-by: Fengguang Wu Signed-off-by: Damian Hobson-Garcia Cc: "Hans J. Koch" Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/uio/uio_dmem_genirq.c b/drivers/uio/uio_dmem_genirq.c index 4d4dd00..d8bbe07 100644 --- a/drivers/uio/uio_dmem_genirq.c +++ b/drivers/uio/uio_dmem_genirq.c @@ -37,6 +37,7 @@ struct uio_dmem_genirq_platdata { struct platform_device *pdev; unsigned int dmem_region_start; unsigned int num_dmem_regions; + void *dmem_region_vaddr[MAX_UIO_MAPS]; struct mutex alloc_lock; unsigned int refcnt; }; @@ -46,6 +47,7 @@ static int uio_dmem_genirq_open(struct uio_info *info, struct inode *inode) struct uio_dmem_genirq_platdata *priv = info->priv; struct uio_mem *uiomem; int ret = 0; + int dmem_region = priv->dmem_region_start; uiomem = &priv->uioinfo->mem[priv->dmem_region_start]; @@ -61,8 +63,7 @@ static int uio_dmem_genirq_open(struct uio_info *info, struct inode *inode) ret = -ENOMEM; break; } - - uiomem->internal_addr = addr; + priv->dmem_region_vaddr[dmem_region++] = addr; ++uiomem; } priv->refcnt++; @@ -77,6 +78,7 @@ static int uio_dmem_genirq_release(struct uio_info *info, struct inode *inode) { struct uio_dmem_genirq_platdata *priv = info->priv; struct uio_mem *uiomem; + int dmem_region = priv->dmem_region_start; /* Tell the Runtime PM code that the device has become idle */ pm_runtime_put_sync(&priv->pdev->dev); @@ -91,7 +93,8 @@ static int uio_dmem_genirq_release(struct uio_info *info, struct inode *inode) break; dma_free_coherent(&priv->pdev->dev, uiomem->size, - uiomem->internal_addr, uiomem->addr); + priv->dmem_region_vaddr[dmem_region++], + uiomem->addr); uiomem->addr = DMA_ERROR_CODE; ++uiomem; } -- cgit v0.10.2 From 87c4d1a7dce956b86e34329ed1b11a751ba9a8ea Mon Sep 17 00:00:00 2001 From: Damian Hobson-Garcia Date: Fri, 16 Nov 2012 14:46:10 +0900 Subject: drivers: uio_dmem_genirq: Don't use DMA_ERROR_CODE to indicate unmapped regions DMA_ERROR_CODE is not defined on all architectures and is architecture specific. Instead, use the constant, ~0 to indicate unmapped regions. Reported-by: Fengguang Wu Reported-by: Geert Uytterhoeven Signed-off-by: Damian Hobson-Garcia Cc: "Hans J. Koch" Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/DocBook/uio-howto.tmpl b/Documentation/DocBook/uio-howto.tmpl index fdbf86f..ddb05e9 100644 --- a/Documentation/DocBook/uio-howto.tmpl +++ b/Documentation/DocBook/uio-howto.tmpl @@ -771,7 +771,7 @@ framework to set up sysfs files for this region. Simply leave it alone. /sys/class/uio/uioX/maps/mapY/*. The dynmaic memory regions will be freed when the UIO device file is closed. When no processes are holding the device file open, the address - returned to userspace is DMA_ERROR_CODE. + returned to userspace is ~0. diff --git a/drivers/uio/uio_dmem_genirq.c b/drivers/uio/uio_dmem_genirq.c index d8bbe07..7be8d04 100644 --- a/drivers/uio/uio_dmem_genirq.c +++ b/drivers/uio/uio_dmem_genirq.c @@ -29,6 +29,7 @@ #include #define DRIVER_NAME "uio_dmem_genirq" +#define DMEM_MAP_ERROR (~0) struct uio_dmem_genirq_platdata { struct uio_info *uioinfo; @@ -60,6 +61,7 @@ static int uio_dmem_genirq_open(struct uio_info *info, struct inode *inode) addr = dma_alloc_coherent(&priv->pdev->dev, uiomem->size, (dma_addr_t *)&uiomem->addr, GFP_KERNEL); if (!addr) { + uiomem->addr = DMEM_MAP_ERROR; ret = -ENOMEM; break; } @@ -95,7 +97,7 @@ static int uio_dmem_genirq_release(struct uio_info *info, struct inode *inode) dma_free_coherent(&priv->pdev->dev, uiomem->size, priv->dmem_region_vaddr[dmem_region++], uiomem->addr); - uiomem->addr = DMA_ERROR_CODE; + uiomem->addr = DMEM_MAP_ERROR; ++uiomem; } @@ -238,7 +240,7 @@ static int uio_dmem_genirq_probe(struct platform_device *pdev) break; } uiomem->memtype = UIO_MEM_PHYS; - uiomem->addr = DMA_ERROR_CODE; + uiomem->addr = DMEM_MAP_ERROR; uiomem->size = pdata->dynamic_region_sizes[i]; ++uiomem; } -- cgit v0.10.2 From 439926c81c01f31f9ffa7af7bf2d242b7f794f3c Mon Sep 17 00:00:00 2001 From: Damian Hobson-Garcia Date: Fri, 16 Nov 2012 14:46:11 +0900 Subject: drivers: uio_dmem_genirq: Allow partial success when opening device The uio device should not fail on open just because one memory allocation fails. The device might export several regions, the failure of some of which may or may not be a problem for the user space driver. Failing regions will remain unmapped, and successful regions will be mapped and exported to user space. Also deals with the case where failing to map a region after successfully allocating others would not unmap the successfully allocated regions before dying. Signed-off-by: Damian Hobson-Garcia Cc: "Hans J. Koch" Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/uio/uio_dmem_genirq.c b/drivers/uio/uio_dmem_genirq.c index 7be8d04..bbdf925 100644 --- a/drivers/uio/uio_dmem_genirq.c +++ b/drivers/uio/uio_dmem_genirq.c @@ -62,8 +62,6 @@ static int uio_dmem_genirq_open(struct uio_info *info, struct inode *inode) (dma_addr_t *)&uiomem->addr, GFP_KERNEL); if (!addr) { uiomem->addr = DMEM_MAP_ERROR; - ret = -ENOMEM; - break; } priv->dmem_region_vaddr[dmem_region++] = addr; ++uiomem; @@ -93,11 +91,13 @@ static int uio_dmem_genirq_release(struct uio_info *info, struct inode *inode) while (!priv->refcnt && uiomem < &priv->uioinfo->mem[MAX_UIO_MAPS]) { if (!uiomem->size) break; - - dma_free_coherent(&priv->pdev->dev, uiomem->size, - priv->dmem_region_vaddr[dmem_region++], - uiomem->addr); + if (priv->dmem_region_vaddr[dmem_region]) { + dma_free_coherent(&priv->pdev->dev, uiomem->size, + priv->dmem_region_vaddr[dmem_region], + uiomem->addr); + } uiomem->addr = DMEM_MAP_ERROR; + ++dmem_region; ++uiomem; } -- cgit v0.10.2 From d5185c4eb3a022f7e7a435238c2b0b885e6b4821 Mon Sep 17 00:00:00 2001 From: Damian Hobson-Garcia Date: Fri, 16 Nov 2012 14:46:12 +0900 Subject: drivers: uio: Only allocate new private data when probing device tree node The same condition should be used both when allocating and freeing the driver private data. When dev.of_node is non NULL, allocate a new private data structure, otherwise use the values from the platform data. Reported-by: Fengguang Wu Signed-off-by: Damian Hobson-Garcia Cc: "Hans J. Koch" Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/uio/uio_dmem_genirq.c b/drivers/uio/uio_dmem_genirq.c index bbdf925..252434c 100644 --- a/drivers/uio/uio_dmem_genirq.c +++ b/drivers/uio/uio_dmem_genirq.c @@ -153,7 +153,7 @@ static int uio_dmem_genirq_probe(struct platform_device *pdev) int ret = -EINVAL; int i; - if (!uioinfo) { + if (pdev->dev.of_node) { int irq; /* alloc uioinfo for one device */ diff --git a/drivers/uio/uio_pdrv_genirq.c b/drivers/uio/uio_pdrv_genirq.c index ac988ce..c122bca 100644 --- a/drivers/uio/uio_pdrv_genirq.c +++ b/drivers/uio/uio_pdrv_genirq.c @@ -102,7 +102,7 @@ static int uio_pdrv_genirq_probe(struct platform_device *pdev) int ret = -EINVAL; int i; - if (!uioinfo) { + if (pdev->dev.of_node) { int irq; /* alloc uioinfo for one device */ -- cgit v0.10.2 From 93ed0327808f7d7ef0fc90114c3457629dd683c1 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 19 Nov 2012 13:25:49 -0500 Subject: extcon: remove use of __devexit CONFIG_HOTPLUG is going away as an option so __devexit is no longer needed. Signed-off-by: Bill Pemberton Cc: MyungJoo Ham Cc: Chanwoo Choi Acked-by: Mark Brown Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/extcon/extcon-adc-jack.c b/drivers/extcon/extcon-adc-jack.c index e87196f..b88ae91 100644 --- a/drivers/extcon/extcon-adc-jack.c +++ b/drivers/extcon/extcon-adc-jack.c @@ -175,7 +175,7 @@ out: return err; } -static int __devexit adc_jack_remove(struct platform_device *pdev) +static int adc_jack_remove(struct platform_device *pdev) { struct adc_jack_data *data = platform_get_drvdata(pdev); diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index cdab9e5..c4ea28c 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -517,7 +517,7 @@ err: return ret; } -static int __devexit arizona_extcon_remove(struct platform_device *pdev) +static int arizona_extcon_remove(struct platform_device *pdev) { struct arizona_extcon_info *info = platform_get_drvdata(pdev); struct arizona *arizona = info->arizona; diff --git a/drivers/extcon/extcon-gpio.c b/drivers/extcon/extcon-gpio.c index 71d3ab7..3fe3381 100644 --- a/drivers/extcon/extcon-gpio.c +++ b/drivers/extcon/extcon-gpio.c @@ -137,7 +137,7 @@ err: return ret; } -static int __devexit gpio_extcon_remove(struct platform_device *pdev) +static int gpio_extcon_remove(struct platform_device *pdev) { struct gpio_extcon_data *extcon_data = platform_get_drvdata(pdev); diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c index a17d0d9..3cde2c5 100644 --- a/drivers/extcon/extcon-max77693.c +++ b/drivers/extcon/extcon-max77693.c @@ -774,7 +774,7 @@ err_kfree: return ret; } -static int __devexit max77693_muic_remove(struct platform_device *pdev) +static int max77693_muic_remove(struct platform_device *pdev) { struct max77693_muic_info *info = platform_get_drvdata(pdev); int i; diff --git a/drivers/extcon/extcon-max8997.c b/drivers/extcon/extcon-max8997.c index 77b66b0..b85189b 100644 --- a/drivers/extcon/extcon-max8997.c +++ b/drivers/extcon/extcon-max8997.c @@ -508,7 +508,7 @@ err_kfree: return ret; } -static int __devexit max8997_muic_remove(struct platform_device *pdev) +static int max8997_muic_remove(struct platform_device *pdev) { struct max8997_muic_info *info = platform_get_drvdata(pdev); int i; -- cgit v0.10.2 From 44f34fd4a7f80439f14bdd2df032b0b4427c4ab0 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 19 Nov 2012 13:23:21 -0500 Subject: extcon: remove use of __devinit CONFIG_HOTPLUG is going away as an option so __devinit is no longer needed. Signed-off-by: Bill Pemberton Cc: MyungJoo Ham Cc: Chanwoo Choi Acked-by: Mark Brown Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/extcon/extcon-adc-jack.c b/drivers/extcon/extcon-adc-jack.c index b88ae91..84144e6 100644 --- a/drivers/extcon/extcon-adc-jack.c +++ b/drivers/extcon/extcon-adc-jack.c @@ -91,7 +91,7 @@ static irqreturn_t adc_jack_irq_thread(int irq, void *_data) return IRQ_HANDLED; } -static int __devinit adc_jack_probe(struct platform_device *pdev) +static int adc_jack_probe(struct platform_device *pdev) { struct adc_jack_data *data; struct adc_jack_pdata *pdata = pdev->dev.platform_data; diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index c4ea28c..2473be9 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -337,7 +337,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data) return IRQ_HANDLED; } -static int __devinit arizona_extcon_probe(struct platform_device *pdev) +static int arizona_extcon_probe(struct platform_device *pdev) { struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); struct arizona_pdata *pdata; diff --git a/drivers/extcon/extcon-gpio.c b/drivers/extcon/extcon-gpio.c index 3fe3381..e02219e 100644 --- a/drivers/extcon/extcon-gpio.c +++ b/drivers/extcon/extcon-gpio.c @@ -76,7 +76,7 @@ static ssize_t extcon_gpio_print_state(struct extcon_dev *edev, char *buf) return -EINVAL; } -static int __devinit gpio_extcon_probe(struct platform_device *pdev) +static int gpio_extcon_probe(struct platform_device *pdev) { struct gpio_extcon_platform_data *pdata = pdev->dev.platform_data; struct gpio_extcon_data *extcon_data; diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c index 3cde2c5..437f573 100644 --- a/drivers/extcon/extcon-max77693.c +++ b/drivers/extcon/extcon-max77693.c @@ -648,7 +648,7 @@ out: return ret; } -static int __devinit max77693_muic_probe(struct platform_device *pdev) +static int max77693_muic_probe(struct platform_device *pdev) { struct max77693_dev *max77693 = dev_get_drvdata(pdev->dev.parent); struct max77693_platform_data *pdata = dev_get_platdata(max77693->dev); diff --git a/drivers/extcon/extcon-max8997.c b/drivers/extcon/extcon-max8997.c index b85189b..4981299 100644 --- a/drivers/extcon/extcon-max8997.c +++ b/drivers/extcon/extcon-max8997.c @@ -426,7 +426,7 @@ static void max8997_muic_detect_dev(struct max8997_muic_info *info) max8997_muic_handle_charger_type(info, chg_type); } -static int __devinit max8997_muic_probe(struct platform_device *pdev) +static int max8997_muic_probe(struct platform_device *pdev) { struct max8997_dev *max8997 = dev_get_drvdata(pdev->dev.parent); struct max8997_platform_data *pdata = dev_get_platdata(max8997->dev); -- cgit v0.10.2 From 5f7e22283cec597e532b75d5a455ce6ed75de362 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 19 Nov 2012 13:20:06 -0500 Subject: extcon: remove use of __devexit_p CONFIG_HOTPLUG is going away as an option so __devexit_p is no longer needed. Signed-off-by: Bill Pemberton Cc: MyungJoo Ham Cc: Chanwoo Choi Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/extcon/extcon-adc-jack.c b/drivers/extcon/extcon-adc-jack.c index 84144e6..eda2a1aa 100644 --- a/drivers/extcon/extcon-adc-jack.c +++ b/drivers/extcon/extcon-adc-jack.c @@ -188,7 +188,7 @@ static int adc_jack_remove(struct platform_device *pdev) static struct platform_driver adc_jack_driver = { .probe = adc_jack_probe, - .remove = __devexit_p(adc_jack_remove), + .remove = adc_jack_remove, .driver = { .name = "adc-jack", .owner = THIS_MODULE, diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index 2473be9..f10f05d 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -544,7 +544,7 @@ static struct platform_driver arizona_extcon_driver = { .owner = THIS_MODULE, }, .probe = arizona_extcon_probe, - .remove = __devexit_p(arizona_extcon_remove), + .remove = arizona_extcon_remove, }; module_platform_driver(arizona_extcon_driver); diff --git a/drivers/extcon/extcon-gpio.c b/drivers/extcon/extcon-gpio.c index e02219e..1b14bfc 100644 --- a/drivers/extcon/extcon-gpio.c +++ b/drivers/extcon/extcon-gpio.c @@ -150,7 +150,7 @@ static int gpio_extcon_remove(struct platform_device *pdev) static struct platform_driver gpio_extcon_driver = { .probe = gpio_extcon_probe, - .remove = __devexit_p(gpio_extcon_remove), + .remove = gpio_extcon_remove, .driver = { .name = "extcon-gpio", .owner = THIS_MODULE, diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c index 437f573..b656dfa 100644 --- a/drivers/extcon/extcon-max77693.c +++ b/drivers/extcon/extcon-max77693.c @@ -795,7 +795,7 @@ static struct platform_driver max77693_muic_driver = { .owner = THIS_MODULE, }, .probe = max77693_muic_probe, - .remove = __devexit_p(max77693_muic_remove), + .remove = max77693_muic_remove, }; module_platform_driver(max77693_muic_driver); diff --git a/drivers/extcon/extcon-max8997.c b/drivers/extcon/extcon-max8997.c index 4981299..bad76f5 100644 --- a/drivers/extcon/extcon-max8997.c +++ b/drivers/extcon/extcon-max8997.c @@ -531,7 +531,7 @@ static struct platform_driver max8997_muic_driver = { .owner = THIS_MODULE, }, .probe = max8997_muic_probe, - .remove = __devexit_p(max8997_muic_remove), + .remove = max8997_muic_remove, }; module_platform_driver(max8997_muic_driver); -- cgit v0.10.2 From 277ed0d542778182c863c30bdbd2441dee3f964c Mon Sep 17 00:00:00 2001 From: Pantelis Antoniou Date: Thu, 22 Nov 2012 01:13:29 +0400 Subject: w1-gpio: Pinctrl-fy Enable pinctrl for w1-gpio. Acked-by: Tony Lindgren Signed-off-by: Pantelis Antoniou Signed-off-by: Evgeniy Polyakov Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c index 6012c4e..aec35bd 100644 --- a/drivers/w1/masters/w1-gpio.c +++ b/drivers/w1/masters/w1-gpio.c @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include "../w1.h" #include "../w1_int.h" @@ -85,8 +87,13 @@ static int __init w1_gpio_probe(struct platform_device *pdev) { struct w1_bus_master *master; struct w1_gpio_platform_data *pdata; + struct pinctrl *pinctrl; int err; + pinctrl = devm_pinctrl_get_select_default(&pdev->dev); + if (IS_ERR(pinctrl)) + dev_warn(&pdev->dev, "unable to select pin group\n"); + err = w1_gpio_probe_dt(pdev); if (err < 0) return err; -- cgit v0.10.2 From 8a1861d997d698a120401f3c125085679f729d64 Mon Sep 17 00:00:00 2001 From: Pantelis Antoniou Date: Thu, 22 Nov 2012 01:13:47 +0400 Subject: w1-gpio: Simplify & get rid of defines There's no reason to have the OF defines; it complicates the driver. There's also no need for the funky platform_driver_probe. Add a few warnings in case there's a failure; helps us find out what went wrong. Signed-off-by: Pantelis Antoniou Signed-off-by: Evgeniy Polyakov Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c index aec35bd..85b363a 100644 --- a/drivers/w1/masters/w1-gpio.c +++ b/drivers/w1/masters/w1-gpio.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "../w1.h" #include "../w1_int.h" @@ -46,7 +47,6 @@ static u8 w1_gpio_read_bit(void *data) return gpio_get_value(pdata->pin) ? 1 : 0; } -#ifdef CONFIG_OF static struct of_device_id w1_gpio_dt_ids[] = { { .compatible = "w1-gpio" }, {} @@ -57,11 +57,6 @@ static int w1_gpio_probe_dt(struct platform_device *pdev) { struct w1_gpio_platform_data *pdata = pdev->dev.platform_data; struct device_node *np = pdev->dev.of_node; - const struct of_device_id *of_id = - of_match_device(w1_gpio_dt_ids, &pdev->dev); - - if (!of_id) - return 0; pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) @@ -76,12 +71,6 @@ static int w1_gpio_probe_dt(struct platform_device *pdev) return 0; } -#else -static int w1_gpio_probe_dt(struct platform_device *pdev) -{ - return 0; -} -#endif static int __init w1_gpio_probe(struct platform_device *pdev) { @@ -94,28 +83,41 @@ static int __init w1_gpio_probe(struct platform_device *pdev) if (IS_ERR(pinctrl)) dev_warn(&pdev->dev, "unable to select pin group\n"); - err = w1_gpio_probe_dt(pdev); - if (err < 0) - return err; + if (of_have_populated_dt()) { + err = w1_gpio_probe_dt(pdev); + if (err < 0) { + dev_err(&pdev->dev, "Failed to parse DT\n"); + return err; + } + } pdata = pdev->dev.platform_data; - if (!pdata) + if (!pdata) { + dev_err(&pdev->dev, "No configuration data\n"); return -ENXIO; + } master = kzalloc(sizeof(struct w1_bus_master), GFP_KERNEL); - if (!master) + if (!master) { + dev_err(&pdev->dev, "Out of memory\n"); return -ENOMEM; + } err = gpio_request(pdata->pin, "w1"); - if (err) + if (err) { + dev_err(&pdev->dev, "gpio_request (pin) failed\n"); goto free_master; + } if (gpio_is_valid(pdata->ext_pullup_enable_pin)) { err = gpio_request_one(pdata->ext_pullup_enable_pin, GPIOF_INIT_LOW, "w1 pullup"); - if (err < 0) + if (err < 0) { + dev_err(&pdev->dev, "gpio_request_one " + "(ext_pullup_enable_pin) failed\n"); goto free_gpio; + } } master->data = pdata; @@ -130,8 +132,10 @@ static int __init w1_gpio_probe(struct platform_device *pdev) } err = w1_add_master_device(master); - if (err) + if (err) { + dev_err(&pdev->dev, "w1_add_master device failed\n"); goto free_gpio_ext_pu; + } if (pdata->enable_external_pullup) pdata->enable_external_pullup(1); @@ -205,23 +209,13 @@ static struct platform_driver w1_gpio_driver = { .owner = THIS_MODULE, .of_match_table = of_match_ptr(w1_gpio_dt_ids), }, + .probe = w1_gpio_probe, .remove = __exit_p(w1_gpio_remove), .suspend = w1_gpio_suspend, .resume = w1_gpio_resume, }; -static int __init w1_gpio_init(void) -{ - return platform_driver_probe(&w1_gpio_driver, w1_gpio_probe); -} - -static void __exit w1_gpio_exit(void) -{ - platform_driver_unregister(&w1_gpio_driver); -} - -module_init(w1_gpio_init); -module_exit(w1_gpio_exit); +module_platform_driver(w1_gpio_driver); MODULE_DESCRIPTION("GPIO w1 bus master driver"); MODULE_AUTHOR("Ville Syrjala "); -- cgit v0.10.2 From 2cf4e52e27dc719941cd3727205ca62b742f2746 Mon Sep 17 00:00:00 2001 From: Chen Gang Date: Fri, 23 Nov 2012 17:46:43 +0800 Subject: drivers/char: for hpet, add count checking, and ~0UL instead of -1 use ~0UL for unsigned long variable initialization, instead of -1. add check for hdp->hd_nirqs within 32 (HPET_MAX_TIMERS). the type of irqp->interrupt_count is u8. the git diff not display the relative lines below. hdp->hd_irq[hdp->hd_nirqs] = irq; hdp->hd_nirqs++; please check source code to get more information. Signed-off-by: Chen Gang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index dfd7876..fe6d4be 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -816,7 +816,7 @@ static unsigned long __hpet_calibrate(struct hpets *hpetp) static unsigned long hpet_calibrate(struct hpets *hpetp) { - unsigned long ret = -1; + unsigned long ret = ~0UL; unsigned long tmp; /* @@ -1001,6 +1001,9 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data) irqp = &res->data.extended_irq; for (i = 0; i < irqp->interrupt_count; i++) { + if (hdp->hd_nirqs >= HPET_MAX_TIMERS) + break; + irq = acpi_register_gsi(NULL, irqp->interrupts[i], irqp->triggering, irqp->polarity); if (irq < 0) -- cgit v0.10.2 From b2997387c291ecf8015a89fc626f02be60e359a0 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Thu, 22 Nov 2012 23:26:14 +0100 Subject: misc/st_kim: Free resources in the error path of probe() Signed-off-by: Matthias Kaehlcke Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c index 04a8199..9ff942a 100644 --- a/drivers/misc/ti-st/st_kim.c +++ b/drivers/misc/ti-st/st_kim.c @@ -705,9 +705,9 @@ static const struct file_operations list_debugfs_fops = { static struct dentry *kim_debugfs_dir; static int kim_probe(struct platform_device *pdev) { - long status; struct kim_data_s *kim_gdata; struct ti_st_plat_data *pdata = pdev->dev.platform_data; + int err; if ((pdev->id != -1) && (pdev->id < MAX_ST_DEVICES)) { /* multiple devices could exist */ @@ -724,10 +724,11 @@ static int kim_probe(struct platform_device *pdev) } dev_set_drvdata(&pdev->dev, kim_gdata); - status = st_core_init(&kim_gdata->core_data); - if (status != 0) { + err = st_core_init(&kim_gdata->core_data); + if (err != 0) { pr_err(" ST core init failed"); - return -EIO; + err = -EIO; + goto err_core_init; } /* refer to itself */ kim_gdata->core_data->kim_data = kim_gdata; @@ -738,10 +739,10 @@ static int kim_probe(struct platform_device *pdev) init_completion(&kim_gdata->kim_rcvd); init_completion(&kim_gdata->ldisc_installed); - status = sysfs_create_group(&pdev->dev.kobj, &uim_attr_grp); - if (status) { + err = sysfs_create_group(&pdev->dev.kobj, &uim_attr_grp); + if (err) { pr_err("failed to create sysfs entries"); - return status; + goto err_sysfs_group; } /* copying platform data */ @@ -753,8 +754,8 @@ static int kim_probe(struct platform_device *pdev) kim_debugfs_dir = debugfs_create_dir("ti-st", NULL); if (IS_ERR(kim_debugfs_dir)) { pr_err(" debugfs entries creation failed "); - kim_debugfs_dir = NULL; - return -EIO; + err = -EIO; + goto err_debugfs_dir; } debugfs_create_file("version", S_IRUGO, kim_debugfs_dir, @@ -763,6 +764,17 @@ static int kim_probe(struct platform_device *pdev) kim_gdata, &list_debugfs_fops); pr_info(" debugfs entries created "); return 0; + +err_debugfs_dir: + sysfs_remove_group(&pdev->dev.kobj, &uim_attr_grp); + +err_sysfs_group: + st_core_exit(kim_gdata->core_data); + +err_core_init: + kfree(kim_gdata); + + return err; } static int kim_remove(struct platform_device *pdev) -- cgit v0.10.2 From 70e78c40ed6c25bb34d642848e485d79ffc55c26 Mon Sep 17 00:00:00 2001 From: Cesar Eduardo Barros Date: Fri, 23 Nov 2012 22:26:36 -0200 Subject: MAINTAINERS: remove drivers/staging/hv/ This directory was removed by commit 89ae7d7 (hv: storvsc: Move the storage driver out of the staging area). Cc: K. Y. Srinivasan Cc: Haiyang Zhang Signed-off-by: Cesar Eduardo Barros Signed-off-by: Greg Kroah-Hartman diff --git a/MAINTAINERS b/MAINTAINERS index bb0b27d..9890539 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3596,7 +3596,6 @@ S: Maintained F: drivers/hv/ F: drivers/hid/hid-hyperv.c F: drivers/net/hyperv/ -F: drivers/staging/hv/ I2C OVER PARALLEL PORT M: Jean Delvare -- cgit v0.10.2