diff options
Diffstat (limited to 'drivers')
47 files changed, 1763 insertions, 484 deletions
diff --git a/drivers/android/binder.c b/drivers/android/binder.c index fddf76ef5bd6..95a96a254e5d 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -2192,7 +2192,7 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, off_start, offp - off_start); if (!parent) { - pr_err("transaction release %d bad parent offset", + pr_err("transaction release %d bad parent offset\n", debug_id); continue; } diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index c2819a3d58a6..6f6f745605af 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -186,12 +186,12 @@ struct binder_buffer *binder_alloc_prepare_to_free(struct binder_alloc *alloc, } static int binder_update_page_range(struct binder_alloc *alloc, int allocate, - void *start, void *end, - struct vm_area_struct *vma) + void *start, void *end) { void *page_addr; unsigned long user_page_addr; struct binder_lru_page *page; + struct vm_area_struct *vma = NULL; struct mm_struct *mm = NULL; bool need_mm = false; @@ -215,7 +215,7 @@ static int binder_update_page_range(struct binder_alloc *alloc, int allocate, } } - if (!vma && need_mm && mmget_not_zero(alloc->vma_vm_mm)) + if (need_mm && mmget_not_zero(alloc->vma_vm_mm)) mm = alloc->vma_vm_mm; if (mm) { @@ -437,7 +437,7 @@ struct binder_buffer *binder_alloc_new_buf_locked(struct binder_alloc *alloc, if (end_page_addr > has_page_addr) end_page_addr = has_page_addr; ret = binder_update_page_range(alloc, 1, - (void *)PAGE_ALIGN((uintptr_t)buffer->data), end_page_addr, NULL); + (void *)PAGE_ALIGN((uintptr_t)buffer->data), end_page_addr); if (ret) return ERR_PTR(ret); @@ -478,7 +478,7 @@ struct binder_buffer *binder_alloc_new_buf_locked(struct binder_alloc *alloc, err_alloc_buf_struct_failed: binder_update_page_range(alloc, 0, (void *)PAGE_ALIGN((uintptr_t)buffer->data), - end_page_addr, NULL); + end_page_addr); return ERR_PTR(-ENOMEM); } @@ -562,8 +562,7 @@ static void binder_delete_free_buffer(struct binder_alloc *alloc, alloc->pid, buffer->data, prev->data, next ? next->data : NULL); binder_update_page_range(alloc, 0, buffer_start_page(buffer), - buffer_start_page(buffer) + PAGE_SIZE, - NULL); + buffer_start_page(buffer) + PAGE_SIZE); } list_del(&buffer->entry); kfree(buffer); @@ -600,8 +599,7 @@ static void binder_free_buf_locked(struct binder_alloc *alloc, binder_update_page_range(alloc, 0, (void *)PAGE_ALIGN((uintptr_t)buffer->data), - (void *)(((uintptr_t)buffer->data + buffer_size) & PAGE_MASK), - NULL); + (void *)(((uintptr_t)buffer->data + buffer_size) & PAGE_MASK)); rb_erase(&buffer->rb_node, &alloc->allocated_buffers); buffer->free = 1; @@ -984,7 +982,7 @@ binder_shrink_scan(struct shrinker *shrink, struct shrink_control *sc) return ret; } -struct shrinker binder_shrinker = { +static struct shrinker binder_shrinker = { .count_objects = binder_shrink_count, .scan_objects = binder_shrink_scan, .seeks = DEFAULT_SEEKS, diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c index cd53771b9ae7..370e0a64ead1 100644 --- a/drivers/char/pcmcia/cm4000_cs.c +++ b/drivers/char/pcmcia/cm4000_cs.c @@ -659,9 +659,9 @@ static void terminate_monitor(struct cm4000_dev *dev) * is already doing that for you. */ -static void monitor_card(unsigned long p) +static void monitor_card(struct timer_list *t) { - struct cm4000_dev *dev = (struct cm4000_dev *) p; + struct cm4000_dev *dev = from_timer(dev, t, timer); unsigned int iobase = dev->p_dev->resource[0]->start; unsigned short s; struct ptsreq ptsreq; @@ -1374,7 +1374,7 @@ static void start_monitor(struct cm4000_dev *dev) DEBUGP(3, dev, "-> start_monitor\n"); if (!dev->monitor_running) { DEBUGP(5, dev, "create, init and add timer\n"); - setup_timer(&dev->timer, monitor_card, (unsigned long)dev); + timer_setup(&dev->timer, monitor_card, 0); dev->monitor_running = 1; mod_timer(&dev->timer, jiffies); } else diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c index 382c864814d9..9a1aaf538758 100644 --- a/drivers/char/pcmcia/cm4040_cs.c +++ b/drivers/char/pcmcia/cm4040_cs.c @@ -104,9 +104,9 @@ static inline unsigned char xinb(unsigned short port) /* poll the device fifo status register. not to be confused with * the poll syscall. */ -static void cm4040_do_poll(unsigned long dummy) +static void cm4040_do_poll(struct timer_list *t) { - struct reader_dev *dev = (struct reader_dev *) dummy; + struct reader_dev *dev = from_timer(dev, t, poll_timer); unsigned int obs = xinb(dev->p_dev->resource[0]->start + REG_OFFSET_BUFFER_STATUS); @@ -465,7 +465,6 @@ static int cm4040_open(struct inode *inode, struct file *filp) link->open = 1; - dev->poll_timer.data = (unsigned long) dev; mod_timer(&dev->poll_timer, jiffies + POLL_PERIOD); DEBUGP(2, dev, "<- cm4040_open (successfully)\n"); @@ -585,7 +584,7 @@ static int reader_probe(struct pcmcia_device *link) init_waitqueue_head(&dev->poll_wait); init_waitqueue_head(&dev->read_wait); init_waitqueue_head(&dev->write_wait); - setup_timer(&dev->poll_timer, cm4040_do_poll, 0); + timer_setup(&dev->poll_timer, cm4040_do_poll, 0); ret = reader_config(link, i); if (ret) { diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 62be953e5fb0..aa502e9fb7fa 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -375,7 +375,7 @@ static void reset_device(MGSLPC_INFO *info); static void hdlc_mode(MGSLPC_INFO *info); static void async_mode(MGSLPC_INFO *info); -static void tx_timeout(unsigned long context); +static void tx_timeout(struct timer_list *t); static int carrier_raised(struct tty_port *port); static void dtr_rts(struct tty_port *port, int onoff); @@ -1289,7 +1289,7 @@ static int startup(MGSLPC_INFO * info, struct tty_struct *tty) memset(&info->icount, 0, sizeof(info->icount)); - setup_timer(&info->tx_timer, tx_timeout, (unsigned long)info); + timer_setup(&info->tx_timer, tx_timeout, 0); /* Allocate and claim adapter resources */ retval = claim_resources(info); @@ -3846,9 +3846,9 @@ static void trace_block(MGSLPC_INFO *info,const char* data, int count, int xmit) /* HDLC frame time out * update stats and do tx completion processing */ -static void tx_timeout(unsigned long context) +static void tx_timeout(struct timer_list *t) { - MGSLPC_INFO *info = (MGSLPC_INFO*)context; + MGSLPC_INFO *info = from_timer(info, t, tx_timer); unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) diff --git a/drivers/fpga/xilinx-pr-decoupler.c b/drivers/fpga/xilinx-pr-decoupler.c index e359930bebc8..0d7743089414 100644 --- a/drivers/fpga/xilinx-pr-decoupler.c +++ b/drivers/fpga/xilinx-pr-decoupler.c @@ -79,7 +79,7 @@ static int xlnx_pr_decoupler_enable_show(struct fpga_bridge *bridge) return !status; } -static struct fpga_bridge_ops xlnx_pr_decoupler_br_ops = { +static const struct fpga_bridge_ops xlnx_pr_decoupler_br_ops = { .enable_set = xlnx_pr_decoupler_enable_set, .enable_show = xlnx_pr_decoupler_enable_show, }; diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c index 4ea63d9bd131..e318bf8c623c 100644 --- a/drivers/fsi/fsi-core.c +++ b/drivers/fsi/fsi-core.c @@ -185,7 +185,7 @@ static int fsi_slave_calc_addr(struct fsi_slave *slave, uint32_t *addrp, return 0; } -int fsi_slave_report_and_clear_errors(struct fsi_slave *slave) +static int fsi_slave_report_and_clear_errors(struct fsi_slave *slave) { struct fsi_master *master = slave->master; uint32_t irq, stat; @@ -215,8 +215,8 @@ int fsi_slave_report_and_clear_errors(struct fsi_slave *slave) static int fsi_slave_set_smode(struct fsi_master *master, int link, int id); -int fsi_slave_handle_error(struct fsi_slave *slave, bool write, uint32_t addr, - size_t size) +static int fsi_slave_handle_error(struct fsi_slave *slave, bool write, + uint32_t addr, size_t size) { struct fsi_master *master = slave->master; int rc, link; diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index 894b67ac2cae..a406beb10dd0 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -745,6 +745,7 @@ int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel, desc.dataoffset8 = descsize >> 3; /* in 8-bytes granularity */ desc.length8 = (u16)(packetlen_aligned >> 3); desc.transactionid = requestid; + desc.reserved = 0; desc.rangecount = pagecount; for (i = 0; i < pagecount; i++) { @@ -788,6 +789,7 @@ int vmbus_sendpacket_mpb_desc(struct vmbus_channel *channel, desc->dataoffset8 = desc_size >> 3; /* in 8-bytes granularity */ desc->length8 = (u16)(packetlen_aligned >> 3); desc->transactionid = requestid; + desc->reserved = 0; desc->rangecount = 1; bufferlist[0].iov_base = desc; diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index 379b0df123be..a8dc9a164631 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -350,7 +350,7 @@ static void free_channel(struct vmbus_channel *channel) { tasklet_kill(&channel->callback_event); - kfree_rcu(channel, rcu); + kobject_put(&channel->kobj); } static void percpu_channel_enq(void *arg) @@ -520,6 +520,14 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel) newchannel->state = CHANNEL_OPEN_STATE; if (!fnew) { + struct hv_device *dev + = newchannel->primary_channel->device_obj; + + if (vmbus_add_channel_kobj(dev, newchannel)) { + atomic_dec(&vmbus_connection.offer_in_progress); + goto err_free_chan; + } + if (channel->sc_creation_callback != NULL) channel->sc_creation_callback(newchannel); newchannel->probe_done = true; diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index 49569f8fe038..de6f01df9592 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -373,6 +373,8 @@ struct hv_device *vmbus_device_create(const uuid_le *type, int vmbus_device_register(struct hv_device *child_device_obj); void vmbus_device_unregister(struct hv_device *device_obj); +int vmbus_add_channel_kobj(struct hv_device *device_obj, + struct vmbus_channel *channel); struct vmbus_channel *relid2channel(u32 relid); diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 937801ac2fe0..1da8e818f4de 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -107,28 +107,30 @@ static void print_alias_name(struct hv_device *hv_dev, char *alias_name) sprintf(&alias_name[i], "%02x", hv_dev->dev_type.b[i/2]); } -static u8 channel_monitor_group(struct vmbus_channel *channel) +static u8 channel_monitor_group(const struct vmbus_channel *channel) { return (u8)channel->offermsg.monitorid / 32; } -static u8 channel_monitor_offset(struct vmbus_channel *channel) +static u8 channel_monitor_offset(const struct vmbus_channel *channel) { return (u8)channel->offermsg.monitorid % 32; } -static u32 channel_pending(struct vmbus_channel *channel, - struct hv_monitor_page *monitor_page) +static u32 channel_pending(const struct vmbus_channel *channel, + const struct hv_monitor_page *monitor_page) { u8 monitor_group = channel_monitor_group(channel); + return monitor_page->trigger_group[monitor_group].pending; } -static u32 channel_latency(struct vmbus_channel *channel, - struct hv_monitor_page *monitor_page) +static u32 channel_latency(const struct vmbus_channel *channel, + const struct hv_monitor_page *monitor_page) { u8 monitor_group = channel_monitor_group(channel); u8 monitor_offset = channel_monitor_offset(channel); + return monitor_page->latency[monitor_group][monitor_offset]; } @@ -1133,6 +1135,145 @@ void vmbus_driver_unregister(struct hv_driver *hv_driver) } EXPORT_SYMBOL_GPL(vmbus_driver_unregister); + +/* + * Called when last reference to channel is gone. + */ +static void vmbus_chan_release(struct kobject *kobj) +{ + struct vmbus_channel *channel + = container_of(kobj, struct vmbus_channel, kobj); + + kfree_rcu(channel, rcu); +} + +struct vmbus_chan_attribute { + struct attribute attr; + ssize_t (*show)(const struct vmbus_channel *chan, char *buf); + ssize_t (*store)(struct vmbus_channel *chan, + const char *buf, size_t count); +}; +#define VMBUS_CHAN_ATTR(_name, _mode, _show, _store) \ + struct vmbus_chan_attribute chan_attr_##_name \ + = __ATTR(_name, _mode, _show, _store) +#define VMBUS_CHAN_ATTR_RW(_name) \ + struct vmbus_chan_attribute chan_attr_##_name = __ATTR_RW(_name) +#define VMBUS_CHAN_ATTR_RO(_name) \ + struct vmbus_chan_attribute chan_attr_##_name = __ATTR_RO(_name) +#define VMBUS_CHAN_ATTR_WO(_name) \ + struct vmbus_chan_attribute chan_attr_##_name = __ATTR_WO(_name) + +static ssize_t vmbus_chan_attr_show(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + const struct vmbus_chan_attribute *attribute + = container_of(attr, struct vmbus_chan_attribute, attr); + const struct vmbus_channel *chan + = container_of(kobj, struct vmbus_channel, kobj); + + if (!attribute->show) + return -EIO; + + return attribute->show(chan, buf); +} + +static const struct sysfs_ops vmbus_chan_sysfs_ops = { + .show = vmbus_chan_attr_show, +}; + +static ssize_t out_mask_show(const struct vmbus_channel *channel, char *buf) +{ + const struct hv_ring_buffer_info *rbi = &channel->outbound; + + return sprintf(buf, "%u\n", rbi->ring_buffer->interrupt_mask); +} +VMBUS_CHAN_ATTR_RO(out_mask); + +static ssize_t in_mask_show(const struct vmbus_channel *channel, char *buf) +{ + const struct hv_ring_buffer_info *rbi = &channel->inbound; + + return sprintf(buf, "%u\n", rbi->ring_buffer->interrupt_mask); +} +VMBUS_CHAN_ATTR_RO(in_mask); + +static ssize_t read_avail_show(const struct vmbus_channel *channel, char *buf) +{ + const struct hv_ring_buffer_info *rbi = &channel->inbound; + + return sprintf(buf, "%u\n", hv_get_bytes_to_read(rbi)); +} +VMBUS_CHAN_ATTR_RO(read_avail); + +static ssize_t write_avail_show(const struct vmbus_channel *channel, char *buf) +{ + const struct hv_ring_buffer_info *rbi = &channel->outbound; + + return sprintf(buf, "%u\n", hv_get_bytes_to_write(rbi)); +} +VMBUS_CHAN_ATTR_RO(write_avail); + +static ssize_t show_target_cpu(const struct vmbus_channel *channel, char *buf) +{ + return sprintf(buf, "%u\n", channel->target_cpu); +} +VMBUS_CHAN_ATTR(cpu, S_IRUGO, show_target_cpu, NULL); + +static ssize_t channel_pending_show(const struct vmbus_channel *channel, + char *buf) +{ + return sprintf(buf, "%d\n", + channel_pending(channel, + vmbus_connection.monitor_pages[1])); +} +VMBUS_CHAN_ATTR(pending, S_IRUGO, channel_pending_show, NULL); + +static ssize_t channel_latency_show(const struct vmbus_channel *channel, + char *buf) +{ + return sprintf(buf, "%d\n", + channel_latency(channel, + vmbus_connection.monitor_pages[1])); +} +VMBUS_CHAN_ATTR(latency, S_IRUGO, channel_latency_show, NULL); + +static struct attribute *vmbus_chan_attrs[] = { + &chan_attr_out_mask.attr, + &chan_attr_in_mask.attr, + &chan_attr_read_avail.attr, + &chan_attr_write_avail.attr, + &chan_attr_cpu.attr, + &chan_attr_pending.attr, + &chan_attr_latency.attr, + NULL +}; + +static struct kobj_type vmbus_chan_ktype = { + .sysfs_ops = &vmbus_chan_sysfs_ops, + .release = vmbus_chan_release, + .default_attrs = vmbus_chan_attrs, +}; + +/* + * vmbus_add_channel_kobj - setup a sub-directory under device/channels + */ +int vmbus_add_channel_kobj(struct hv_device *dev, struct vmbus_channel *channel) +{ + struct kobject *kobj = &channel->kobj; + u32 relid = channel->offermsg.child_relid; + int ret; + + kobj->kset = dev->channels_kset; + ret = kobject_init_and_add(kobj, &vmbus_chan_ktype, NULL, + "%u", relid); + if (ret) + return ret; + + kobject_uevent(kobj, KOBJ_ADD); + + return 0; +} + /* * vmbus_device_create - Creates and registers a new child device * on the vmbus. @@ -1164,7 +1305,8 @@ struct hv_device *vmbus_device_create(const uuid_le *type, */ int vmbus_device_register(struct hv_device *child_device_obj) { - int ret = 0; + struct kobject *kobj = &child_device_obj->device.kobj; + int ret; dev_set_name(&child_device_obj->device, "%pUl", child_device_obj->channel->offermsg.offer.if_instance.b); @@ -1178,13 +1320,32 @@ int vmbus_device_register(struct hv_device *child_device_obj) * binding...which will eventually call vmbus_match() and vmbus_probe() */ ret = device_register(&child_device_obj->device); - - if (ret) + if (ret) { pr_err("Unable to register child device\n"); - else - pr_debug("child device %s registered\n", - dev_name(&child_device_obj->device)); + return ret; + } + + child_device_obj->channels_kset = kset_create_and_add("channels", + NULL, kobj); + if (!child_device_obj->channels_kset) { + ret = -ENOMEM; + goto err_dev_unregister; + } + + ret = vmbus_add_channel_kobj(child_device_obj, + child_device_obj->channel); + if (ret) { + pr_err("Unable to register primary channeln"); + goto err_kset_unregister; + } + + return 0; + +err_kset_unregister: + kset_unregister(child_device_obj->channels_kset); +err_dev_unregister: + device_unregister(&child_device_obj->device); return ret; } diff --git a/drivers/hwtracing/coresight/coresight-dynamic-replicator.c b/drivers/hwtracing/coresight/coresight-dynamic-replicator.c index accc2056f7c6..8f4357e2626c 100644 --- a/drivers/hwtracing/coresight/coresight-dynamic-replicator.c +++ b/drivers/hwtracing/coresight/coresight-dynamic-replicator.c @@ -199,8 +199,8 @@ static const struct dev_pm_ops replicator_dev_pm_ops = { static const struct amba_id replicator_ids[] = { { - .id = 0x0003b909, - .mask = 0x0003ffff, + .id = 0x000bb909, + .mask = 0x000fffff, }, { /* Coresight SoC-600 */ diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c index 56ecd7aff5eb..e03e58933141 100644 --- a/drivers/hwtracing/coresight/coresight-etb10.c +++ b/drivers/hwtracing/coresight/coresight-etb10.c @@ -748,8 +748,8 @@ static const struct dev_pm_ops etb_dev_pm_ops = { static const struct amba_id etb_ids[] = { { - .id = 0x0003b907, - .mask = 0x0003ffff, + .id = 0x000bb907, + .mask = 0x000fffff, }, { 0, 0}, }; diff --git a/drivers/hwtracing/coresight/coresight-etm3x.c b/drivers/hwtracing/coresight/coresight-etm3x.c index e5b1ec57dbde..39f42fdd503d 100644 --- a/drivers/hwtracing/coresight/coresight-etm3x.c +++ b/drivers/hwtracing/coresight/coresight-etm3x.c @@ -901,33 +901,33 @@ static const struct dev_pm_ops etm_dev_pm_ops = { static const struct amba_id etm_ids[] = { { /* ETM 3.3 */ - .id = 0x0003b921, - .mask = 0x0003ffff, + .id = 0x000bb921, + .mask = 0x000fffff, .data = "ETM 3.3", }, { /* ETM 3.5 - Cortex-A5 */ - .id = 0x0003b955, - .mask = 0x0003ffff, + .id = 0x000bb955, + .mask = 0x000fffff, .data = "ETM 3.5", }, { /* ETM 3.5 */ - .id = 0x0003b956, - .mask = 0x0003ffff, + .id = 0x000bb956, + .mask = 0x000fffff, .data = "ETM 3.5", }, { /* PTM 1.0 */ - .id = 0x0003b950, - .mask = 0x0003ffff, + .id = 0x000bb950, + .mask = 0x000fffff, .data = "PTM 1.0", }, { /* PTM 1.1 */ - .id = 0x0003b95f, - .mask = 0x0003ffff, + .id = 0x000bb95f, + .mask = 0x000fffff, .data = "PTM 1.1", }, { /* PTM 1.1 Qualcomm */ - .id = 0x0003006f, - .mask = 0x0003ffff, + .id = 0x000b006f, + .mask = 0x000fffff, .data = "PTM 1.1", }, { 0, 0}, diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c index 77642e0e955b..fd3c396717f6 100644 --- a/drivers/hwtracing/coresight/coresight-funnel.c +++ b/drivers/hwtracing/coresight/coresight-funnel.c @@ -248,8 +248,8 @@ static const struct dev_pm_ops funnel_dev_pm_ops = { static const struct amba_id funnel_ids[] = { { - .id = 0x0003b908, - .mask = 0x0003ffff, + .id = 0x000bb908, + .mask = 0x000fffff, }, { /* Coresight SoC-600 */ diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c index 92a780a6df1d..15e7ef3891f5 100644 --- a/drivers/hwtracing/coresight/coresight-stm.c +++ b/drivers/hwtracing/coresight/coresight-stm.c @@ -917,13 +917,13 @@ static const struct dev_pm_ops stm_dev_pm_ops = { static const struct amba_id stm_ids[] = { { - .id = 0x0003b962, - .mask = 0x0003ffff, + .id = 0x000bb962, + .mask = 0x000fffff, .data = "STM32", }, { - .id = 0x0003b963, - .mask = 0x0003ffff, + .id = 0x000bb963, + .mask = 0x000fffff, .data = "STM500", }, { 0, 0}, diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c index 2ff4a66a3caa..0ea04f588de0 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.c +++ b/drivers/hwtracing/coresight/coresight-tmc.c @@ -439,8 +439,8 @@ out: static const struct amba_id tmc_ids[] = { { - .id = 0x0003b961, - .mask = 0x0003ffff, + .id = 0x000bb961, + .mask = 0x000fffff, }, { /* Coresight SoC 600 TMC-ETR/ETS */ diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c index d7a3e453016d..bef49a3a5ca7 100644 --- a/drivers/hwtracing/coresight/coresight-tpiu.c +++ b/drivers/hwtracing/coresight/coresight-tpiu.c @@ -194,8 +194,8 @@ static const struct dev_pm_ops tpiu_dev_pm_ops = { static const struct amba_id tpiu_ids[] = { { - .id = 0x0003b912, - .mask = 0x0003ffff, + .id = 0x000bb912, + .mask = 0x000fffff, }, { .id = 0x0004b912, diff --git a/drivers/misc/altera-stapl/Kconfig b/drivers/misc/altera-stapl/Kconfig index 7f01d8e93992..8a828fe41fad 100644 --- a/drivers/misc/altera-stapl/Kconfig +++ b/drivers/misc/altera-stapl/Kconfig @@ -1,4 +1,5 @@ -comment "Altera FPGA firmware download module" +comment "Altera FPGA firmware download module (requires I2C)" + depends on !I2C config ALTERA_STAPL tristate "Altera FPGA firmware download module" diff --git a/drivers/misc/genwqe/card_base.h b/drivers/misc/genwqe/card_base.h index 5813b5f25006..3743c87f8ab9 100644 --- a/drivers/misc/genwqe/card_base.h +++ b/drivers/misc/genwqe/card_base.h @@ -182,6 +182,7 @@ struct dma_mapping { struct list_head card_list; /* list of usr_maps for card */ struct list_head pin_list; /* list of pinned memory for dev */ + int write; /* writable map? useful in unmapping */ }; static inline void genwqe_mapping_init(struct dma_mapping *m, @@ -189,6 +190,7 @@ static inline void genwqe_mapping_init(struct dma_mapping *m, { memset(m, 0, sizeof(*m)); m->type = type; + m->write = 1; /* Assume the maps we create are R/W */ } /** @@ -347,6 +349,7 @@ enum genwqe_requ_state { * @user_size: size of user-space memory area * @page: buffer for partial pages if needed * @page_dma_addr: dma address partial pages + * @write: should we write it back to userspace? */ struct genwqe_sgl { dma_addr_t sgl_dma_addr; @@ -356,6 +359,8 @@ struct genwqe_sgl { void __user *user_addr; /* user-space base-address */ size_t user_size; /* size of memory area */ + int write; + unsigned long nr_pages; unsigned long fpage_offs; size_t fpage_size; @@ -369,7 +374,7 @@ struct genwqe_sgl { }; int genwqe_alloc_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl, - void __user *user_addr, size_t user_size); + void __user *user_addr, size_t user_size, int write); int genwqe_setup_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl, dma_addr_t *dma_list); diff --git a/drivers/misc/genwqe/card_dev.c b/drivers/misc/genwqe/card_dev.c index dd4617764f14..3ecfa35457e0 100644 --- a/drivers/misc/genwqe/card_dev.c +++ b/drivers/misc/genwqe/card_dev.c @@ -942,6 +942,10 @@ static int ddcb_cmd_fixups(struct genwqe_file *cfile, struct ddcb_requ *req) genwqe_mapping_init(m, GENWQE_MAPPING_SGL_TEMP); + + if (ats_flags == ATS_TYPE_SGL_RD) + m->write = 0; + rc = genwqe_user_vmap(cd, m, (void *)u_addr, u_size, req); if (rc != 0) @@ -954,7 +958,7 @@ static int ddcb_cmd_fixups(struct genwqe_file *cfile, struct ddcb_requ *req) /* create genwqe style scatter gather list */ rc = genwqe_alloc_sync_sgl(cd, &req->sgls[i], (void __user *)u_addr, - u_size); + u_size, m->write); if (rc != 0) goto err_out; diff --git a/drivers/misc/genwqe/card_utils.c b/drivers/misc/genwqe/card_utils.c index 147b83011b58..5c0d917636f7 100644 --- a/drivers/misc/genwqe/card_utils.c +++ b/drivers/misc/genwqe/card_utils.c @@ -296,7 +296,7 @@ static int genwqe_sgl_size(int num_pages) * from user-space into the cached pages. */ int genwqe_alloc_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl, - void __user *user_addr, size_t user_size) + void __user *user_addr, size_t user_size, int write) { int rc; struct pci_dev *pci_dev = cd->pci_dev; @@ -312,6 +312,7 @@ int genwqe_alloc_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl, sgl->user_addr = user_addr; sgl->user_size = user_size; + sgl->write = write; sgl->sgl_size = genwqe_sgl_size(sgl->nr_pages); if (get_order(sgl->sgl_size) > MAX_ORDER) { @@ -476,14 +477,20 @@ int genwqe_setup_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl, int genwqe_free_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl) { int rc = 0; + size_t offset; + unsigned long res; struct pci_dev *pci_dev = cd->pci_dev; if (sgl->fpage) { - if (copy_to_user(sgl->user_addr, sgl->fpage + sgl->fpage_offs, - sgl->fpage_size)) { - dev_err(&pci_dev->dev, "[%s] err: copying fpage!\n", - __func__); - rc = -EFAULT; + if (sgl->write) { + res = copy_to_user(sgl->user_addr, + sgl->fpage + sgl->fpage_offs, sgl->fpage_size); + if (res) { + dev_err(&pci_dev->dev, + "[%s] err: copying fpage! (res=%lu)\n", + __func__, res); + rc = -EFAULT; + } } __genwqe_free_consistent(cd, PAGE_SIZE, sgl->fpage, sgl->fpage_dma_addr); @@ -491,12 +498,16 @@ int genwqe_free_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl) sgl->fpage_dma_addr = 0; } if (sgl->lpage) { - if (copy_to_user(sgl->user_addr + sgl->user_size - - sgl->lpage_size, sgl->lpage, - sgl->lpage_size)) { - dev_err(&pci_dev->dev, "[%s] err: copying lpage!\n", - __func__); - rc = -EFAULT; + if (sgl->write) { + offset = sgl->user_size - sgl->lpage_size; + res = copy_to_user(sgl->user_addr + offset, sgl->lpage, + sgl->lpage_size); + if (res) { + dev_err(&pci_dev->dev, + "[%s] err: copying lpage! (res=%lu)\n", + __func__, res); + rc = -EFAULT; + } } __genwqe_free_consistent(cd, PAGE_SIZE, sgl->lpage, sgl->lpage_dma_addr); @@ -599,14 +610,14 @@ int genwqe_user_vmap(struct genwqe_dev *cd, struct dma_mapping *m, void *uaddr, /* pin user pages in memory */ rc = get_user_pages_fast(data & PAGE_MASK, /* page aligned addr */ m->nr_pages, - 1, /* write by caller */ + m->write, /* readable/writable */ m->page_list); /* ptrs to pages */ if (rc < 0) goto fail_get_user_pages; /* assumption: get_user_pages can be killed by signals. */ if (rc < m->nr_pages) { - free_user_pages(m->page_list, rc, 0); + free_user_pages(m->page_list, rc, m->write); rc = -EFAULT; goto fail_get_user_pages; } @@ -618,7 +629,7 @@ int genwqe_user_vmap(struct genwqe_dev *cd, struct dma_mapping *m, void *uaddr, return 0; fail_free_user_pages: - free_user_pages(m->page_list, m->nr_pages, 0); + free_user_pages(m->page_list, m->nr_pages, m->write); fail_get_user_pages: kfree(m->page_list); @@ -651,7 +662,7 @@ int genwqe_user_vunmap(struct genwqe_dev *cd, struct dma_mapping *m, genwqe_unmap_pages(cd, m->dma_list, m->nr_pages); if (m->page_list) { - free_user_pages(m->page_list, m->nr_pages, 1); + free_user_pages(m->page_list, m->nr_pages, m->write); kfree(m->page_list); m->page_list = NULL; diff --git a/drivers/misc/lkdtm_core.c b/drivers/misc/lkdtm_core.c index 981b3ef71e47..ba92291508dc 100644 --- a/drivers/misc/lkdtm_core.c +++ b/drivers/misc/lkdtm_core.c @@ -56,122 +56,54 @@ static ssize_t direct_entry(struct file *f, const char __user *user_buf, size_t count, loff_t *off); #ifdef CONFIG_KPROBES -static void lkdtm_handler(void); +static int lkdtm_kprobe_handler(struct kprobe *kp, struct pt_regs *regs); static ssize_t lkdtm_debugfs_entry(struct file *f, const char __user *user_buf, size_t count, loff_t *off); - - -/* jprobe entry point handlers. */ -static unsigned int jp_do_irq(unsigned int irq) -{ - lkdtm_handler(); - jprobe_return(); - return 0; -} - -static irqreturn_t jp_handle_irq_event(unsigned int irq, - struct irqaction *action) -{ - lkdtm_handler(); - jprobe_return(); - return 0; -} - -static void jp_tasklet_action(struct softirq_action *a) -{ - lkdtm_handler(); - jprobe_return(); -} - -static void jp_ll_rw_block(int rw, int nr, struct buffer_head *bhs[]) -{ - lkdtm_handler(); - jprobe_return(); -} - -struct scan_control; - -static unsigned long jp_shrink_inactive_list(unsigned long max_scan, - struct zone *zone, - struct scan_control *sc) -{ - lkdtm_handler(); - jprobe_return(); - return 0; -} - -static int jp_hrtimer_start(struct hrtimer *timer, ktime_t tim, - const enum hrtimer_mode mode) -{ - lkdtm_handler(); - jprobe_return(); - return 0; -} - -static int jp_scsi_dispatch_cmd(struct scsi_cmnd *cmd) -{ - lkdtm_handler(); - jprobe_return(); - return 0; -} - -# ifdef CONFIG_IDE -static int jp_generic_ide_ioctl(ide_drive_t *drive, struct file *file, - struct block_device *bdev, unsigned int cmd, - unsigned long arg) -{ - lkdtm_handler(); - jprobe_return(); - return 0; -} -# endif +# define CRASHPOINT_KPROBE(_symbol) \ + .kprobe = { \ + .symbol_name = (_symbol), \ + .pre_handler = lkdtm_kprobe_handler, \ + }, +# define CRASHPOINT_WRITE(_symbol) \ + (_symbol) ? lkdtm_debugfs_entry : direct_entry +#else +# define CRASHPOINT_KPROBE(_symbol) +# define CRASHPOINT_WRITE(_symbol) direct_entry #endif /* Crash points */ struct crashpoint { const char *name; const struct file_operations fops; - struct jprobe jprobe; + struct kprobe kprobe; }; -#define CRASHPOINT(_name, _write, _symbol, _entry) \ +#define CRASHPOINT(_name, _symbol) \ { \ .name = _name, \ .fops = { \ .read = lkdtm_debugfs_read, \ .llseek = generic_file_llseek, \ .open = lkdtm_debugfs_open, \ - .write = _write, \ - }, \ - .jprobe = { \ - .kp.symbol_name = _symbol, \ - .entry = (kprobe_opcode_t *)_entry, \ + .write = CRASHPOINT_WRITE(_symbol) \ }, \ + CRASHPOINT_KPROBE(_symbol) \ } /* Define the possible places where we can trigger a crash point. */ -struct crashpoint crashpoints[] = { - CRASHPOINT("DIRECT", direct_entry, - NULL, NULL), +static struct crashpoint crashpoints[] = { + CRASHPOINT("DIRECT", NULL), #ifdef CONFIG_KPROBES - CRASHPOINT("INT_HARDWARE_ENTRY", lkdtm_debugfs_entry, - "do_IRQ", jp_do_irq), - CRASHPOINT("INT_HW_IRQ_EN", lkdtm_debugfs_entry, - "handle_IRQ_event", jp_handle_irq_event), - CRASHPOINT("INT_TASKLET_ENTRY", lkdtm_debugfs_entry, - "tasklet_action", jp_tasklet_action), - CRASHPOINT("FS_DEVRW", lkdtm_debugfs_entry, - "ll_rw_block", jp_ll_rw_block), - CRASHPOINT("MEM_SWAPOUT", lkdtm_debugfs_entry, - "shrink_inactive_list", jp_shrink_inactive_list), - CRASHPOINT("TIMERADD", lkdtm_debugfs_entry, - "hrtimer_start", jp_hrtimer_start), - CRASHPOINT("SCSI_DISPATCH_CMD", lkdtm_debugfs_entry, - "scsi_dispatch_cmd", jp_scsi_dispatch_cmd), + CRASHPOINT("INT_HARDWARE_ENTRY", "do_IRQ"), + CRASHPOINT("INT_HW_IRQ_EN", "handle_IRQ_event"), + CRASHPOINT("INT_TASKLET_ENTRY", "tasklet_action"), + CRASHPOINT("FS_DEVRW", "ll_rw_block"), + CRASHPOINT("MEM_SWAPOUT", "shrink_inactive_list"), + CRASHPOINT("TIMERADD", "hrtimer_start"), + CRASHPOINT("SCSI_DISPATCH_CMD", "scsi_dispatch_cmd"), # ifdef CONFIG_IDE - CRASHPOINT("IDE_CORE_CP", lkdtm_debugfs_entry, - "generic_ide_ioctl", jp_generic_ide_ioctl), + CRASHPOINT("IDE_CORE_CP", "generic_ide_ioctl"), # endif #endif }; @@ -190,7 +122,7 @@ struct crashtype { } /* Define the possible types of crashes that can be triggered. */ -struct crashtype crashtypes[] = { +static const struct crashtype crashtypes[] = { CRASHTYPE(PANIC), CRASHTYPE(BUG), CRASHTYPE(WARNING), @@ -254,10 +186,10 @@ struct crashtype crashtypes[] = { }; -/* Global jprobe entry and crashtype. */ -static struct jprobe *lkdtm_jprobe; -struct crashpoint *lkdtm_crashpoint; -struct crashtype *lkdtm_crashtype; +/* Global kprobe entry and crashtype. */ +static struct kprobe *lkdtm_kprobe; +static struct crashpoint *lkdtm_crashpoint; +static const struct crashtype *lkdtm_crashtype; /* Module parameters */ static int recur_count = -1; @@ -280,7 +212,7 @@ MODULE_PARM_DESC(cpoint_count, " Crash Point Count, number of times the "\ /* Return the crashtype number or NULL if the name is invalid */ -static struct crashtype *find_crashtype(const char *name) +static const struct crashtype *find_crashtype(const char *name) { int i; @@ -296,34 +228,35 @@ static struct crashtype *find_crashtype(const char *name) * This is forced noinline just so it distinctly shows up in the stackdump * which makes validation of expected lkdtm crashes easier. */ -static noinline void lkdtm_do_action(struct crashtype *crashtype) +static noinline void lkdtm_do_action(const struct crashtype *crashtype) { - BUG_ON(!crashtype || !crashtype->func); + if (WARN_ON(!crashtype || !crashtype->func)) + return; crashtype->func(); } static int lkdtm_register_cpoint(struct crashpoint *crashpoint, - struct crashtype *crashtype) + const struct crashtype *crashtype) { int ret; /* If this doesn't have a symbol, just call immediately. */ - if (!crashpoint->jprobe.kp.symbol_name) { + if (!crashpoint->kprobe.symbol_name) { lkdtm_do_action(crashtype); return 0; } - if (lkdtm_jprobe != NULL) - unregister_jprobe(lkdtm_jprobe); + if (lkdtm_kprobe != NULL) + unregister_kprobe(lkdtm_kprobe); lkdtm_crashpoint = crashpoint; lkdtm_crashtype = crashtype; - lkdtm_jprobe = &crashpoint->jprobe; - ret = register_jprobe(lkdtm_jprobe); + lkdtm_kprobe = &crashpoint->kprobe; + ret = register_kprobe(lkdtm_kprobe); if (ret < 0) { - pr_info("Couldn't register jprobe %s\n", - crashpoint->jprobe.kp.symbol_name); - lkdtm_jprobe = NULL; + pr_info("Couldn't register kprobe %s\n", + crashpoint->kprobe.symbol_name); + lkdtm_kprobe = NULL; lkdtm_crashpoint = NULL; lkdtm_crashtype = NULL; } @@ -336,13 +269,14 @@ static int lkdtm_register_cpoint(struct crashpoint *crashpoint, static int crash_count = DEFAULT_COUNT; static DEFINE_SPINLOCK(crash_count_lock); -/* Called by jprobe entry points. */ -static void lkdtm_handler(void) +/* Called by kprobe entry points. */ +static int lkdtm_kprobe_handler(struct kprobe *kp, struct pt_regs *regs) { unsigned long flags; bool do_it = false; - BUG_ON(!lkdtm_crashpoint || !lkdtm_crashtype); + if (WARN_ON(!lkdtm_crashpoint || !lkdtm_crashtype)) + return 0; spin_lock_irqsave(&crash_count_lock, flags); crash_count--; @@ -357,6 +291,8 @@ static void lkdtm_handler(void) if (do_it) lkdtm_do_action(lkdtm_crashtype); + + return 0; } static ssize_t lkdtm_debugfs_entry(struct file *f, @@ -364,7 +300,7 @@ static ssize_t lkdtm_debugfs_entry(struct file *f, size_t count, loff_t *off) { struct crashpoint *crashpoint = file_inode(f)->i_private; - struct crashtype *crashtype = NULL; + const struct crashtype *crashtype = NULL; char *buf; int err; @@ -432,7 +368,7 @@ static int lkdtm_debugfs_open(struct inode *inode, struct file *file) static ssize_t direct_entry(struct file *f, const char __user *user_buf, size_t count, loff_t *off) { - struct crashtype *crashtype; + const struct crashtype *crashtype; char *buf; if (count >= PAGE_SIZE) @@ -468,7 +404,7 @@ static struct dentry *lkdtm_debugfs_root; static int __init lkdtm_module_init(void) { struct crashpoint *crashpoint = NULL; - struct crashtype *crashtype = NULL; + const struct crashtype *crashtype = NULL; int ret = -EINVAL; int i; @@ -556,8 +492,8 @@ static void __exit lkdtm_module_exit(void) /* Handle test-specific clean-up. */ lkdtm_usercopy_exit(); - if (lkdtm_jprobe != NULL) - unregister_jprobe(lkdtm_jprobe); + if (lkdtm_kprobe != NULL) + unregister_kprobe(lkdtm_kprobe); pr_info("Crash point unregistered\n"); } diff --git a/drivers/misc/mei/mei-trace.c b/drivers/misc/mei/mei-trace.c index e19e6acb191b..374edde72a14 100644 --- a/drivers/misc/mei/mei-trace.c +++ b/drivers/misc/mei/mei-trace.c @@ -23,5 +23,4 @@ EXPORT_TRACEPOINT_SYMBOL(mei_reg_read); EXPORT_TRACEPOINT_SYMBOL(mei_reg_write); EXPORT_TRACEPOINT_SYMBOL(mei_pci_cfg_read); -EXPORT_TRACEPOINT_SYMBOL(mei_pci_cfg_write); #endif /* __CHECKER__ */ diff --git a/drivers/misc/mei/mei-trace.h b/drivers/misc/mei/mei-trace.h index 7d2d5d4a1624..b52e9b97a7c0 100644 --- a/drivers/misc/mei/mei-trace.h +++ b/drivers/misc/mei/mei-trace.h @@ -83,25 +83,6 @@ TRACE_EVENT(mei_pci_cfg_read, __get_str(dev), __entry->reg, __entry->offs, __entry->val) ); -TRACE_EVENT(mei_pci_cfg_write, - TP_PROTO(const struct device *dev, const char *reg, u32 offs, u32 val), - TP_ARGS(dev, reg, offs, val), - TP_STRUCT__entry( - __string(dev, dev_name(dev)) - __field(const char *, reg) - __field(u32, offs) - __field(u32, val) - ), - TP_fast_assign( - __assign_str(dev, dev_name(dev)) - __entry->reg = reg; - __entry->offs = offs; - __entry->val = val; - ), - TP_printk("[%s] pci cfg write %s[%#x] = %#x", - __get_str(dev), __entry->reg, __entry->offs, __entry->val) -); - #endif /* _MEI_TRACE_H_ */ /* This part must be outside protection */ diff --git a/drivers/misc/mic/Kconfig b/drivers/misc/mic/Kconfig index 6fd9d367dea7..227cc7443671 100644 --- a/drivers/misc/mic/Kconfig +++ b/drivers/misc/mic/Kconfig @@ -1,3 +1,5 @@ +menu "Intel MIC & related support" + comment "Intel MIC Bus Driver" config INTEL_MIC_BUS @@ -150,3 +152,5 @@ config VOP if VOP source "drivers/vhost/Kconfig.vringh" endif + +endmenu diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c index deb203026496..d40a34f594c7 100644 --- a/drivers/misc/pci_endpoint_test.c +++ b/drivers/misc/pci_endpoint_test.c @@ -226,6 +226,9 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test, size_t size) u32 src_crc32; u32 dst_crc32; + if (size > SIZE_MAX - alignment) + goto err; + orig_src_addr = dma_alloc_coherent(dev, size + alignment, &orig_src_phys_addr, GFP_KERNEL); if (!orig_src_addr) { @@ -311,6 +314,9 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test, size_t size) size_t alignment = test->alignment; u32 crc32; + if (size > SIZE_MAX - alignment) + goto err; + orig_addr = dma_alloc_coherent(dev, size + alignment, &orig_phys_addr, GFP_KERNEL); if (!orig_addr) { @@ -369,6 +375,9 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test, size_t size) size_t alignment = test->alignment; u32 crc32; + if (size > SIZE_MAX - alignment) + goto err; + orig_addr = dma_alloc_coherent(dev, size + alignment, &orig_phys_addr, GFP_KERNEL); if (!orig_addr) { @@ -588,6 +597,8 @@ static void pci_endpoint_test_remove(struct pci_dev *pdev) if (sscanf(misc_device->name, DRV_MODULE_NAME ".%d", &id) != 1) return; + if (id < 0) + return; misc_deregister(&test->miscdev); ida_simple_remove(&pci_endpoint_test_ida, id); diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig index 101ced4c84be..eb09916744bf 100644 --- a/drivers/nvmem/Kconfig +++ b/drivers/nvmem/Kconfig @@ -135,13 +135,33 @@ config NVMEM_VF610_OCOTP be called nvmem-vf610-ocotp. config MESON_EFUSE - tristate "Amlogic eFuse Support" + tristate "Amlogic Meson GX eFuse Support" depends on (ARCH_MESON || COMPILE_TEST) && MESON_SM help This is a driver to retrieve specific values from the eFuse found on - the Amlogic Meson SoCs. + the Amlogic Meson GX SoCs. This driver can also be built as a module. If so, the module will be called nvmem_meson_efuse. +config MESON_MX_EFUSE + tristate "Amlogic Meson6/Meson8/Meson8b eFuse Support" + depends on ARCH_MESON || COMPILE_TEST + help + This is a driver to retrieve specific values from the eFuse found on + the Amlogic Meson6, Meson8 and Meson8b SoCs. + + This driver can also be built as a module. If so, the module + will be called nvmem_meson_mx_efuse. + +config NVMEM_SNVS_LPGPR + tristate "Support for Low Power General Purpose Register" + depends on SOC_IMX6 || COMPILE_TEST + help + This is a driver for Low Power General Purpose Register (LPGPR) available on + i.MX6 SoCs in Secure Non-Volatile Storage (SNVS) of this chip. + + This driver can also be built as a module. If so, the module + will be called nvmem-snvs-lpgpr. + endif diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile index 173140658693..362f394da65d 100644 --- a/drivers/nvmem/Makefile +++ b/drivers/nvmem/Makefile @@ -30,3 +30,7 @@ obj-$(CONFIG_NVMEM_VF610_OCOTP) += nvmem-vf610-ocotp.o nvmem-vf610-ocotp-y := vf610-ocotp.o obj-$(CONFIG_MESON_EFUSE) += nvmem_meson_efuse.o nvmem_meson_efuse-y := meson-efuse.o +obj-$(CONFIG_MESON_MX_EFUSE) += nvmem_meson_mx_efuse.o +nvmem_meson_mx_efuse-y := meson-mx-efuse.o +obj-$(CONFIG_NVMEM_SNVS_LPGPR) += nvmem_snvs_lpgpr.o +nvmem_snvs_lpgpr-y := snvs_lpgpr.o diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index d12e5de78e70..864904594063 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -615,7 +615,7 @@ static struct nvmem_device *nvmem_find(const char *name) return to_nvmem_device(d); } -#if IS_ENABLED(CONFIG_NVMEM) && IS_ENABLED(CONFIG_OF) +#if IS_ENABLED(CONFIG_OF) /** * of_nvmem_device_get() - Get nvmem device from a given id * @@ -753,7 +753,7 @@ static struct nvmem_cell *nvmem_cell_get_from_list(const char *cell_id) return cell; } -#if IS_ENABLED(CONFIG_NVMEM) && IS_ENABLED(CONFIG_OF) +#if IS_ENABLED(CONFIG_OF) /** * of_nvmem_cell_get() - Get a nvmem cell from given device node and cell id * @@ -946,8 +946,7 @@ void nvmem_cell_put(struct nvmem_cell *cell) } EXPORT_SYMBOL_GPL(nvmem_cell_put); -static inline void nvmem_shift_read_buffer_in_place(struct nvmem_cell *cell, - void *buf) +static void nvmem_shift_read_buffer_in_place(struct nvmem_cell *cell, void *buf) { u8 *p, *b; int i, bit_offset = cell->bit_offset; @@ -1028,8 +1027,8 @@ void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len) } EXPORT_SYMBOL_GPL(nvmem_cell_read); -static inline void *nvmem_cell_prepare_write_buffer(struct nvmem_cell *cell, - u8 *_buf, int len) +static void *nvmem_cell_prepare_write_buffer(struct nvmem_cell *cell, + u8 *_buf, int len) { struct nvmem_device *nvmem = cell->nvmem; int i, rc, nbits, bit_offset = cell->bit_offset; diff --git a/drivers/nvmem/meson-efuse.c b/drivers/nvmem/meson-efuse.c index 70bfc9839bb2..1ea3cd24a508 100644 --- a/drivers/nvmem/meson-efuse.c +++ b/drivers/nvmem/meson-efuse.c @@ -1,5 +1,5 @@ /* - * Amlogic eFuse Driver + * Amlogic Meson GX eFuse Driver * * Copyright (c) 2016 Endless Computers, Inc. * Author: Carlo Caione <carlo@endlessm.com> @@ -89,5 +89,5 @@ static struct platform_driver meson_efuse_driver = { module_platform_driver(meson_efuse_driver); MODULE_AUTHOR("Carlo Caione <carlo@endlessm.com>"); -MODULE_DESCRIPTION("Amlogic Meson NVMEM driver"); +MODULE_DESCRIPTION("Amlogic Meson GX NVMEM driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/nvmem/meson-mx-efuse.c b/drivers/nvmem/meson-mx-efuse.c new file mode 100644 index 000000000000..a346b4923550 --- /dev/null +++ b/drivers/nvmem/meson-mx-efuse.c @@ -0,0 +1,265 @@ +/* + * Amlogic Meson6, Meson8 and Meson8b eFuse Driver + * + * Copyright (c) 2017 Martin Blumenstingl <martin.blumenstingl@googlemail.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License 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. See the GNU General Public License for + * more details. + */ + +#include <linux/bitfield.h> +#include <linux/bitops.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/module.h> +#include <linux/nvmem-provider.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/sizes.h> +#include <linux/slab.h> + +#define MESON_MX_EFUSE_CNTL1 0x04 +#define MESON_MX_EFUSE_CNTL1_PD_ENABLE BIT(27) +#define MESON_MX_EFUSE_CNTL1_AUTO_RD_BUSY BIT(26) +#define MESON_MX_EFUSE_CNTL1_AUTO_RD_START BIT(25) +#define MESON_MX_EFUSE_CNTL1_AUTO_RD_ENABLE BIT(24) +#define MESON_MX_EFUSE_CNTL1_BYTE_WR_DATA GENMASK(23, 16) +#define MESON_MX_EFUSE_CNTL1_AUTO_WR_BUSY BIT(14) +#define MESON_MX_EFUSE_CNTL1_AUTO_WR_START BIT(13) +#define MESON_MX_EFUSE_CNTL1_AUTO_WR_ENABLE BIT(12) +#define MESON_MX_EFUSE_CNTL1_BYTE_ADDR_SET BIT(11) +#define MESON_MX_EFUSE_CNTL1_BYTE_ADDR_MASK GENMASK(10, 0) + +#define MESON_MX_EFUSE_CNTL2 0x08 + +#define MESON_MX_EFUSE_CNTL4 0x10 +#define MESON_MX_EFUSE_CNTL4_ENCRYPT_ENABLE BIT(10) + +struct meson_mx_efuse_platform_data { + const char *name; + unsigned int word_size; +}; + +struct meson_mx_efuse { + void __iomem *base; + struct clk *core_clk; + struct nvmem_device *nvmem; + struct nvmem_config config; +}; + +static void meson_mx_efuse_mask_bits(struct meson_mx_efuse *efuse, u32 reg, + u32 mask, u32 set) +{ + u32 data; + + data = readl(efuse->base + reg); + data &= ~mask; + data |= (set & mask); + + writel(data, efuse->base + reg); +} + +static int meson_mx_efuse_hw_enable(struct meson_mx_efuse *efuse) +{ + int err; + + err = clk_prepare_enable(efuse->core_clk); + if (err) + return err; + + /* power up the efuse */ + meson_mx_efuse_mask_bits(efuse, MESON_MX_EFUSE_CNTL1, + MESON_MX_EFUSE_CNTL1_PD_ENABLE, 0); + + meson_mx_efuse_mask_bits(efuse, MESON_MX_EFUSE_CNTL4, + MESON_MX_EFUSE_CNTL4_ENCRYPT_ENABLE, 0); + + return 0; +} + +static void meson_mx_efuse_hw_disable(struct meson_mx_efuse *efuse) +{ + meson_mx_efuse_mask_bits(efuse, MESON_MX_EFUSE_CNTL1, + MESON_MX_EFUSE_CNTL1_PD_ENABLE, + MESON_MX_EFUSE_CNTL1_PD_ENABLE); + + clk_disable_unprepare(efuse->core_clk); +} + +static int meson_mx_efuse_read_addr(struct meson_mx_efuse *efuse, + unsigned int addr, u32 *value) +{ + int err; + u32 regval; + + /* write the address to read */ + regval = FIELD_PREP(MESON_MX_EFUSE_CNTL1_BYTE_ADDR_MASK, addr); + meson_mx_efuse_mask_bits(efuse, MESON_MX_EFUSE_CNTL1, + MESON_MX_EFUSE_CNTL1_BYTE_ADDR_MASK, regval); + + /* inform the hardware that we changed the address */ + meson_mx_efuse_mask_bits(efuse, MESON_MX_EFUSE_CNTL1, + MESON_MX_EFUSE_CNTL1_BYTE_ADDR_SET, + MESON_MX_EFUSE_CNTL1_BYTE_ADDR_SET); + meson_mx_efuse_mask_bits(efuse, MESON_MX_EFUSE_CNTL1, + MESON_MX_EFUSE_CNTL1_BYTE_ADDR_SET, 0); + + /* start the read process */ + meson_mx_efuse_mask_bits(efuse, MESON_MX_EFUSE_CNTL1, + MESON_MX_EFUSE_CNTL1_AUTO_RD_START, + MESON_MX_EFUSE_CNTL1_AUTO_RD_START); + meson_mx_efuse_mask_bits(efuse, MESON_MX_EFUSE_CNTL1, + MESON_MX_EFUSE_CNTL1_AUTO_RD_START, 0); + + /* + * perform a dummy read to ensure that the HW has the RD_BUSY bit set + * when polling for the status below. + */ + readl(efuse->base + MESON_MX_EFUSE_CNTL1); + + err = readl_poll_timeout_atomic(efuse->base + MESON_MX_EFUSE_CNTL1, + regval, + (!(regval & MESON_MX_EFUSE_CNTL1_AUTO_RD_BUSY)), + 1, 1000); + if (err) { + dev_err(efuse->config.dev, + "Timeout while reading efuse address %u\n", addr); + return err; + } + + *value = readl(efuse->base + MESON_MX_EFUSE_CNTL2); + + return 0; +} + +static int meson_mx_efuse_read(void *context, unsigned int offset, + void *buf, size_t bytes) +{ + struct meson_mx_efuse *efuse = context; + u32 tmp; + int err, i, addr; + + err = meson_mx_efuse_hw_enable(efuse); + if (err) + return err; + + meson_mx_efuse_mask_bits(efuse, MESON_MX_EFUSE_CNTL1, + MESON_MX_EFUSE_CNTL1_AUTO_RD_ENABLE, + MESON_MX_EFUSE_CNTL1_AUTO_RD_ENABLE); + + for (i = offset; i < offset + bytes; i += efuse->config.word_size) { + addr = i / efuse->config.word_size; + + err = meson_mx_efuse_read_addr(efuse, addr, &tmp); + if (err) + break; + + memcpy(buf + i, &tmp, efuse->config.word_size); + } + + meson_mx_efuse_mask_bits(efuse, MESON_MX_EFUSE_CNTL1, + MESON_MX_EFUSE_CNTL1_AUTO_RD_ENABLE, 0); + + meson_mx_efuse_hw_disable(efuse); + + return err; +} + +static const struct meson_mx_efuse_platform_data meson6_efuse_data = { + .name = "meson6-efuse", + .word_size = 1, +}; + +static const struct meson_mx_efuse_platform_data meson8_efuse_data = { + .name = "meson8-efuse", + .word_size = 4, +}; + +static const struct meson_mx_efuse_platform_data meson8b_efuse_data = { + .name = "meson8b-efuse", + .word_size = 4, +}; + +static const struct of_device_id meson_mx_efuse_match[] = { + { .compatible = "amlogic,meson6-efuse", .data = &meson6_efuse_data }, + { .compatible = "amlogic,meson8-efuse", .data = &meson8_efuse_data }, + { .compatible = "amlogic,meson8b-efuse", .data = &meson8b_efuse_data }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, meson_mx_efuse_match); + +static int meson_mx_efuse_probe(struct platform_device *pdev) +{ + const struct meson_mx_efuse_platform_data *drvdata; + struct meson_mx_efuse *efuse; + struct resource *res; + + drvdata = of_device_get_match_data(&pdev->dev); + if (!drvdata) + return -EINVAL; + + efuse = devm_kzalloc(&pdev->dev, sizeof(*efuse), GFP_KERNEL); + if (!efuse) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + efuse->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(efuse->base)) + return PTR_ERR(efuse->base); + + efuse->config.name = devm_kstrdup(&pdev->dev, drvdata->name, + GFP_KERNEL); + efuse->config.owner = THIS_MODULE; + efuse->config.dev = &pdev->dev; + efuse->config.priv = efuse; + efuse->config.stride = drvdata->word_size; + efuse->config.word_size = drvdata->word_size; + efuse->config.size = SZ_512; + efuse->config.read_only = true; + efuse->config.reg_read = meson_mx_efuse_read; + + efuse->core_clk = devm_clk_get(&pdev->dev, "core"); + if (IS_ERR(efuse->core_clk)) { + dev_err(&pdev->dev, "Failed to get core clock\n"); + return PTR_ERR(efuse->core_clk); + } + + efuse->nvmem = nvmem_register(&efuse->config); + if (IS_ERR(efuse->nvmem)) + return PTR_ERR(efuse->nvmem); + + platform_set_drvdata(pdev, efuse); + + return 0; +} + +static int meson_mx_efuse_remove(struct platform_device *pdev) +{ + struct meson_mx_efuse *efuse = platform_get_drvdata(pdev); + + return nvmem_unregister(efuse->nvmem); +} + +static struct platform_driver meson_mx_efuse_driver = { + .probe = meson_mx_efuse_probe, + .remove = meson_mx_efuse_remove, + .driver = { + .name = "meson-mx-efuse", + .of_match_table = meson_mx_efuse_match, + }, +}; + +module_platform_driver(meson_mx_efuse_driver); + +MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>"); +MODULE_DESCRIPTION("Amlogic Meson MX eFuse NVMEM driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/nvmem/rockchip-efuse.c b/drivers/nvmem/rockchip-efuse.c index 63e3eb55f3ac..eb4c530c2564 100644 --- a/drivers/nvmem/rockchip-efuse.c +++ b/drivers/nvmem/rockchip-efuse.c @@ -178,6 +178,10 @@ static const struct of_device_id rockchip_efuse_match[] = { .data = (void *)&rockchip_rk3288_efuse_read, }, { + .compatible = "rockchip,rk3368-efuse", + .data = (void *)&rockchip_rk3288_efuse_read, + }, + { .compatible = "rockchip,rk3399-efuse", .data = (void *)&rockchip_rk3399_efuse_read, }, diff --git a/drivers/nvmem/snvs_lpgpr.c b/drivers/nvmem/snvs_lpgpr.c new file mode 100644 index 000000000000..e5c2a4a17f03 --- /dev/null +++ b/drivers/nvmem/snvs_lpgpr.c @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2015 Pengutronix, Steffen Trumtrar <kernel@pengutronix.de> + * Copyright (c) 2017 Pengutronix, Oleksij Rempel <kernel@pengutronix.de> + * + * 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 <linux/mfd/syscon.h> +#include <linux/module.h> +#include <linux/nvmem-provider.h> +#include <linux/of_device.h> +#include <linux/regmap.h> + +#define IMX6Q_SNVS_HPLR 0x00 +#define IMX6Q_GPR_SL BIT(5) +#define IMX6Q_SNVS_LPLR 0x34 +#define IMX6Q_GPR_HL BIT(5) +#define IMX6Q_SNVS_LPGPR 0x68 + +struct snvs_lpgpr_cfg { + int offset; + int offset_hplr; + int offset_lplr; +}; + +struct snvs_lpgpr_priv { + struct device_d *dev; + struct regmap *regmap; + struct nvmem_config cfg; + const struct snvs_lpgpr_cfg *dcfg; +}; + +static const struct snvs_lpgpr_cfg snvs_lpgpr_cfg_imx6q = { + .offset = IMX6Q_SNVS_LPGPR, + .offset_hplr = IMX6Q_SNVS_HPLR, + .offset_lplr = IMX6Q_SNVS_LPLR, +}; + +static int snvs_lpgpr_write(void *context, unsigned int offset, void *val, + size_t bytes) +{ + struct snvs_lpgpr_priv *priv = context; + const struct snvs_lpgpr_cfg *dcfg = priv->dcfg; + unsigned int lock_reg; + int ret; + + ret = regmap_read(priv->regmap, dcfg->offset_hplr, &lock_reg); + if (ret < 0) + return ret; + + if (lock_reg & IMX6Q_GPR_SL) + return -EPERM; + + ret = regmap_read(priv->regmap, dcfg->offset_lplr, &lock_reg); + if (ret < 0) + return ret; + + if (lock_reg & IMX6Q_GPR_HL) + return -EPERM; + + return regmap_bulk_write(priv->regmap, dcfg->offset + offset, val, + bytes / 4); +} + +static int snvs_lpgpr_read(void *context, unsigned int offset, void *val, + size_t bytes) +{ + struct snvs_lpgpr_priv *priv = context; + const struct snvs_lpgpr_cfg *dcfg = priv->dcfg; + + return regmap_bulk_read(priv->regmap, dcfg->offset + offset, + val, bytes / 4); +} + +static int snvs_lpgpr_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; + struct device_node *syscon_node; + struct snvs_lpgpr_priv *priv; + struct nvmem_config *cfg; + struct nvmem_device *nvmem; + const struct snvs_lpgpr_cfg *dcfg; + + if (!node) + return -ENOENT; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + dcfg = of_device_get_match_data(dev); + if (!dcfg) + return -EINVAL; + + syscon_node = of_get_parent(node); + if (!syscon_node) + return -ENODEV; + + priv->regmap = syscon_node_to_regmap(syscon_node); + of_node_put(syscon_node); + if (IS_ERR(priv->regmap)) + return PTR_ERR(priv->regmap); + + priv->dcfg = dcfg; + + cfg = &priv->cfg; + cfg->priv = priv; + cfg->name = dev_name(dev); + cfg->dev = dev; + cfg->stride = 4, + cfg->word_size = 4, + cfg->size = 4, + cfg->owner = THIS_MODULE, + cfg->reg_read = snvs_lpgpr_read, + cfg->reg_write = snvs_lpgpr_write, + + nvmem = nvmem_register(cfg); + if (IS_ERR(nvmem)) + return PTR_ERR(nvmem); + + platform_set_drvdata(pdev, nvmem); + + return 0; +} + +static int snvs_lpgpr_remove(struct platform_device *pdev) +{ + struct nvmem_device *nvmem = platform_get_drvdata(pdev); + + return nvmem_unregister(nvmem); +} + +static const struct of_device_id snvs_lpgpr_dt_ids[] = { + { .compatible = "fsl,imx6q-snvs-lpgpr", .data = &snvs_lpgpr_cfg_imx6q }, + { .compatible = "fsl,imx6ul-snvs-lpgpr", + .data = &snvs_lpgpr_cfg_imx6q }, + { }, +}; +MODULE_DEVICE_TABLE(of, snvs_lpgpr_dt_ids); + +static struct platform_driver snvs_lpgpr_driver = { + .probe = snvs_lpgpr_probe, + .remove = snvs_lpgpr_remove, + .driver = { + .name = "snvs_lpgpr", + .of_match_table = snvs_lpgpr_dt_ids, + }, +}; +module_platform_driver(snvs_lpgpr_driver); + +MODULE_AUTHOR("Oleksij Rempel <o.rempel@pengutronix.de>"); +MODULE_DESCRIPTION("Low Power General Purpose Register in i.MX6 Secure Non-Volatile Storage"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/parport/parport_ip32.c b/drivers/parport/parport_ip32.c index 0186db7680d4..62873070f988 100644 --- a/drivers/parport/parport_ip32.c +++ b/drivers/parport/parport_ip32.c @@ -1769,7 +1769,7 @@ stop: /*--- Default parport operations ---------------------------------------*/ -static __initdata struct parport_operations parport_ip32_ops = { +static const struct parport_operations parport_ip32_ops __initconst = { .write_data = parport_ip32_write_data, .read_data = parport_ip32_read_data, diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index 55ef7d1fd8da..102646fedb56 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c @@ -1599,7 +1599,7 @@ static ssize_t pccard_store_cis(struct file *filp, struct kobject *kobj, } -struct bin_attribute pccard_cis_attr = { +const struct bin_attribute pccard_cis_attr = { .attr = { .name = "cis", .mode = S_IRUGO | S_IWUSR }, .size = 0x200, .read = pccard_show_cis, diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index e86cd6b31773..6765beadea95 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -152,7 +152,7 @@ void pcmcia_cleanup_irq(struct pcmcia_socket *s); int pcmcia_setup_irq(struct pcmcia_device *p_dev); /* cistpl.c */ -extern struct bin_attribute pccard_cis_attr; +extern const struct bin_attribute pccard_cis_attr; int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr, u_int len, void *ptr); diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c index 70b089430fcc..9a4940e56e2f 100644 --- a/drivers/pcmcia/m32r_cfc.c +++ b/drivers/pcmcia/m32r_cfc.c @@ -380,11 +380,10 @@ static irqreturn_t pcc_interrupt(int irq, void *dev) return IRQ_RETVAL(handled); } /* pcc_interrupt */ -static void pcc_interrupt_wrapper(u_long data) +static void pcc_interrupt_wrapper(struct timer_list *unused) { pr_debug("m32r_cfc: pcc_interrupt_wrapper:\n"); pcc_interrupt(0, NULL); - init_timer(&poll_timer); poll_timer.expires = jiffies + poll_interval; add_timer(&poll_timer); } @@ -758,9 +757,7 @@ static int __init init_m32r_pcc(void) /* Finally, schedule a polling interrupt */ if (poll_interval != 0) { - poll_timer.function = pcc_interrupt_wrapper; - poll_timer.data = 0; - init_timer(&poll_timer); + timer_setup(&poll_timer, pcc_interrupt_wrapper, 0); poll_timer.expires = jiffies + poll_interval; add_timer(&poll_timer); } diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c index e50bbf826188..c2239a7e383a 100644 --- a/drivers/pcmcia/m32r_pcc.c +++ b/drivers/pcmcia/m32r_pcc.c @@ -386,10 +386,9 @@ static irqreturn_t pcc_interrupt(int irq, void *dev) return IRQ_RETVAL(handled); } /* pcc_interrupt */ -static void pcc_interrupt_wrapper(u_long data) +static void pcc_interrupt_wrapper(struct timer_list *unused) { pcc_interrupt(0, NULL); - init_timer(&poll_timer); poll_timer.expires = jiffies + poll_interval; add_timer(&poll_timer); } @@ -729,9 +728,7 @@ static int __init init_m32r_pcc(void) /* Finally, schedule a polling interrupt */ if (poll_interval != 0) { - poll_timer.function = pcc_interrupt_wrapper; - poll_timer.data = 0; - init_timer(&poll_timer); + timer_setup(&poll_timer, pcc_interrupt_wrapper, 0); poll_timer.expires = jiffies + poll_interval; add_timer(&poll_timer); } diff --git a/drivers/vme/bridges/vme_ca91cx42.c b/drivers/vme/bridges/vme_ca91cx42.c index 7cc51223db1c..5dd284008630 100644 --- a/drivers/vme/bridges/vme_ca91cx42.c +++ b/drivers/vme/bridges/vme_ca91cx42.c @@ -511,7 +511,7 @@ static int ca91cx42_alloc_resource(struct vme_master_resource *image, ca91cx42_bridge = image->parent; /* Find pci_dev container of dev */ - if (ca91cx42_bridge->parent == NULL) { + if (!ca91cx42_bridge->parent) { dev_err(ca91cx42_bridge->parent, "Dev entry NULL\n"); return -EINVAL; } @@ -529,14 +529,12 @@ static int ca91cx42_alloc_resource(struct vme_master_resource *image, image->kern_base = NULL; kfree(image->bus_resource.name); release_resource(&image->bus_resource); - memset(&image->bus_resource, 0, sizeof(struct resource)); + memset(&image->bus_resource, 0, sizeof(image->bus_resource)); } - if (image->bus_resource.name == NULL) { + if (!image->bus_resource.name) { image->bus_resource.name = kmalloc(VMENAMSIZ+3, GFP_ATOMIC); - if (image->bus_resource.name == NULL) { - dev_err(ca91cx42_bridge->parent, "Unable to allocate " - "memory for resource name\n"); + if (!image->bus_resource.name) { retval = -ENOMEM; goto err_name; } @@ -562,7 +560,7 @@ static int ca91cx42_alloc_resource(struct vme_master_resource *image, image->kern_base = ioremap_nocache( image->bus_resource.start, size); - if (image->kern_base == NULL) { + if (!image->kern_base) { dev_err(ca91cx42_bridge->parent, "Failed to remap resource\n"); retval = -ENOMEM; goto err_remap; @@ -574,7 +572,7 @@ err_remap: release_resource(&image->bus_resource); err_resource: kfree(image->bus_resource.name); - memset(&image->bus_resource, 0, sizeof(struct resource)); + memset(&image->bus_resource, 0, sizeof(image->bus_resource)); err_name: return retval; } @@ -588,7 +586,7 @@ static void ca91cx42_free_resource(struct vme_master_resource *image) image->kern_base = NULL; release_resource(&image->bus_resource); kfree(image->bus_resource.name); - memset(&image->bus_resource, 0, sizeof(struct resource)); + memset(&image->bus_resource, 0, sizeof(image->bus_resource)); } @@ -1036,10 +1034,8 @@ static int ca91cx42_dma_list_add(struct vme_dma_list *list, dev = list->parent->parent->parent; /* XXX descriptor must be aligned on 64-bit boundaries */ - entry = kmalloc(sizeof(struct ca91cx42_dma_entry), GFP_KERNEL); - if (entry == NULL) { - dev_err(dev, "Failed to allocate memory for dma resource " - "structure\n"); + entry = kmalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) { retval = -ENOMEM; goto err_mem; } @@ -1052,7 +1048,7 @@ static int ca91cx42_dma_list_add(struct vme_dma_list *list, goto err_align; } - memset(&entry->descriptor, 0, sizeof(struct ca91cx42_dma_descriptor)); + memset(&entry->descriptor, 0, sizeof(entry->descriptor)); if (dest->type == VME_DMA_VME) { entry->descriptor.dctl |= CA91CX42_DCTL_L2V; @@ -1323,7 +1319,7 @@ static int ca91cx42_lm_set(struct vme_lm_resource *lm, /* If we already have a callback attached, we can't move it! */ for (i = 0; i < lm->monitors; i++) { - if (bridge->lm_callback[i] != NULL) { + if (bridge->lm_callback[i]) { mutex_unlock(&lm->mtx); dev_err(dev, "Location monitor callback attached, " "can't reset\n"); @@ -1432,7 +1428,7 @@ static int ca91cx42_lm_attach(struct vme_lm_resource *lm, int monitor, } /* Check that a callback isn't already attached */ - if (bridge->lm_callback[monitor] != NULL) { + if (bridge->lm_callback[monitor]) { mutex_unlock(&lm->mtx); dev_err(dev, "Existing callback attached\n"); return -EBUSY; @@ -1567,7 +1563,7 @@ static int ca91cx42_crcsr_init(struct vme_bridge *ca91cx42_bridge, /* Allocate mem for CR/CSR image */ bridge->crcsr_kernel = pci_zalloc_consistent(pdev, VME_CRCSR_BUF_SIZE, &bridge->crcsr_bus); - if (bridge->crcsr_kernel == NULL) { + if (!bridge->crcsr_kernel) { dev_err(&pdev->dev, "Failed to allocate memory for CR/CSR " "image\n"); return -ENOMEM; @@ -1618,21 +1614,15 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* We want to support more than one of each bridge so we need to * dynamically allocate the bridge structure */ - ca91cx42_bridge = kzalloc(sizeof(struct vme_bridge), GFP_KERNEL); - - if (ca91cx42_bridge == NULL) { - dev_err(&pdev->dev, "Failed to allocate memory for device " - "structure\n"); + ca91cx42_bridge = kzalloc(sizeof(*ca91cx42_bridge), GFP_KERNEL); + if (!ca91cx42_bridge) { retval = -ENOMEM; goto err_struct; } vme_init_bridge(ca91cx42_bridge); - ca91cx42_device = kzalloc(sizeof(struct ca91cx42_driver), GFP_KERNEL); - - if (ca91cx42_device == NULL) { - dev_err(&pdev->dev, "Failed to allocate memory for device " - "structure\n"); + ca91cx42_device = kzalloc(sizeof(*ca91cx42_device), GFP_KERNEL); + if (!ca91cx42_device) { retval = -ENOMEM; goto err_driver; } @@ -1688,11 +1678,8 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* Add master windows to list */ for (i = 0; i < CA91C142_MAX_MASTER; i++) { - master_image = kmalloc(sizeof(struct vme_master_resource), - GFP_KERNEL); - if (master_image == NULL) { - dev_err(&pdev->dev, "Failed to allocate memory for " - "master resource structure\n"); + master_image = kmalloc(sizeof(*master_image), GFP_KERNEL); + if (!master_image) { retval = -ENOMEM; goto err_master; } @@ -1706,7 +1693,7 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id) VME_SUPER | VME_USER | VME_PROG | VME_DATA; master_image->width_attr = VME_D8 | VME_D16 | VME_D32 | VME_D64; memset(&master_image->bus_resource, 0, - sizeof(struct resource)); + sizeof(master_image->bus_resource)); master_image->kern_base = NULL; list_add_tail(&master_image->list, &ca91cx42_bridge->master_resources); @@ -1714,11 +1701,8 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* Add slave windows to list */ for (i = 0; i < CA91C142_MAX_SLAVE; i++) { - slave_image = kmalloc(sizeof(struct vme_slave_resource), - GFP_KERNEL); - if (slave_image == NULL) { - dev_err(&pdev->dev, "Failed to allocate memory for " - "slave resource structure\n"); + slave_image = kmalloc(sizeof(*slave_image), GFP_KERNEL); + if (!slave_image) { retval = -ENOMEM; goto err_slave; } @@ -1741,11 +1725,8 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* Add dma engines to list */ for (i = 0; i < CA91C142_MAX_DMA; i++) { - dma_ctrlr = kmalloc(sizeof(struct vme_dma_resource), - GFP_KERNEL); - if (dma_ctrlr == NULL) { - dev_err(&pdev->dev, "Failed to allocate memory for " - "dma resource structure\n"); + dma_ctrlr = kmalloc(sizeof(*dma_ctrlr), GFP_KERNEL); + if (!dma_ctrlr) { retval = -ENOMEM; goto err_dma; } @@ -1762,10 +1743,8 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id) } /* Add location monitor to list */ - lm = kmalloc(sizeof(struct vme_lm_resource), GFP_KERNEL); - if (lm == NULL) { - dev_err(&pdev->dev, "Failed to allocate memory for " - "location monitor resource structure\n"); + lm = kmalloc(sizeof(*lm), GFP_KERNEL); + if (!lm) { retval = -ENOMEM; goto err_lm; } diff --git a/drivers/vme/bridges/vme_fake.c b/drivers/vme/bridges/vme_fake.c index 30b3acc93833..7d83691047f4 100644 --- a/drivers/vme/bridges/vme_fake.c +++ b/drivers/vme/bridges/vme_fake.c @@ -409,7 +409,7 @@ static void fake_lm_check(struct fake_driver *bridge, unsigned long long addr, /* Each location monitor covers 8 bytes */ if (((lm_base + (8 * i)) <= addr) && ((lm_base + (8 * i) + 8) > addr)) { - if (bridge->lm_callback[i] != NULL) + if (bridge->lm_callback[i]) bridge->lm_callback[i]( bridge->lm_data[i]); } @@ -866,7 +866,7 @@ static int fake_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base, /* If we already have a callback attached, we can't move it! */ for (i = 0; i < lm->monitors; i++) { - if (bridge->lm_callback[i] != NULL) { + if (bridge->lm_callback[i]) { mutex_unlock(&lm->mtx); pr_err("Location monitor callback attached, can't reset\n"); return -EBUSY; @@ -940,7 +940,7 @@ static int fake_lm_attach(struct vme_lm_resource *lm, int monitor, } /* Check that a callback isn't already attached */ - if (bridge->lm_callback[monitor] != NULL) { + if (bridge->lm_callback[monitor]) { mutex_unlock(&lm->mtx); pr_err("Existing callback attached\n"); return -EBUSY; @@ -978,7 +978,7 @@ static int fake_lm_detach(struct vme_lm_resource *lm, int monitor) /* If all location monitors disabled, disable global Location Monitor */ tmp = 0; for (i = 0; i < lm->monitors; i++) { - if (bridge->lm_callback[i] != NULL) + if (bridge->lm_callback[i]) tmp = 1; } @@ -1003,7 +1003,7 @@ static void *fake_alloc_consistent(struct device *parent, size_t size, { void *alloc = kmalloc(size, GFP_KERNEL); - if (alloc != NULL) + if (alloc) *dma = fake_ptr_to_pci(alloc); return alloc; @@ -1039,7 +1039,7 @@ static int fake_crcsr_init(struct vme_bridge *fake_bridge) /* Allocate mem for CR/CSR image */ bridge->crcsr_kernel = kzalloc(VME_CRCSR_BUF_SIZE, GFP_KERNEL); bridge->crcsr_bus = fake_ptr_to_pci(bridge->crcsr_kernel); - if (bridge->crcsr_kernel == NULL) + if (!bridge->crcsr_kernel) return -ENOMEM; vstat = fake_slot_get(fake_bridge); @@ -1075,14 +1075,14 @@ static int __init fake_init(void) /* If we want to support more than one bridge at some point, we need to * dynamically allocate this so we get one per device. */ - fake_bridge = kzalloc(sizeof(struct vme_bridge), GFP_KERNEL); - if (fake_bridge == NULL) { + fake_bridge = kzalloc(sizeof(*fake_bridge), GFP_KERNEL); + if (!fake_bridge) { retval = -ENOMEM; goto err_struct; } - fake_device = kzalloc(sizeof(struct fake_driver), GFP_KERNEL); - if (fake_device == NULL) { + fake_device = kzalloc(sizeof(*fake_device), GFP_KERNEL); + if (!fake_device) { retval = -ENOMEM; goto err_driver; } @@ -1104,9 +1104,8 @@ static int __init fake_init(void) /* Add master windows to list */ INIT_LIST_HEAD(&fake_bridge->master_resources); for (i = 0; i < FAKE_MAX_MASTER; i++) { - master_image = kmalloc(sizeof(struct vme_master_resource), - GFP_KERNEL); - if (master_image == NULL) { + master_image = kmalloc(sizeof(*master_image), GFP_KERNEL); + if (!master_image) { retval = -ENOMEM; goto err_master; } @@ -1131,9 +1130,8 @@ static int __init fake_init(void) /* Add slave windows to list */ INIT_LIST_HEAD(&fake_bridge->slave_resources); for (i = 0; i < FAKE_MAX_SLAVE; i++) { - slave_image = kmalloc(sizeof(struct vme_slave_resource), - GFP_KERNEL); - if (slave_image == NULL) { + slave_image = kmalloc(sizeof(*slave_image), GFP_KERNEL); + if (!slave_image) { retval = -ENOMEM; goto err_slave; } @@ -1154,9 +1152,8 @@ static int __init fake_init(void) /* Add location monitor to list */ INIT_LIST_HEAD(&fake_bridge->lm_resources); - lm = kmalloc(sizeof(struct vme_lm_resource), GFP_KERNEL); - if (lm == NULL) { - pr_err("Failed to allocate memory for location monitor resource structure\n"); + lm = kmalloc(sizeof(*lm), GFP_KERNEL); + if (!lm) { retval = -ENOMEM; goto err_lm; } diff --git a/drivers/vme/bridges/vme_tsi148.c b/drivers/vme/bridges/vme_tsi148.c index fc1b634b969a..647d231d4422 100644 --- a/drivers/vme/bridges/vme_tsi148.c +++ b/drivers/vme/bridges/vme_tsi148.c @@ -741,18 +741,16 @@ static int tsi148_alloc_resource(struct vme_master_resource *image, image->kern_base = NULL; kfree(image->bus_resource.name); release_resource(&image->bus_resource); - memset(&image->bus_resource, 0, sizeof(struct resource)); + memset(&image->bus_resource, 0, sizeof(image->bus_resource)); } /* Exit here if size is zero */ if (size == 0) return 0; - if (image->bus_resource.name == NULL) { + if (!image->bus_resource.name) { image->bus_resource.name = kmalloc(VMENAMSIZ+3, GFP_ATOMIC); - if (image->bus_resource.name == NULL) { - dev_err(tsi148_bridge->parent, "Unable to allocate " - "memory for resource name\n"); + if (!image->bus_resource.name) { retval = -ENOMEM; goto err_name; } @@ -778,7 +776,7 @@ static int tsi148_alloc_resource(struct vme_master_resource *image, image->kern_base = ioremap_nocache( image->bus_resource.start, size); - if (image->kern_base == NULL) { + if (!image->kern_base) { dev_err(tsi148_bridge->parent, "Failed to remap resource\n"); retval = -ENOMEM; goto err_remap; @@ -790,7 +788,7 @@ err_remap: release_resource(&image->bus_resource); err_resource: kfree(image->bus_resource.name); - memset(&image->bus_resource, 0, sizeof(struct resource)); + memset(&image->bus_resource, 0, sizeof(image->bus_resource)); err_name: return retval; } @@ -804,7 +802,7 @@ static void tsi148_free_resource(struct vme_master_resource *image) image->kern_base = NULL; release_resource(&image->bus_resource); kfree(image->bus_resource.name); - memset(&image->bus_resource, 0, sizeof(struct resource)); + memset(&image->bus_resource, 0, sizeof(image->bus_resource)); } /* @@ -1641,10 +1639,8 @@ static int tsi148_dma_list_add(struct vme_dma_list *list, tsi148_bridge = list->parent->parent; /* Descriptor must be aligned on 64-bit boundaries */ - entry = kmalloc(sizeof(struct tsi148_dma_entry), GFP_KERNEL); - if (entry == NULL) { - dev_err(tsi148_bridge->parent, "Failed to allocate memory for " - "dma resource structure\n"); + entry = kmalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) { retval = -ENOMEM; goto err_mem; } @@ -1661,7 +1657,7 @@ static int tsi148_dma_list_add(struct vme_dma_list *list, /* Given we are going to fill out the structure, we probably don't * need to zero it, but better safe than sorry for now. */ - memset(&entry->descriptor, 0, sizeof(struct tsi148_dma_descriptor)); + memset(&entry->descriptor, 0, sizeof(entry->descriptor)); /* Fill out source part */ switch (src->type) { @@ -1756,8 +1752,9 @@ static int tsi148_dma_list_add(struct vme_dma_list *list, list_add_tail(&entry->list, &list->entries); entry->dma_handle = dma_map_single(tsi148_bridge->parent, - &entry->descriptor, - sizeof(struct tsi148_dma_descriptor), DMA_TO_DEVICE); + &entry->descriptor, + sizeof(entry->descriptor), + DMA_TO_DEVICE); if (dma_mapping_error(tsi148_bridge->parent, entry->dma_handle)) { dev_err(tsi148_bridge->parent, "DMA mapping error\n"); retval = -EINVAL; @@ -1946,7 +1943,7 @@ static int tsi148_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base, /* If we already have a callback attached, we can't move it! */ for (i = 0; i < lm->monitors; i++) { - if (bridge->lm_callback[i] != NULL) { + if (bridge->lm_callback[i]) { mutex_unlock(&lm->mtx); dev_err(tsi148_bridge->parent, "Location monitor " "callback attached, can't reset\n"); @@ -2071,7 +2068,7 @@ static int tsi148_lm_attach(struct vme_lm_resource *lm, int monitor, } /* Check that a callback isn't already attached */ - if (bridge->lm_callback[monitor] != NULL) { + if (bridge->lm_callback[monitor]) { mutex_unlock(&lm->mtx); dev_err(tsi148_bridge->parent, "Existing callback attached\n"); return -EBUSY; @@ -2208,7 +2205,7 @@ static int tsi148_crcsr_init(struct vme_bridge *tsi148_bridge, /* Allocate mem for CR/CSR image */ bridge->crcsr_kernel = pci_zalloc_consistent(pdev, VME_CRCSR_BUF_SIZE, &bridge->crcsr_bus); - if (bridge->crcsr_kernel == NULL) { + if (!bridge->crcsr_kernel) { dev_err(tsi148_bridge->parent, "Failed to allocate memory for " "CR/CSR image\n"); return -ENOMEM; @@ -2294,19 +2291,15 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* If we want to support more than one of each bridge, we need to * dynamically generate this so we get one per device */ - tsi148_bridge = kzalloc(sizeof(struct vme_bridge), GFP_KERNEL); - if (tsi148_bridge == NULL) { - dev_err(&pdev->dev, "Failed to allocate memory for device " - "structure\n"); + tsi148_bridge = kzalloc(sizeof(*tsi148_bridge), GFP_KERNEL); + if (!tsi148_bridge) { retval = -ENOMEM; goto err_struct; } vme_init_bridge(tsi148_bridge); - tsi148_device = kzalloc(sizeof(struct tsi148_driver), GFP_KERNEL); - if (tsi148_device == NULL) { - dev_err(&pdev->dev, "Failed to allocate memory for device " - "structure\n"); + tsi148_device = kzalloc(sizeof(*tsi148_device), GFP_KERNEL); + if (!tsi148_device) { retval = -ENOMEM; goto err_driver; } @@ -2371,10 +2364,9 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id) master_num--; tsi148_device->flush_image = - kmalloc(sizeof(struct vme_master_resource), GFP_KERNEL); - if (tsi148_device->flush_image == NULL) { - dev_err(&pdev->dev, "Failed to allocate memory for " - "flush resource structure\n"); + kmalloc(sizeof(*tsi148_device->flush_image), + GFP_KERNEL); + if (!tsi148_device->flush_image) { retval = -ENOMEM; goto err_master; } @@ -2383,17 +2375,14 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id) tsi148_device->flush_image->locked = 1; tsi148_device->flush_image->number = master_num; memset(&tsi148_device->flush_image->bus_resource, 0, - sizeof(struct resource)); + sizeof(tsi148_device->flush_image->bus_resource)); tsi148_device->flush_image->kern_base = NULL; } /* Add master windows to list */ for (i = 0; i < master_num; i++) { - master_image = kmalloc(sizeof(struct vme_master_resource), - GFP_KERNEL); - if (master_image == NULL) { - dev_err(&pdev->dev, "Failed to allocate memory for " - "master resource structure\n"); + master_image = kmalloc(sizeof(*master_image), GFP_KERNEL); + if (!master_image) { retval = -ENOMEM; goto err_master; } @@ -2410,7 +2399,7 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id) VME_PROG | VME_DATA; master_image->width_attr = VME_D16 | VME_D32; memset(&master_image->bus_resource, 0, - sizeof(struct resource)); + sizeof(master_image->bus_resource)); master_image->kern_base = NULL; list_add_tail(&master_image->list, &tsi148_bridge->master_resources); @@ -2418,11 +2407,8 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* Add slave windows to list */ for (i = 0; i < TSI148_MAX_SLAVE; i++) { - slave_image = kmalloc(sizeof(struct vme_slave_resource), - GFP_KERNEL); - if (slave_image == NULL) { - dev_err(&pdev->dev, "Failed to allocate memory for " - "slave resource structure\n"); + slave_image = kmalloc(sizeof(*slave_image), GFP_KERNEL); + if (!slave_image) { retval = -ENOMEM; goto err_slave; } @@ -2442,11 +2428,8 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* Add dma engines to list */ for (i = 0; i < TSI148_MAX_DMA; i++) { - dma_ctrlr = kmalloc(sizeof(struct vme_dma_resource), - GFP_KERNEL); - if (dma_ctrlr == NULL) { - dev_err(&pdev->dev, "Failed to allocate memory for " - "dma resource structure\n"); + dma_ctrlr = kmalloc(sizeof(*dma_ctrlr), GFP_KERNEL); + if (!dma_ctrlr) { retval = -ENOMEM; goto err_dma; } @@ -2465,10 +2448,8 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id) } /* Add location monitor to list */ - lm = kmalloc(sizeof(struct vme_lm_resource), GFP_KERNEL); - if (lm == NULL) { - dev_err(&pdev->dev, "Failed to allocate memory for " - "location monitor resource structure\n"); + lm = kmalloc(sizeof(*lm), GFP_KERNEL); + if (!lm) { retval = -ENOMEM; goto err_lm; } diff --git a/drivers/vme/vme.c b/drivers/vme/vme.c index 6a3ead42aba8..d0ce50d56019 100644 --- a/drivers/vme/vme.c +++ b/drivers/vme/vme.c @@ -92,23 +92,23 @@ void *vme_alloc_consistent(struct vme_resource *resource, size_t size, { struct vme_bridge *bridge; - if (resource == NULL) { + if (!resource) { printk(KERN_ERR "No resource\n"); return NULL; } bridge = find_bridge(resource); - if (bridge == NULL) { + if (!bridge) { printk(KERN_ERR "Can't find bridge\n"); return NULL; } - if (bridge->parent == NULL) { + if (!bridge->parent) { printk(KERN_ERR "Dev entry NULL for bridge %s\n", bridge->name); return NULL; } - if (bridge->alloc_consistent == NULL) { + if (!bridge->alloc_consistent) { printk(KERN_ERR "alloc_consistent not supported by bridge %s\n", bridge->name); return NULL; @@ -132,23 +132,23 @@ void vme_free_consistent(struct vme_resource *resource, size_t size, { struct vme_bridge *bridge; - if (resource == NULL) { + if (!resource) { printk(KERN_ERR "No resource\n"); return; } bridge = find_bridge(resource); - if (bridge == NULL) { + if (!bridge) { printk(KERN_ERR "Can't find bridge\n"); return; } - if (bridge->parent == NULL) { + if (!bridge->parent) { printk(KERN_ERR "Dev entry NULL for bridge %s\n", bridge->name); return; } - if (bridge->free_consistent == NULL) { + if (!bridge->free_consistent) { printk(KERN_ERR "free_consistent not supported by bridge %s\n", bridge->name); return; @@ -208,29 +208,27 @@ int vme_check_window(u32 aspace, unsigned long long vme_base, { int retval = 0; + if (vme_base + size < size) + return -EINVAL; + switch (aspace) { case VME_A16: - if (((vme_base + size) > VME_A16_MAX) || - (vme_base > VME_A16_MAX)) + if (vme_base + size > VME_A16_MAX) retval = -EFAULT; break; case VME_A24: - if (((vme_base + size) > VME_A24_MAX) || - (vme_base > VME_A24_MAX)) + if (vme_base + size > VME_A24_MAX) retval = -EFAULT; break; case VME_A32: - if (((vme_base + size) > VME_A32_MAX) || - (vme_base > VME_A32_MAX)) + if (vme_base + size > VME_A32_MAX) retval = -EFAULT; break; case VME_A64: - if ((size != 0) && (vme_base > U64_MAX + 1 - size)) - retval = -EFAULT; + /* The VME_A64_MAX limit is actually U64_MAX + 1 */ break; case VME_CRCSR: - if (((vme_base + size) > VME_CRCSR_MAX) || - (vme_base > VME_CRCSR_MAX)) + if (vme_base + size > VME_CRCSR_MAX) retval = -EFAULT; break; case VME_USER1: @@ -303,7 +301,7 @@ struct vme_resource *vme_slave_request(struct vme_dev *vdev, u32 address, struct vme_resource *resource = NULL; bridge = vdev->bridge; - if (bridge == NULL) { + if (!bridge) { printk(KERN_ERR "Can't find VME bus\n"); goto err_bus; } @@ -313,7 +311,7 @@ struct vme_resource *vme_slave_request(struct vme_dev *vdev, u32 address, slave_image = list_entry(slave_pos, struct vme_slave_resource, list); - if (slave_image == NULL) { + if (!slave_image) { printk(KERN_ERR "Registered NULL Slave resource\n"); continue; } @@ -333,14 +331,13 @@ struct vme_resource *vme_slave_request(struct vme_dev *vdev, u32 address, } /* No free image */ - if (allocated_image == NULL) + if (!allocated_image) goto err_image; - resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL); - if (resource == NULL) { - printk(KERN_WARNING "Unable to allocate resource structure\n"); + resource = kmalloc(sizeof(*resource), GFP_KERNEL); + if (!resource) goto err_alloc; - } + resource->type = VME_SLAVE; resource->entry = &allocated_image->list; @@ -389,7 +386,7 @@ int vme_slave_set(struct vme_resource *resource, int enabled, image = list_entry(resource->entry, struct vme_slave_resource, list); - if (bridge->slave_set == NULL) { + if (!bridge->slave_set) { printk(KERN_ERR "Function not supported\n"); return -ENOSYS; } @@ -438,7 +435,7 @@ int vme_slave_get(struct vme_resource *resource, int *enabled, image = list_entry(resource->entry, struct vme_slave_resource, list); - if (bridge->slave_get == NULL) { + if (!bridge->slave_get) { printk(KERN_ERR "vme_slave_get not supported\n"); return -EINVAL; } @@ -465,7 +462,7 @@ void vme_slave_free(struct vme_resource *resource) slave_image = list_entry(resource->entry, struct vme_slave_resource, list); - if (slave_image == NULL) { + if (!slave_image) { printk(KERN_ERR "Can't find slave resource\n"); return; } @@ -505,7 +502,7 @@ struct vme_resource *vme_master_request(struct vme_dev *vdev, u32 address, struct vme_resource *resource = NULL; bridge = vdev->bridge; - if (bridge == NULL) { + if (!bridge) { printk(KERN_ERR "Can't find VME bus\n"); goto err_bus; } @@ -515,7 +512,7 @@ struct vme_resource *vme_master_request(struct vme_dev *vdev, u32 address, master_image = list_entry(master_pos, struct vme_master_resource, list); - if (master_image == NULL) { + if (!master_image) { printk(KERN_WARNING "Registered NULL master resource\n"); continue; } @@ -536,16 +533,15 @@ struct vme_resource *vme_master_request(struct vme_dev *vdev, u32 address, } /* Check to see if we found a resource */ - if (allocated_image == NULL) { + if (!allocated_image) { printk(KERN_ERR "Can't find a suitable resource\n"); goto err_image; } - resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL); - if (resource == NULL) { - printk(KERN_ERR "Unable to allocate resource structure\n"); + resource = kmalloc(sizeof(*resource), GFP_KERNEL); + if (!resource) goto err_alloc; - } + resource->type = VME_MASTER; resource->entry = &allocated_image->list; @@ -594,7 +590,7 @@ int vme_master_set(struct vme_resource *resource, int enabled, image = list_entry(resource->entry, struct vme_master_resource, list); - if (bridge->master_set == NULL) { + if (!bridge->master_set) { printk(KERN_WARNING "vme_master_set not supported\n"); return -EINVAL; } @@ -644,7 +640,7 @@ int vme_master_get(struct vme_resource *resource, int *enabled, image = list_entry(resource->entry, struct vme_master_resource, list); - if (bridge->master_get == NULL) { + if (!bridge->master_get) { printk(KERN_WARNING "%s not supported\n", __func__); return -EINVAL; } @@ -676,7 +672,7 @@ ssize_t vme_master_read(struct vme_resource *resource, void *buf, size_t count, struct vme_master_resource *image; size_t length; - if (bridge->master_read == NULL) { + if (!bridge->master_read) { printk(KERN_WARNING "Reading from resource not supported\n"); return -EINVAL; } @@ -725,7 +721,7 @@ ssize_t vme_master_write(struct vme_resource *resource, void *buf, struct vme_master_resource *image; size_t length; - if (bridge->master_write == NULL) { + if (!bridge->master_write) { printk(KERN_WARNING "Writing to resource not supported\n"); return -EINVAL; } @@ -776,7 +772,7 @@ unsigned int vme_master_rmw(struct vme_resource *resource, unsigned int mask, struct vme_bridge *bridge = find_bridge(resource); struct vme_master_resource *image; - if (bridge->master_rmw == NULL) { + if (!bridge->master_rmw) { printk(KERN_WARNING "Writing to resource not supported\n"); return -EINVAL; } @@ -846,7 +842,7 @@ void vme_master_free(struct vme_resource *resource) master_image = list_entry(resource->entry, struct vme_master_resource, list); - if (master_image == NULL) { + if (!master_image) { printk(KERN_ERR "Can't find master resource\n"); return; } @@ -886,7 +882,7 @@ struct vme_resource *vme_dma_request(struct vme_dev *vdev, u32 route) printk(KERN_ERR "No VME resource Attribute tests done\n"); bridge = vdev->bridge; - if (bridge == NULL) { + if (!bridge) { printk(KERN_ERR "Can't find VME bus\n"); goto err_bus; } @@ -895,8 +891,7 @@ struct vme_resource *vme_dma_request(struct vme_dev *vdev, u32 route) list_for_each(dma_pos, &bridge->dma_resources) { dma_ctrlr = list_entry(dma_pos, struct vme_dma_resource, list); - - if (dma_ctrlr == NULL) { + if (!dma_ctrlr) { printk(KERN_ERR "Registered NULL DMA resource\n"); continue; } @@ -915,14 +910,13 @@ struct vme_resource *vme_dma_request(struct vme_dev *vdev, u32 route) } /* Check to see if we found a resource */ - if (allocated_ctrlr == NULL) + if (!allocated_ctrlr) goto err_ctrlr; - resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL); - if (resource == NULL) { - printk(KERN_WARNING "Unable to allocate resource structure\n"); + resource = kmalloc(sizeof(*resource), GFP_KERNEL); + if (!resource) goto err_alloc; - } + resource->type = VME_DMA; resource->entry = &allocated_ctrlr->list; @@ -951,7 +945,6 @@ EXPORT_SYMBOL(vme_dma_request); */ struct vme_dma_list *vme_new_dma_list(struct vme_resource *resource) { - struct vme_dma_resource *ctrlr; struct vme_dma_list *dma_list; if (resource->type != VME_DMA) { @@ -959,15 +952,14 @@ struct vme_dma_list *vme_new_dma_list(struct vme_resource *resource) return NULL; } - ctrlr = list_entry(resource->entry, struct vme_dma_resource, list); - - dma_list = kmalloc(sizeof(struct vme_dma_list), GFP_KERNEL); - if (dma_list == NULL) { - printk(KERN_ERR "Unable to allocate memory for new DMA list\n"); + dma_list = kmalloc(sizeof(*dma_list), GFP_KERNEL); + if (!dma_list) return NULL; - } + INIT_LIST_HEAD(&dma_list->entries); - dma_list->parent = ctrlr; + dma_list->parent = list_entry(resource->entry, + struct vme_dma_resource, + list); mutex_init(&dma_list->mtx); return dma_list; @@ -990,17 +982,13 @@ struct vme_dma_attr *vme_dma_pattern_attribute(u32 pattern, u32 type) struct vme_dma_attr *attributes; struct vme_dma_pattern *pattern_attr; - attributes = kmalloc(sizeof(struct vme_dma_attr), GFP_KERNEL); - if (attributes == NULL) { - printk(KERN_ERR "Unable to allocate memory for attributes structure\n"); + attributes = kmalloc(sizeof(*attributes), GFP_KERNEL); + if (!attributes) goto err_attr; - } - pattern_attr = kmalloc(sizeof(struct vme_dma_pattern), GFP_KERNEL); - if (pattern_attr == NULL) { - printk(KERN_ERR "Unable to allocate memory for pattern attributes\n"); + pattern_attr = kmalloc(sizeof(*pattern_attr), GFP_KERNEL); + if (!pattern_attr) goto err_pat; - } attributes->type = VME_DMA_PATTERN; attributes->private = (void *)pattern_attr; @@ -1034,19 +1022,13 @@ struct vme_dma_attr *vme_dma_pci_attribute(dma_addr_t address) /* XXX Run some sanity checks here */ - attributes = kmalloc(sizeof(struct vme_dma_attr), GFP_KERNEL); - if (attributes == NULL) { - printk(KERN_ERR "Unable to allocate memory for attributes structure\n"); + attributes = kmalloc(sizeof(*attributes), GFP_KERNEL); + if (!attributes) goto err_attr; - } - pci_attr = kmalloc(sizeof(struct vme_dma_pci), GFP_KERNEL); - if (pci_attr == NULL) { - printk(KERN_ERR "Unable to allocate memory for PCI attributes\n"); + pci_attr = kmalloc(sizeof(*pci_attr), GFP_KERNEL); + if (!pci_attr) goto err_pci; - } - - attributes->type = VME_DMA_PCI; attributes->private = (void *)pci_attr; @@ -1081,18 +1063,13 @@ struct vme_dma_attr *vme_dma_vme_attribute(unsigned long long address, struct vme_dma_attr *attributes; struct vme_dma_vme *vme_attr; - attributes = kmalloc( - sizeof(struct vme_dma_attr), GFP_KERNEL); - if (attributes == NULL) { - printk(KERN_ERR "Unable to allocate memory for attributes structure\n"); + attributes = kmalloc(sizeof(*attributes), GFP_KERNEL); + if (!attributes) goto err_attr; - } - vme_attr = kmalloc(sizeof(struct vme_dma_vme), GFP_KERNEL); - if (vme_attr == NULL) { - printk(KERN_ERR "Unable to allocate memory for VME attributes\n"); + vme_attr = kmalloc(sizeof(*vme_attr), GFP_KERNEL); + if (!vme_attr) goto err_vme; - } attributes->type = VME_DMA_VME; attributes->private = (void *)vme_attr; @@ -1148,7 +1125,7 @@ int vme_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src, struct vme_bridge *bridge = list->parent->parent; int retval; - if (bridge->dma_list_add == NULL) { + if (!bridge->dma_list_add) { printk(KERN_WARNING "Link List DMA generation not supported\n"); return -EINVAL; } @@ -1181,7 +1158,7 @@ int vme_dma_list_exec(struct vme_dma_list *list) struct vme_bridge *bridge = list->parent->parent; int retval; - if (bridge->dma_list_exec == NULL) { + if (!bridge->dma_list_exec) { printk(KERN_ERR "Link List DMA execution not supported\n"); return -EINVAL; } @@ -1210,7 +1187,7 @@ int vme_dma_list_free(struct vme_dma_list *list) struct vme_bridge *bridge = list->parent->parent; int retval; - if (bridge->dma_list_empty == NULL) { + if (!bridge->dma_list_empty) { printk(KERN_WARNING "Emptying of Link Lists not supported\n"); return -EINVAL; } @@ -1342,8 +1319,7 @@ void vme_irq_handler(struct vme_bridge *bridge, int level, int statid) call = bridge->irq[level - 1].callback[statid].func; priv_data = bridge->irq[level - 1].callback[statid].priv_data; - - if (call != NULL) + if (call) call(level, statid, priv_data); else printk(KERN_WARNING "Spurious VME interrupt, level:%x, vector:%x\n", @@ -1374,7 +1350,7 @@ int vme_irq_request(struct vme_dev *vdev, int level, int statid, struct vme_bridge *bridge; bridge = vdev->bridge; - if (bridge == NULL) { + if (!bridge) { printk(KERN_ERR "Can't find VME bus\n"); return -EINVAL; } @@ -1384,7 +1360,7 @@ int vme_irq_request(struct vme_dev *vdev, int level, int statid, return -EINVAL; } - if (bridge->irq_set == NULL) { + if (!bridge->irq_set) { printk(KERN_ERR "Configuring interrupts not supported\n"); return -EINVAL; } @@ -1423,7 +1399,7 @@ void vme_irq_free(struct vme_dev *vdev, int level, int statid) struct vme_bridge *bridge; bridge = vdev->bridge; - if (bridge == NULL) { + if (!bridge) { printk(KERN_ERR "Can't find VME bus\n"); return; } @@ -1433,7 +1409,7 @@ void vme_irq_free(struct vme_dev *vdev, int level, int statid) return; } - if (bridge->irq_set == NULL) { + if (!bridge->irq_set) { printk(KERN_ERR "Configuring interrupts not supported\n"); return; } @@ -1470,7 +1446,7 @@ int vme_irq_generate(struct vme_dev *vdev, int level, int statid) struct vme_bridge *bridge; bridge = vdev->bridge; - if (bridge == NULL) { + if (!bridge) { printk(KERN_ERR "Can't find VME bus\n"); return -EINVAL; } @@ -1480,7 +1456,7 @@ int vme_irq_generate(struct vme_dev *vdev, int level, int statid) return -EINVAL; } - if (bridge->irq_generate == NULL) { + if (!bridge->irq_generate) { printk(KERN_WARNING "Interrupt generation not supported\n"); return -EINVAL; } @@ -1508,7 +1484,7 @@ struct vme_resource *vme_lm_request(struct vme_dev *vdev) struct vme_resource *resource = NULL; bridge = vdev->bridge; - if (bridge == NULL) { + if (!bridge) { printk(KERN_ERR "Can't find VME bus\n"); goto err_bus; } @@ -1517,8 +1493,7 @@ struct vme_resource *vme_lm_request(struct vme_dev *vdev) list_for_each(lm_pos, &bridge->lm_resources) { lm = list_entry(lm_pos, struct vme_lm_resource, list); - - if (lm == NULL) { + if (!lm) { printk(KERN_ERR "Registered NULL Location Monitor resource\n"); continue; } @@ -1535,14 +1510,13 @@ struct vme_resource *vme_lm_request(struct vme_dev *vdev) } /* Check to see if we found a resource */ - if (allocated_lm == NULL) + if (!allocated_lm) goto err_lm; - resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL); - if (resource == NULL) { - printk(KERN_ERR "Unable to allocate resource structure\n"); + resource = kmalloc(sizeof(*resource), GFP_KERNEL); + if (!resource) goto err_alloc; - } + resource->type = VME_LM; resource->entry = &allocated_lm->list; @@ -1612,7 +1586,7 @@ int vme_lm_set(struct vme_resource *resource, unsigned long long lm_base, lm = list_entry(resource->entry, struct vme_lm_resource, list); - if (bridge->lm_set == NULL) { + if (!bridge->lm_set) { printk(KERN_ERR "vme_lm_set not supported\n"); return -EINVAL; } @@ -1648,7 +1622,7 @@ int vme_lm_get(struct vme_resource *resource, unsigned long long *lm_base, lm = list_entry(resource->entry, struct vme_lm_resource, list); - if (bridge->lm_get == NULL) { + if (!bridge->lm_get) { printk(KERN_ERR "vme_lm_get not supported\n"); return -EINVAL; } @@ -1685,7 +1659,7 @@ int vme_lm_attach(struct vme_resource *resource, int monitor, lm = list_entry(resource->entry, struct vme_lm_resource, list); - if (bridge->lm_attach == NULL) { + if (!bridge->lm_attach) { printk(KERN_ERR "vme_lm_attach not supported\n"); return -EINVAL; } @@ -1718,7 +1692,7 @@ int vme_lm_detach(struct vme_resource *resource, int monitor) lm = list_entry(resource->entry, struct vme_lm_resource, list); - if (bridge->lm_detach == NULL) { + if (!bridge->lm_detach) { printk(KERN_ERR "vme_lm_detach not supported\n"); return -EINVAL; } @@ -1780,12 +1754,12 @@ int vme_slot_num(struct vme_dev *vdev) struct vme_bridge *bridge; bridge = vdev->bridge; - if (bridge == NULL) { + if (!bridge) { printk(KERN_ERR "Can't find VME bus\n"); return -EINVAL; } - if (bridge->slot_get == NULL) { + if (!bridge->slot_get) { printk(KERN_WARNING "vme_slot_num not supported\n"); return -EINVAL; } @@ -1808,7 +1782,7 @@ int vme_bus_num(struct vme_dev *vdev) struct vme_bridge *bridge; bridge = vdev->bridge; - if (bridge == NULL) { + if (!bridge) { pr_err("Can't find VME bus\n"); return -EINVAL; } @@ -1888,7 +1862,7 @@ static int __vme_register_driver_bus(struct vme_driver *drv, struct vme_dev *tmp; for (i = 0; i < ndevs; i++) { - vdev = kzalloc(sizeof(struct vme_dev), GFP_KERNEL); + vdev = kzalloc(sizeof(*vdev), GFP_KERNEL); if (!vdev) { err = -ENOMEM; goto err_devalloc; @@ -2020,30 +1994,26 @@ static int vme_bus_match(struct device *dev, struct device_driver *drv) static int vme_bus_probe(struct device *dev) { - int retval = -ENODEV; struct vme_driver *driver; struct vme_dev *vdev = dev_to_vme_dev(dev); driver = dev->platform_data; + if (driver->probe) + return driver->probe(vdev); - if (driver->probe != NULL) - retval = driver->probe(vdev); - - return retval; + return -ENODEV; } static int vme_bus_remove(struct device *dev) { - int retval = -ENODEV; struct vme_driver *driver; struct vme_dev *vdev = dev_to_vme_dev(dev); driver = dev->platform_data; + if (driver->remove) + return driver->remove(vdev); - if (driver->remove != NULL) - retval = driver->remove(vdev); - - return retval; + return -ENODEV; } struct bus_type vme_bus_type = { diff --git a/drivers/w1/slaves/Kconfig b/drivers/w1/slaves/Kconfig index 3c945f9f5f0f..7931231d8e80 100644 --- a/drivers/w1/slaves/Kconfig +++ b/drivers/w1/slaves/Kconfig @@ -148,4 +148,19 @@ config W1_SLAVE_DS28E04 If you are unsure, say N. +config W1_SLAVE_DS28E17 + tristate "1-wire-to-I2C master bridge (DS28E17)" + select CRC16 + depends on I2C + help + Say Y here if you want to use the DS28E17 1-wire-to-I2C master bridge. + For each DS28E17 detected, a new I2C adapter is created within the + kernel. I2C devices on that bus can be configured to be used by the + kernel and userspace tools as on any other "native" I2C bus. + + This driver is also available as a module. If so, the module + will be called w1_ds28e17. + + If you are unsure, say N. + endmenu diff --git a/drivers/w1/slaves/Makefile b/drivers/w1/slaves/Makefile index 36b22fb2d3a1..855371a99e6a 100644 --- a/drivers/w1/slaves/Makefile +++ b/drivers/w1/slaves/Makefile @@ -17,3 +17,4 @@ obj-$(CONFIG_W1_SLAVE_DS2760) += w1_ds2760.o obj-$(CONFIG_W1_SLAVE_DS2780) += w1_ds2780.o obj-$(CONFIG_W1_SLAVE_DS2781) += w1_ds2781.o obj-$(CONFIG_W1_SLAVE_DS28E04) += w1_ds28e04.o +obj-$(CONFIG_W1_SLAVE_DS28E17) += w1_ds28e17.o diff --git a/drivers/w1/slaves/w1_ds28e17.c b/drivers/w1/slaves/w1_ds28e17.c new file mode 100644 index 000000000000..e78b63ea4daf --- /dev/null +++ b/drivers/w1/slaves/w1_ds28e17.c @@ -0,0 +1,771 @@ +/* + * w1_ds28e17.c - w1 family 19 (DS28E17) driver + * + * Copyright (c) 2016 Jan Kandziora <jjj@gmx.de> + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#include <linux/crc16.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/i2c.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/uaccess.h> + +#define CRC16_INIT 0 + +#include <linux/w1.h> + +#define W1_FAMILY_DS28E17 0x19 + +/* Module setup. */ +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Jan Kandziora <jjj@gmx.de>"); +MODULE_DESCRIPTION("w1 family 19 driver for DS28E17, 1-wire to I2C master bridge"); +MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_DS28E17)); + + +/* Default I2C speed to be set when a DS28E17 is detected. */ +static int i2c_speed = 100; +module_param_named(speed, i2c_speed, int, (S_IRUSR | S_IWUSR)); +MODULE_PARM_DESC(speed, "Default I2C speed to be set when a DS28E17 is detected"); + +/* Default I2C stretch value to be set when a DS28E17 is detected. */ +static char i2c_stretch = 1; +module_param_named(stretch, i2c_stretch, byte, (S_IRUSR | S_IWUSR)); +MODULE_PARM_DESC(stretch, "Default I2C stretch value to be set when a DS28E17 is detected"); + +/* DS28E17 device command codes. */ +#define W1_F19_WRITE_DATA_WITH_STOP 0x4B +#define W1_F19_WRITE_DATA_NO_STOP 0x5A +#define W1_F19_WRITE_DATA_ONLY 0x69 +#define W1_F19_WRITE_DATA_ONLY_WITH_STOP 0x78 +#define W1_F19_READ_DATA_WITH_STOP 0x87 +#define W1_F19_WRITE_READ_DATA_WITH_STOP 0x2D +#define W1_F19_WRITE_CONFIGURATION 0xD2 +#define W1_F19_READ_CONFIGURATION 0xE1 +#define W1_F19_ENABLE_SLEEP_MODE 0x1E +#define W1_F19_READ_DEVICE_REVISION 0xC4 + +/* DS28E17 status bits */ +#define W1_F19_STATUS_CRC 0x01 +#define W1_F19_STATUS_ADDRESS 0x02 +#define W1_F19_STATUS_START 0x08 + +/* + * Maximum number of I2C bytes to transfer within one CRC16 protected onewire + * command. + * */ +#define W1_F19_WRITE_DATA_LIMIT 255 + +/* Maximum number of I2C bytes to read with one onewire command. */ +#define W1_F19_READ_DATA_LIMIT 255 + +/* Constants for calculating the busy sleep. */ +#define W1_F19_BUSY_TIMEBASES { 90, 23, 10 } +#define W1_F19_BUSY_GRATUITY 1000 + +/* Number of checks for the busy flag before timeout. */ +#define W1_F19_BUSY_CHECKS 1000 + + +/* Slave specific data. */ +struct w1_f19_data { + u8 speed; + u8 stretch; + struct i2c_adapter adapter; +}; + + +/* Wait a while until the busy flag clears. */ +static int w1_f19_i2c_busy_wait(struct w1_slave *sl, size_t count) +{ + const unsigned long timebases[3] = W1_F19_BUSY_TIMEBASES; + struct w1_f19_data *data = sl->family_data; + unsigned int checks; + + /* Check the busy flag first in any case.*/ + if (w1_touch_bit(sl->master, 1) == 0) + return 0; + + /* + * Do a generously long sleep in the beginning, + * as we have to wait at least this time for all + * the I2C bytes at the given speed to be transferred. + */ + usleep_range(timebases[data->speed] * (data->stretch) * count, + timebases[data->speed] * (data->stretch) * count + + W1_F19_BUSY_GRATUITY); + + /* Now continusly check the busy flag sent by the DS28E17. */ + checks = W1_F19_BUSY_CHECKS; + while ((checks--) > 0) { + /* Return success if the busy flag is cleared. */ + if (w1_touch_bit(sl->master, 1) == 0) + return 0; + + /* Wait one non-streched byte timeslot. */ + udelay(timebases[data->speed]); + } + + /* Timeout. */ + dev_warn(&sl->dev, "busy timeout\n"); + return -ETIMEDOUT; +} + + +/* Utility function: result. */ +static size_t w1_f19_error(struct w1_slave *sl, u8 w1_buf[]) +{ + /* Warnings. */ + if (w1_buf[0] & W1_F19_STATUS_CRC) + dev_warn(&sl->dev, "crc16 mismatch\n"); + if (w1_buf[0] & W1_F19_STATUS_ADDRESS) + dev_warn(&sl->dev, "i2c device not responding\n"); + if ((w1_buf[0] & (W1_F19_STATUS_CRC | W1_F19_STATUS_ADDRESS)) == 0 + && w1_buf[1] != 0) { + dev_warn(&sl->dev, "i2c short write, %d bytes not acknowledged\n", + w1_buf[1]); + } + + /* Check error conditions. */ + if (w1_buf[0] & W1_F19_STATUS_ADDRESS) + return -ENXIO; + if (w1_buf[0] & W1_F19_STATUS_START) + return -EAGAIN; + if (w1_buf[0] != 0 || w1_buf[1] != 0) + return -EIO; + + /* All ok. */ + return 0; +} + + +/* Utility function: write data to I2C slave, single chunk. */ +static int __w1_f19_i2c_write(struct w1_slave *sl, + const u8 *command, size_t command_count, + const u8 *buffer, size_t count) +{ + u16 crc; + int error; + u8 w1_buf[2]; + + /* Send command and I2C data to DS28E17. */ + crc = crc16(CRC16_INIT, command, command_count); + w1_write_block(sl->master, command, command_count); + + w1_buf[0] = count; + crc = crc16(crc, w1_buf, 1); + w1_write_8(sl->master, w1_buf[0]); + + crc = crc16(crc, buffer, count); + w1_write_block(sl->master, buffer, count); + + w1_buf[0] = ~(crc & 0xFF); + w1_buf[1] = ~((crc >> 8) & 0xFF); + w1_write_block(sl->master, w1_buf, 2); + + /* Wait until busy flag clears (or timeout). */ + if (w1_f19_i2c_busy_wait(sl, count + 1) < 0) + return -ETIMEDOUT; + + /* Read status from DS28E17. */ + w1_read_block(sl->master, w1_buf, 2); + + /* Check error conditions. */ + error = w1_f19_error(sl, w1_buf); + if (error < 0) + return error; + + /* Return number of bytes written. */ + return count; +} + + +/* Write data to I2C slave. */ +static int w1_f19_i2c_write(struct w1_slave *sl, u16 i2c_address, + const u8 *buffer, size_t count, bool stop) +{ + int result; + int remaining = count; + const u8 *p; + u8 command[2]; + + /* Check input. */ + if (count == 0) + return -EOPNOTSUPP; + + /* Check whether we need multiple commands. */ + if (count <= W1_F19_WRITE_DATA_LIMIT) { + /* + * Small data amount. Data can be sent with + * a single onewire command. + */ + + /* Send all data to DS28E17. */ + command[0] = (stop ? W1_F19_WRITE_DATA_WITH_STOP + : W1_F19_WRITE_DATA_NO_STOP); + command[1] = i2c_address << 1; + result = __w1_f19_i2c_write(sl, command, 2, buffer, count); + } else { + /* Large data amount. Data has to be sent in multiple chunks. */ + + /* Send first chunk to DS28E17. */ + p = buffer; + command[0] = W1_F19_WRITE_DATA_NO_STOP; + command[1] = i2c_address << 1; + result = __w1_f19_i2c_write(sl, command, 2, p, + W1_F19_WRITE_DATA_LIMIT); + if (result < 0) + return result; + + /* Resume to same DS28E17. */ + if (w1_reset_resume_command(sl->master)) + return -EIO; + + /* Next data chunk. */ + p += W1_F19_WRITE_DATA_LIMIT; + remaining -= W1_F19_WRITE_DATA_LIMIT; + + while (remaining > W1_F19_WRITE_DATA_LIMIT) { + /* Send intermediate chunk to DS28E17. */ + command[0] = W1_F19_WRITE_DATA_ONLY; + result = __w1_f19_i2c_write(sl, command, 1, p, + W1_F19_WRITE_DATA_LIMIT); + if (result < 0) + return result; + + /* Resume to same DS28E17. */ + if (w1_reset_resume_command(sl->master)) + return -EIO; + + /* Next data chunk. */ + p += W1_F19_WRITE_DATA_LIMIT; + remaining -= W1_F19_WRITE_DATA_LIMIT; + } + + /* Send final chunk to DS28E17. */ + command[0] = (stop ? W1_F19_WRITE_DATA_ONLY_WITH_STOP + : W1_F19_WRITE_DATA_ONLY); + result = __w1_f19_i2c_write(sl, command, 1, p, remaining); + } + + return result; +} + + +/* Read data from I2C slave. */ +static int w1_f19_i2c_read(struct w1_slave *sl, u16 i2c_address, + u8 *buffer, size_t count) +{ + u16 crc; + int error; + u8 w1_buf[5]; + + /* Check input. */ + if (count == 0) + return -EOPNOTSUPP; + + /* Send command to DS28E17. */ + w1_buf[0] = W1_F19_READ_DATA_WITH_STOP; + w1_buf[1] = i2c_address << 1 | 0x01; + w1_buf[2] = count; + crc = crc16(CRC16_INIT, w1_buf, 3); + w1_buf[3] = ~(crc & 0xFF); + w1_buf[4] = ~((crc >> 8) & 0xFF); + w1_write_block(sl->master, w1_buf, 5); + + /* Wait until busy flag clears (or timeout). */ + if (w1_f19_i2c_busy_wait(sl, count + 1) < 0) + return -ETIMEDOUT; + + /* Read status from DS28E17. */ + w1_buf[0] = w1_read_8(sl->master); + w1_buf[1] = 0; + + /* Check error conditions. */ + error = w1_f19_error(sl, w1_buf); + if (error < 0) + return error; + + /* Read received I2C data from DS28E17. */ + return w1_read_block(sl->master, buffer, count); +} + + +/* Write to, then read data from I2C slave. */ +static int w1_f19_i2c_write_read(struct w1_slave *sl, u16 i2c_address, + const u8 *wbuffer, size_t wcount, u8 *rbuffer, size_t rcount) +{ + u16 crc; + int error; + u8 w1_buf[3]; + + /* Check input. */ + if (wcount == 0 || rcount == 0) + return -EOPNOTSUPP; + + /* Send command and I2C data to DS28E17. */ + w1_buf[0] = W1_F19_WRITE_READ_DATA_WITH_STOP; + w1_buf[1] = i2c_address << 1; + w1_buf[2] = wcount; + crc = crc16(CRC16_INIT, w1_buf, 3); + w1_write_block(sl->master, w1_buf, 3); + + crc = crc16(crc, wbuffer, wcount); + w1_write_block(sl->master, wbuffer, wcount); + + w1_buf[0] = rcount; + crc = crc16(crc, w1_buf, 1); + w1_buf[1] = ~(crc & 0xFF); + w1_buf[2] = ~((crc >> 8) & 0xFF); + w1_write_block(sl->master, w1_buf, 3); + + /* Wait until busy flag clears (or timeout). */ + if (w1_f19_i2c_busy_wait(sl, wcount + rcount + 2) < 0) + return -ETIMEDOUT; + + /* Read status from DS28E17. */ + w1_read_block(sl->master, w1_buf, 2); + + /* Check error conditions. */ + error = w1_f19_error(sl, w1_buf); + if (error < 0) + return error; + + /* Read received I2C data from DS28E17. */ + return w1_read_block(sl->master, rbuffer, rcount); +} + + +/* Do an I2C master transfer. */ +static int w1_f19_i2c_master_transfer(struct i2c_adapter *adapter, + struct i2c_msg *msgs, int num) +{ + struct w1_slave *sl = (struct w1_slave *) adapter->algo_data; + int i = 0; + int result = 0; + + /* Start onewire transaction. */ + mutex_lock(&sl->master->bus_mutex); + + /* Select DS28E17. */ + if (w1_reset_select_slave(sl)) { + i = -EIO; + goto error; + } + + /* Loop while there are still messages to transfer. */ + while (i < num) { + /* + * Check for special case: Small write followed + * by read to same I2C device. + */ + if (i < (num-1) + && msgs[i].addr == msgs[i+1].addr + && !(msgs[i].flags & I2C_M_RD) + && (msgs[i+1].flags & I2C_M_RD) + && (msgs[i].len <= W1_F19_WRITE_DATA_LIMIT)) { + /* + * The DS28E17 has a combined transfer + * for small write+read. + */ + result = w1_f19_i2c_write_read(sl, msgs[i].addr, + msgs[i].buf, msgs[i].len, + msgs[i+1].buf, msgs[i+1].len); + if (result < 0) { + i = result; + goto error; + } + + /* + * Check if we should interpret the read data + * as a length byte. The DS28E17 unfortunately + * has no read without stop, so we can just do + * another simple read in that case. + */ + if (msgs[i+1].flags & I2C_M_RECV_LEN) { + result = w1_f19_i2c_read(sl, msgs[i+1].addr, + &(msgs[i+1].buf[1]), msgs[i+1].buf[0]); + if (result < 0) { + i = result; + goto error; + } + } + + /* Eat up read message, too. */ + i++; + } else if (msgs[i].flags & I2C_M_RD) { + /* Read transfer. */ + result = w1_f19_i2c_read(sl, msgs[i].addr, + msgs[i].buf, msgs[i].len); + if (result < 0) { + i = result; + goto error; + } + + /* + * Check if we should interpret the read data + * as a length byte. The DS28E17 unfortunately + * has no read without stop, so we can just do + * another simple read in that case. + */ + if (msgs[i].flags & I2C_M_RECV_LEN) { + result = w1_f19_i2c_read(sl, + msgs[i].addr, + &(msgs[i].buf[1]), + msgs[i].buf[0]); + if (result < 0) { + i = result; + goto error; + } + } + } else { + /* + * Write transfer. + * Stop condition only for last + * transfer. + */ + result = w1_f19_i2c_write(sl, + msgs[i].addr, + msgs[i].buf, + msgs[i].len, + i == (num-1)); + if (result < 0) { + i = result; + goto error; + } + } + + /* Next message. */ + i++; + + /* Are there still messages to send/receive? */ + if (i < num) { + /* Yes. Resume to same DS28E17. */ + if (w1_reset_resume_command(sl->master)) { + i = -EIO; + goto error; + } + } + } + +error: + /* End onewire transaction. */ + mutex_unlock(&sl->master->bus_mutex); + + /* Return number of messages processed or error. */ + return i; +} + + +/* Get I2C adapter functionality. */ +static u32 w1_f19_i2c_functionality(struct i2c_adapter *adapter) +{ + /* + * Plain I2C functions only. + * SMBus is emulated by the kernel's I2C layer. + * No "I2C_FUNC_SMBUS_QUICK" + * No "I2C_FUNC_SMBUS_READ_BLOCK_DATA" + * No "I2C_FUNC_SMBUS_BLOCK_PROC_CALL" + */ + return I2C_FUNC_I2C | + I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_PROC_CALL | + I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | + I2C_FUNC_SMBUS_I2C_BLOCK | + I2C_FUNC_SMBUS_PEC; +} + + +/* I2C adapter quirks. */ +static const struct i2c_adapter_quirks w1_f19_i2c_adapter_quirks = { + .max_read_len = W1_F19_READ_DATA_LIMIT, +}; + +/* I2C algorithm. */ +static const struct i2c_algorithm w1_f19_i2c_algorithm = { + .master_xfer = w1_f19_i2c_master_transfer, + .functionality = w1_f19_i2c_functionality, +}; + + +/* Read I2C speed from DS28E17. */ +static int w1_f19_get_i2c_speed(struct w1_slave *sl) +{ + struct w1_f19_data *data = sl->family_data; + int result = -EIO; + + /* Start onewire transaction. */ + mutex_lock(&sl->master->bus_mutex); + + /* Select slave. */ + if (w1_reset_select_slave(sl)) + goto error; + + /* Read slave configuration byte. */ + w1_write_8(sl->master, W1_F19_READ_CONFIGURATION); + result = w1_read_8(sl->master); + if (result < 0 || result > 2) { + result = -EIO; + goto error; + } + + /* Update speed in slave specific data. */ + data->speed = result; + +error: + /* End onewire transaction. */ + mutex_unlock(&sl->master->bus_mutex); + + return result; +} + + +/* Set I2C speed on DS28E17. */ +static int __w1_f19_set_i2c_speed(struct w1_slave *sl, u8 speed) +{ + struct w1_f19_data *data = sl->family_data; + const int i2c_speeds[3] = { 100, 400, 900 }; + u8 w1_buf[2]; + + /* Select slave. */ + if (w1_reset_select_slave(sl)) + return -EIO; + + w1_buf[0] = W1_F19_WRITE_CONFIGURATION; + w1_buf[1] = speed; + w1_write_block(sl->master, w1_buf, 2); + + /* Update speed in slave specific data. */ + data->speed = speed; + + dev_info(&sl->dev, "i2c speed set to %d kBaud\n", i2c_speeds[speed]); + + return 0; +} + +static int w1_f19_set_i2c_speed(struct w1_slave *sl, u8 speed) +{ + int result; + + /* Start onewire transaction. */ + mutex_lock(&sl->master->bus_mutex); + + /* Set I2C speed on DS28E17. */ + result = __w1_f19_set_i2c_speed(sl, speed); + + /* End onewire transaction. */ + mutex_unlock(&sl->master->bus_mutex); + + return result; +} + + +/* Sysfs attributes. */ + +/* I2C speed attribute for a single chip. */ +static ssize_t speed_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct w1_slave *sl = dev_to_w1_slave(dev); + int result; + + /* Read current speed from slave. Updates data->speed. */ + result = w1_f19_get_i2c_speed(sl); + if (result < 0) + return result; + + /* Return current speed value. */ + return sprintf(buf, "%d\n", result); +} + +static ssize_t speed_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct w1_slave *sl = dev_to_w1_slave(dev); + int error; + + /* Valid values are: "100", "400", "900" */ + if (count < 3 || count > 4 || !buf) + return -EINVAL; + if (count == 4 && buf[3] != '\n') + return -EINVAL; + if (buf[1] != '0' || buf[2] != '0') + return -EINVAL; + + /* Set speed on slave. */ + switch (buf[0]) { + case '1': + error = w1_f19_set_i2c_speed(sl, 0); + break; + case '4': + error = w1_f19_set_i2c_speed(sl, 1); + break; + case '9': + error = w1_f19_set_i2c_speed(sl, 2); + break; + default: + return -EINVAL; + } + + if (error < 0) + return error; + + /* Return bytes written. */ + return count; +} + +static DEVICE_ATTR_RW(speed); + + +/* Busy stretch attribute for a single chip. */ +static ssize_t stretch_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct w1_slave *sl = dev_to_w1_slave(dev); + struct w1_f19_data *data = sl->family_data; + + /* Return current stretch value. */ + return sprintf(buf, "%d\n", data->stretch); +} + +static ssize_t stretch_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct w1_slave *sl = dev_to_w1_slave(dev); + struct w1_f19_data *data = sl->family_data; + + /* Valid values are '1' to '9' */ + if (count < 1 || count > 2 || !buf) + return -EINVAL; + if (count == 2 && buf[1] != '\n') + return -EINVAL; + if (buf[0] < '1' || buf[0] > '9') + return -EINVAL; + + /* Set busy stretch value. */ + data->stretch = buf[0] & 0x0F; + + /* Return bytes written. */ + return count; +} + +static DEVICE_ATTR_RW(stretch); + + +/* All attributes. */ +static struct attribute *w1_f19_attrs[] = { + &dev_attr_speed.attr, + &dev_attr_stretch.attr, + NULL, +}; + +static const struct attribute_group w1_f19_group = { + .attrs = w1_f19_attrs, +}; + +static const struct attribute_group *w1_f19_groups[] = { + &w1_f19_group, + NULL, +}; + + +/* Slave add and remove functions. */ +static int w1_f19_add_slave(struct w1_slave *sl) +{ + struct w1_f19_data *data = NULL; + + /* Allocate memory for slave specific data. */ + data = devm_kzalloc(&sl->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + sl->family_data = data; + + /* Setup default I2C speed on slave. */ + switch (i2c_speed) { + case 100: + __w1_f19_set_i2c_speed(sl, 0); + break; + case 400: + __w1_f19_set_i2c_speed(sl, 1); + break; + case 900: + __w1_f19_set_i2c_speed(sl, 2); + break; + default: + /* + * A i2c_speed module parameter of anything else + * than 100, 400, 900 means not to touch the + * speed of the DS28E17. + * We assume 400kBaud, the power-on value. + */ + data->speed = 1; + } + + /* + * Setup default busy stretch + * configuration for the DS28E17. + */ + data->stretch = i2c_stretch; + + /* Setup I2C adapter. */ + data->adapter.owner = THIS_MODULE; + data->adapter.algo = &w1_f19_i2c_algorithm; + data->adapter.algo_data = sl; + strcpy(data->adapter.name, "w1-"); + strcat(data->adapter.name, sl->name); + data->adapter.dev.parent = &sl->dev; + data->adapter.quirks = &w1_f19_i2c_adapter_quirks; + + return i2c_add_adapter(&data->adapter); +} + +static void w1_f19_remove_slave(struct w1_slave *sl) +{ + struct w1_f19_data *family_data = sl->family_data; + + /* Delete I2C adapter. */ + i2c_del_adapter(&family_data->adapter); + + /* Free slave specific data. */ + devm_kfree(&sl->dev, family_data); + sl->family_data = NULL; +} + + +/* Declarations within the w1 subsystem. */ +static struct w1_family_ops w1_f19_fops = { + .add_slave = w1_f19_add_slave, + .remove_slave = w1_f19_remove_slave, + .groups = w1_f19_groups, +}; + +static struct w1_family w1_family_19 = { + .fid = W1_FAMILY_DS28E17, + .fops = &w1_f19_fops, +}; + + +/* Module init and remove functions. */ +static int __init w1_f19_init(void) +{ + return w1_register_family(&w1_family_19); +} + +static void __exit w1_f19_fini(void) +{ + w1_unregister_family(&w1_family_19); +} + +module_init(w1_f19_init); +module_exit(w1_f19_fini); + diff --git a/drivers/w1/w1_io.c b/drivers/w1/w1_io.c index d191e1f80579..075d120e7b88 100644 --- a/drivers/w1/w1_io.c +++ b/drivers/w1/w1_io.c @@ -58,7 +58,7 @@ static u8 w1_read_bit(struct w1_master *dev); * @dev: the master device * @bit: 0 - write a 0, 1 - write a 0 read the level */ -static u8 w1_touch_bit(struct w1_master *dev, int bit) +u8 w1_touch_bit(struct w1_master *dev, int bit) { if (dev->bus_master->touch_bit) return dev->bus_master->touch_bit(dev->bus_master->data, bit); @@ -69,6 +69,7 @@ static u8 w1_touch_bit(struct w1_master *dev, int bit) return 0; } } +EXPORT_SYMBOL_GPL(w1_touch_bit); /** * w1_write_bit() - Generates a write-0 or write-1 cycle. |