From a056ab8c7a00a0ffc52e9573bf01257004c2d08c Mon Sep 17 00:00:00 2001 From: Carlos Chinea Date: Fri, 16 Apr 2010 19:01:02 +0300 Subject: HSI: hsi: Introducing HSI framework Adds HSI framework in to the linux kernel. High Speed Synchronous Serial Interface (HSI) is a serial interface mainly used for connecting application engines (APE) with cellular modem engines (CMT) in cellular handsets. HSI provides multiplexing for up to 16 logical channels, low-latency and full duplex communication. Signed-off-by: Carlos Chinea Acked-by: Linus Walleij --- drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/hsi/Kconfig | 17 ++ drivers/hsi/Makefile | 5 + drivers/hsi/hsi.c | 494 ++++++++++++++++++++++++++++++++++++++++++++ drivers/hsi/hsi_boardinfo.c | 62 ++++++ drivers/hsi/hsi_core.h | 35 ++++ 7 files changed, 616 insertions(+) create mode 100644 drivers/hsi/Kconfig create mode 100644 drivers/hsi/Makefile create mode 100644 drivers/hsi/hsi.c create mode 100644 drivers/hsi/hsi_boardinfo.c create mode 100644 drivers/hsi/hsi_core.h (limited to 'drivers') diff --git a/drivers/Kconfig b/drivers/Kconfig index b5e6f243f749..52895081db0b 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -52,6 +52,8 @@ source "drivers/i2c/Kconfig" source "drivers/spi/Kconfig" +source "drivers/hsi/Kconfig" + source "drivers/pps/Kconfig" source "drivers/ptp/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 1b3142127bf5..91077ac6b156 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -53,6 +53,7 @@ obj-$(CONFIG_ATA) += ata/ obj-$(CONFIG_TARGET_CORE) += target/ obj-$(CONFIG_MTD) += mtd/ obj-$(CONFIG_SPI) += spi/ +obj-y += hsi/ obj-y += net/ obj-$(CONFIG_ATM) += atm/ obj-$(CONFIG_FUSION) += message/ diff --git a/drivers/hsi/Kconfig b/drivers/hsi/Kconfig new file mode 100644 index 000000000000..937062e8bcd0 --- /dev/null +++ b/drivers/hsi/Kconfig @@ -0,0 +1,17 @@ +# +# HSI driver configuration +# +menuconfig HSI + tristate "HSI support" + ---help--- + The "High speed synchronous Serial Interface" is + synchronous serial interface used mainly to connect + application engines and cellular modems. + +if HSI + +config HSI_BOARDINFO + bool + default y + +endif # HSI diff --git a/drivers/hsi/Makefile b/drivers/hsi/Makefile new file mode 100644 index 000000000000..ed94a3a334a4 --- /dev/null +++ b/drivers/hsi/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for HSI +# +obj-$(CONFIG_HSI_BOARDINFO) += hsi_boardinfo.o +obj-$(CONFIG_HSI) += hsi.o diff --git a/drivers/hsi/hsi.c b/drivers/hsi/hsi.c new file mode 100644 index 000000000000..4e2d79b79334 --- /dev/null +++ b/drivers/hsi/hsi.c @@ -0,0 +1,494 @@ +/* + * HSI core. + * + * Copyright (C) 2010 Nokia Corporation. All rights reserved. + * + * Contact: Carlos Chinea + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "hsi_core.h" + +static struct device_type hsi_ctrl = { + .name = "hsi_controller", +}; + +static struct device_type hsi_cl = { + .name = "hsi_client", +}; + +static struct device_type hsi_port = { + .name = "hsi_port", +}; + +static ssize_t modalias_show(struct device *dev, + struct device_attribute *a __maybe_unused, char *buf) +{ + return sprintf(buf, "hsi:%s\n", dev_name(dev)); +} + +static struct device_attribute hsi_bus_dev_attrs[] = { + __ATTR_RO(modalias), + __ATTR_NULL, +}; + +static int hsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + if (dev->type == &hsi_cl) + add_uevent_var(env, "MODALIAS=hsi:%s", dev_name(dev)); + + return 0; +} + +static int hsi_bus_match(struct device *dev, struct device_driver *driver) +{ + return strcmp(dev_name(dev), driver->name) == 0; +} + +static struct bus_type hsi_bus_type = { + .name = "hsi", + .dev_attrs = hsi_bus_dev_attrs, + .match = hsi_bus_match, + .uevent = hsi_bus_uevent, +}; + +static void hsi_client_release(struct device *dev) +{ + kfree(to_hsi_client(dev)); +} + +static void hsi_new_client(struct hsi_port *port, struct hsi_board_info *info) +{ + struct hsi_client *cl; + unsigned long flags; + + cl = kzalloc(sizeof(*cl), GFP_KERNEL); + if (!cl) + return; + cl->device.type = &hsi_cl; + cl->tx_cfg = info->tx_cfg; + cl->rx_cfg = info->rx_cfg; + cl->device.bus = &hsi_bus_type; + cl->device.parent = &port->device; + cl->device.release = hsi_client_release; + dev_set_name(&cl->device, info->name); + cl->device.platform_data = info->platform_data; + spin_lock_irqsave(&port->clock, flags); + list_add_tail(&cl->link, &port->clients); + spin_unlock_irqrestore(&port->clock, flags); + if (info->archdata) + cl->device.archdata = *info->archdata; + if (device_register(&cl->device) < 0) { + pr_err("hsi: failed to register client: %s\n", info->name); + kfree(cl); + } +} + +static void hsi_scan_board_info(struct hsi_controller *hsi) +{ + struct hsi_cl_info *cl_info; + struct hsi_port *p; + + list_for_each_entry(cl_info, &hsi_board_list, list) + if (cl_info->info.hsi_id == hsi->id) { + p = hsi_find_port_num(hsi, cl_info->info.port); + if (!p) + continue; + hsi_new_client(p, &cl_info->info); + } +} + +static int hsi_remove_client(struct device *dev, void *data __maybe_unused) +{ + struct hsi_client *cl = to_hsi_client(dev); + struct hsi_port *port = to_hsi_port(dev->parent); + unsigned long flags; + + spin_lock_irqsave(&port->clock, flags); + list_del(&cl->link); + spin_unlock_irqrestore(&port->clock, flags); + device_unregister(dev); + + return 0; +} + +static int hsi_remove_port(struct device *dev, void *data __maybe_unused) +{ + device_for_each_child(dev, NULL, hsi_remove_client); + device_unregister(dev); + + return 0; +} + +static void hsi_controller_release(struct device *dev __maybe_unused) +{ +} + +static void hsi_port_release(struct device *dev __maybe_unused) +{ +} + +/** + * hsi_unregister_controller - Unregister an HSI controller + * @hsi: The HSI controller to register + */ +void hsi_unregister_controller(struct hsi_controller *hsi) +{ + device_for_each_child(&hsi->device, NULL, hsi_remove_port); + device_unregister(&hsi->device); +} +EXPORT_SYMBOL_GPL(hsi_unregister_controller); + +/** + * hsi_register_controller - Register an HSI controller and its ports + * @hsi: The HSI controller to register + * + * Returns -errno on failure, 0 on success. + */ +int hsi_register_controller(struct hsi_controller *hsi) +{ + unsigned int i; + int err; + + hsi->device.type = &hsi_ctrl; + hsi->device.bus = &hsi_bus_type; + hsi->device.release = hsi_controller_release; + err = device_register(&hsi->device); + if (err < 0) + return err; + for (i = 0; i < hsi->num_ports; i++) { + hsi->port[i].device.parent = &hsi->device; + hsi->port[i].device.bus = &hsi_bus_type; + hsi->port[i].device.release = hsi_port_release; + hsi->port[i].device.type = &hsi_port; + INIT_LIST_HEAD(&hsi->port[i].clients); + spin_lock_init(&hsi->port[i].clock); + err = device_register(&hsi->port[i].device); + if (err < 0) + goto out; + } + /* Populate HSI bus with HSI clients */ + hsi_scan_board_info(hsi); + + return 0; +out: + hsi_unregister_controller(hsi); + + return err; +} +EXPORT_SYMBOL_GPL(hsi_register_controller); + +/** + * hsi_register_client_driver - Register an HSI client to the HSI bus + * @drv: HSI client driver to register + * + * Returns -errno on failure, 0 on success. + */ +int hsi_register_client_driver(struct hsi_client_driver *drv) +{ + drv->driver.bus = &hsi_bus_type; + + return driver_register(&drv->driver); +} +EXPORT_SYMBOL_GPL(hsi_register_client_driver); + +static inline int hsi_dummy_msg(struct hsi_msg *msg __maybe_unused) +{ + return 0; +} + +static inline int hsi_dummy_cl(struct hsi_client *cl __maybe_unused) +{ + return 0; +} + +/** + * hsi_alloc_controller - Allocate an HSI controller and its ports + * @n_ports: Number of ports on the HSI controller + * @flags: Kernel allocation flags + * + * Return NULL on failure or a pointer to an hsi_controller on success. + */ +struct hsi_controller *hsi_alloc_controller(unsigned int n_ports, gfp_t flags) +{ + struct hsi_controller *hsi; + struct hsi_port *port; + unsigned int i; + + if (!n_ports) + return NULL; + + port = kzalloc(sizeof(*port)*n_ports, flags); + if (!port) + return NULL; + hsi = kzalloc(sizeof(*hsi), flags); + if (!hsi) + goto out; + for (i = 0; i < n_ports; i++) { + dev_set_name(&port[i].device, "port%d", i); + port[i].num = i; + port[i].async = hsi_dummy_msg; + port[i].setup = hsi_dummy_cl; + port[i].flush = hsi_dummy_cl; + port[i].start_tx = hsi_dummy_cl; + port[i].stop_tx = hsi_dummy_cl; + port[i].release = hsi_dummy_cl; + mutex_init(&port[i].lock); + } + hsi->num_ports = n_ports; + hsi->port = port; + + return hsi; +out: + kfree(port); + + return NULL; +} +EXPORT_SYMBOL_GPL(hsi_alloc_controller); + +/** + * hsi_free_controller - Free an HSI controller + * @hsi: Pointer to HSI controller + */ +void hsi_free_controller(struct hsi_controller *hsi) +{ + if (!hsi) + return; + + kfree(hsi->port); + kfree(hsi); +} +EXPORT_SYMBOL_GPL(hsi_free_controller); + +/** + * hsi_free_msg - Free an HSI message + * @msg: Pointer to the HSI message + * + * Client is responsible to free the buffers pointed by the scatterlists. + */ +void hsi_free_msg(struct hsi_msg *msg) +{ + if (!msg) + return; + sg_free_table(&msg->sgt); + kfree(msg); +} +EXPORT_SYMBOL_GPL(hsi_free_msg); + +/** + * hsi_alloc_msg - Allocate an HSI message + * @nents: Number of memory entries + * @flags: Kernel allocation flags + * + * nents can be 0. This mainly makes sense for read transfer. + * In that case, HSI drivers will call the complete callback when + * there is data to be read without consuming it. + * + * Return NULL on failure or a pointer to an hsi_msg on success. + */ +struct hsi_msg *hsi_alloc_msg(unsigned int nents, gfp_t flags) +{ + struct hsi_msg *msg; + int err; + + msg = kzalloc(sizeof(*msg), flags); + if (!msg) + return NULL; + + if (!nents) + return msg; + + err = sg_alloc_table(&msg->sgt, nents, flags); + if (unlikely(err)) { + kfree(msg); + msg = NULL; + } + + return msg; +} +EXPORT_SYMBOL_GPL(hsi_alloc_msg); + +/** + * hsi_async - Submit an HSI transfer to the controller + * @cl: HSI client sending the transfer + * @msg: The HSI transfer passed to controller + * + * The HSI message must have the channel, ttype, complete and destructor + * fields set beforehand. If nents > 0 then the client has to initialize + * also the scatterlists to point to the buffers to write to or read from. + * + * HSI controllers relay on pre-allocated buffers from their clients and they + * do not allocate buffers on their own. + * + * Once the HSI message transfer finishes, the HSI controller calls the + * complete callback with the status and actual_len fields of the HSI message + * updated. The complete callback can be called before returning from + * hsi_async. + * + * Returns -errno on failure or 0 on success + */ +int hsi_async(struct hsi_client *cl, struct hsi_msg *msg) +{ + struct hsi_port *port = hsi_get_port(cl); + + if (!hsi_port_claimed(cl)) + return -EACCES; + + WARN_ON_ONCE(!msg->destructor || !msg->complete); + msg->cl = cl; + + return port->async(msg); +} +EXPORT_SYMBOL_GPL(hsi_async); + +/** + * hsi_claim_port - Claim the HSI client's port + * @cl: HSI client that wants to claim its port + * @share: Flag to indicate if the client wants to share the port or not. + * + * Returns -errno on failure, 0 on success. + */ +int hsi_claim_port(struct hsi_client *cl, unsigned int share) +{ + struct hsi_port *port = hsi_get_port(cl); + int err = 0; + + mutex_lock(&port->lock); + if ((port->claimed) && (!port->shared || !share)) { + err = -EBUSY; + goto out; + } + if (!try_module_get(to_hsi_controller(port->device.parent)->owner)) { + err = -ENODEV; + goto out; + } + port->claimed++; + port->shared = !!share; + cl->pclaimed = 1; +out: + mutex_unlock(&port->lock); + + return err; +} +EXPORT_SYMBOL_GPL(hsi_claim_port); + +/** + * hsi_release_port - Release the HSI client's port + * @cl: HSI client which previously claimed its port + */ +void hsi_release_port(struct hsi_client *cl) +{ + struct hsi_port *port = hsi_get_port(cl); + + mutex_lock(&port->lock); + /* Allow HW driver to do some cleanup */ + port->release(cl); + if (cl->pclaimed) + port->claimed--; + BUG_ON(port->claimed < 0); + cl->pclaimed = 0; + if (!port->claimed) + port->shared = 0; + module_put(to_hsi_controller(port->device.parent)->owner); + mutex_unlock(&port->lock); +} +EXPORT_SYMBOL_GPL(hsi_release_port); + +static int hsi_start_rx(struct hsi_client *cl, void *data __maybe_unused) +{ + if (cl->hsi_start_rx) + (*cl->hsi_start_rx)(cl); + + return 0; +} + +static int hsi_stop_rx(struct hsi_client *cl, void *data __maybe_unused) +{ + if (cl->hsi_stop_rx) + (*cl->hsi_stop_rx)(cl); + + return 0; +} + +static int hsi_port_for_each_client(struct hsi_port *port, void *data, + int (*fn)(struct hsi_client *cl, void *data)) +{ + struct hsi_client *cl; + + spin_lock(&port->clock); + list_for_each_entry(cl, &port->clients, link) { + spin_unlock(&port->clock); + (*fn)(cl, data); + spin_lock(&port->clock); + } + spin_unlock(&port->clock); + + return 0; +} + +/** + * hsi_event -Notifies clients about port events + * @port: Port where the event occurred + * @event: The event type + * + * Clients should not be concerned about wake line behavior. However, due + * to a race condition in HSI HW protocol, clients need to be notified + * about wake line changes, so they can implement a workaround for it. + * + * Events: + * HSI_EVENT_START_RX - Incoming wake line high + * HSI_EVENT_STOP_RX - Incoming wake line down + */ +void hsi_event(struct hsi_port *port, unsigned int event) +{ + int (*fn)(struct hsi_client *cl, void *data); + + switch (event) { + case HSI_EVENT_START_RX: + fn = hsi_start_rx; + break; + case HSI_EVENT_STOP_RX: + fn = hsi_stop_rx; + break; + default: + return; + } + hsi_port_for_each_client(port, NULL, fn); +} +EXPORT_SYMBOL_GPL(hsi_event); + +static int __init hsi_init(void) +{ + return bus_register(&hsi_bus_type); +} +postcore_initcall(hsi_init); + +static void __exit hsi_exit(void) +{ + bus_unregister(&hsi_bus_type); +} +module_exit(hsi_exit); + +MODULE_AUTHOR("Carlos Chinea "); +MODULE_DESCRIPTION("High-speed Synchronous Serial Interface (HSI) framework"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/hsi/hsi_boardinfo.c b/drivers/hsi/hsi_boardinfo.c new file mode 100644 index 000000000000..e56bc6da5f98 --- /dev/null +++ b/drivers/hsi/hsi_boardinfo.c @@ -0,0 +1,62 @@ +/* + * HSI clients registration interface + * + * Copyright (C) 2010 Nokia Corporation. All rights reserved. + * + * Contact: Carlos Chinea + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ +#include +#include +#include +#include "hsi_core.h" + +/* + * hsi_board_list is only used internally by the HSI framework. + * No one else is allowed to make use of it. + */ +LIST_HEAD(hsi_board_list); +EXPORT_SYMBOL_GPL(hsi_board_list); + +/** + * hsi_register_board_info - Register HSI clients information + * @info: Array of HSI clients on the board + * @len: Length of the array + * + * HSI clients are statically declared and registered on board files. + * + * HSI clients will be automatically registered to the HSI bus once the + * controller and the port where the clients wishes to attach are registered + * to it. + * + * Return -errno on failure, 0 on success. + */ +int __init hsi_register_board_info(struct hsi_board_info const *info, + unsigned int len) +{ + struct hsi_cl_info *cl_info; + + cl_info = kzalloc(sizeof(*cl_info) * len, GFP_KERNEL); + if (!cl_info) + return -ENOMEM; + + for (; len; len--, info++, cl_info++) { + cl_info->info = *info; + list_add_tail(&cl_info->list, &hsi_board_list); + } + + return 0; +} diff --git a/drivers/hsi/hsi_core.h b/drivers/hsi/hsi_core.h new file mode 100644 index 000000000000..ab5c2fb175fd --- /dev/null +++ b/drivers/hsi/hsi_core.h @@ -0,0 +1,35 @@ +/* + * HSI framework internal interfaces, + * + * Copyright (C) 2010 Nokia Corporation. All rights reserved. + * + * Contact: Carlos Chinea + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef __LINUX_HSI_CORE_H__ +#define __LINUX_HSI_CORE_H__ + +#include + +struct hsi_cl_info { + struct list_head list; + struct hsi_board_info info; +}; + +extern struct list_head hsi_board_list; + +#endif /* __LINUX_HSI_CORE_H__ */ -- cgit v1.2.3 From 4e69fc22753fcce1d9275b5517ef3646ffeffcf4 Mon Sep 17 00:00:00 2001 From: Andras Domokos Date: Thu, 30 Sep 2010 17:18:53 +0300 Subject: HSI: hsi_char: Add HSI char device driver Add HSI char device driver to the kernel. Signed-off-by: Andras Domokos Signed-off-by: Carlos Chinea --- drivers/hsi/clients/hsi_char.c | 802 +++++++++++++++++++++++++++++++++++++++++ include/linux/hsi/hsi_char.h | 63 ++++ 2 files changed, 865 insertions(+) create mode 100644 drivers/hsi/clients/hsi_char.c create mode 100644 include/linux/hsi/hsi_char.h (limited to 'drivers') diff --git a/drivers/hsi/clients/hsi_char.c b/drivers/hsi/clients/hsi_char.c new file mode 100644 index 000000000000..88a050df2389 --- /dev/null +++ b/drivers/hsi/clients/hsi_char.c @@ -0,0 +1,802 @@ +/* + * HSI character device driver, implements the character device + * interface. + * + * Copyright (C) 2010 Nokia Corporation. All rights reserved. + * + * Contact: Andras Domokos + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HSC_DEVS 16 /* Num of channels */ +#define HSC_MSGS 4 + +#define HSC_RXBREAK 0 + +#define HSC_ID_BITS 6 +#define HSC_PORT_ID_BITS 4 +#define HSC_ID_MASK 3 +#define HSC_PORT_ID_MASK 3 +#define HSC_CH_MASK 0xf + +/* + * We support up to 4 controllers that can have up to 4 + * ports, which should currently be more than enough. + */ +#define HSC_BASEMINOR(id, port_id) \ + ((((id) & HSC_ID_MASK) << HSC_ID_BITS) | \ + (((port_id) & HSC_PORT_ID_MASK) << HSC_PORT_ID_BITS)) + +enum { + HSC_CH_OPEN, + HSC_CH_READ, + HSC_CH_WRITE, + HSC_CH_WLINE, +}; + +enum { + HSC_RX, + HSC_TX, +}; + +struct hsc_client_data; +/** + * struct hsc_channel - hsi_char internal channel data + * @ch: channel number + * @flags: Keeps state of the channel (open/close, reading, writing) + * @free_msgs_list: List of free HSI messages/requests + * @rx_msgs_queue: List of pending RX requests + * @tx_msgs_queue: List of pending TX requests + * @lock: Serialize access to the lists + * @cl: reference to the associated hsi_client + * @cl_data: reference to the client data that this channels belongs to + * @rx_wait: RX requests wait queue + * @tx_wait: TX requests wait queue + */ +struct hsc_channel { + unsigned int ch; + unsigned long flags; + struct list_head free_msgs_list; + struct list_head rx_msgs_queue; + struct list_head tx_msgs_queue; + spinlock_t lock; + struct hsi_client *cl; + struct hsc_client_data *cl_data; + wait_queue_head_t rx_wait; + wait_queue_head_t tx_wait; +}; + +/** + * struct hsc_client_data - hsi_char internal client data + * @cdev: Characther device associated to the hsi_client + * @lock: Lock to serialize open/close access + * @flags: Keeps track of port state (rx hwbreak armed) + * @usecnt: Use count for claiming the HSI port (mutex protected) + * @cl: Referece to the HSI client + * @channels: Array of channels accessible by the client + */ +struct hsc_client_data { + struct cdev cdev; + struct mutex lock; + unsigned long flags; + unsigned int usecnt; + struct hsi_client *cl; + struct hsc_channel channels[HSC_DEVS]; +}; + +/* Stores the major number dynamically allocated for hsi_char */ +static unsigned int hsc_major; +/* Maximum buffer size that hsi_char will accept from userspace */ +static unsigned int max_data_size = 0x1000; +module_param(max_data_size, uint, S_IRUSR | S_IWUSR); +MODULE_PARM_DESC(max_data_size, "max read/write data size [4,8..65536] (^2)"); + +static void hsc_add_tail(struct hsc_channel *channel, struct hsi_msg *msg, + struct list_head *queue) +{ + unsigned long flags; + + spin_lock_irqsave(&channel->lock, flags); + list_add_tail(&msg->link, queue); + spin_unlock_irqrestore(&channel->lock, flags); +} + +static struct hsi_msg *hsc_get_first_msg(struct hsc_channel *channel, + struct list_head *queue) +{ + struct hsi_msg *msg = NULL; + unsigned long flags; + + spin_lock_irqsave(&channel->lock, flags); + + if (list_empty(queue)) + goto out; + + msg = list_first_entry(queue, struct hsi_msg, link); + list_del(&msg->link); +out: + spin_unlock_irqrestore(&channel->lock, flags); + + return msg; +} + +static inline void hsc_msg_free(struct hsi_msg *msg) +{ + kfree(sg_virt(msg->sgt.sgl)); + hsi_free_msg(msg); +} + +static void hsc_free_list(struct list_head *list) +{ + struct hsi_msg *msg, *tmp; + + list_for_each_entry_safe(msg, tmp, list, link) { + list_del(&msg->link); + hsc_msg_free(msg); + } +} + +static void hsc_reset_list(struct hsc_channel *channel, struct list_head *l) +{ + unsigned long flags; + LIST_HEAD(list); + + spin_lock_irqsave(&channel->lock, flags); + list_splice_init(l, &list); + spin_unlock_irqrestore(&channel->lock, flags); + + hsc_free_list(&list); +} + +static inline struct hsi_msg *hsc_msg_alloc(unsigned int alloc_size) +{ + struct hsi_msg *msg; + void *buf; + + msg = hsi_alloc_msg(1, GFP_KERNEL); + if (!msg) + goto out; + buf = kmalloc(alloc_size, GFP_KERNEL); + if (!buf) { + hsi_free_msg(msg); + goto out; + } + sg_init_one(msg->sgt.sgl, buf, alloc_size); + /* Ignore false positive, due to sg pointer handling */ + kmemleak_ignore(buf); + + return msg; +out: + return NULL; +} + +static inline int hsc_msgs_alloc(struct hsc_channel *channel) +{ + struct hsi_msg *msg; + int i; + + for (i = 0; i < HSC_MSGS; i++) { + msg = hsc_msg_alloc(max_data_size); + if (!msg) + goto out; + msg->channel = channel->ch; + list_add_tail(&msg->link, &channel->free_msgs_list); + } + + return 0; +out: + hsc_free_list(&channel->free_msgs_list); + + return -ENOMEM; +} + +static inline unsigned int hsc_msg_len_get(struct hsi_msg *msg) +{ + return msg->sgt.sgl->length; +} + +static inline void hsc_msg_len_set(struct hsi_msg *msg, unsigned int len) +{ + msg->sgt.sgl->length = len; +} + +static void hsc_rx_completed(struct hsi_msg *msg) +{ + struct hsc_client_data *cl_data = hsi_client_drvdata(msg->cl); + struct hsc_channel *channel = cl_data->channels + msg->channel; + + if (test_bit(HSC_CH_READ, &channel->flags)) { + hsc_add_tail(channel, msg, &channel->rx_msgs_queue); + wake_up(&channel->rx_wait); + } else { + hsc_add_tail(channel, msg, &channel->free_msgs_list); + } +} + +static void hsc_rx_msg_destructor(struct hsi_msg *msg) +{ + msg->status = HSI_STATUS_ERROR; + hsc_msg_len_set(msg, 0); + hsc_rx_completed(msg); +} + +static void hsc_tx_completed(struct hsi_msg *msg) +{ + struct hsc_client_data *cl_data = hsi_client_drvdata(msg->cl); + struct hsc_channel *channel = cl_data->channels + msg->channel; + + if (test_bit(HSC_CH_WRITE, &channel->flags)) { + hsc_add_tail(channel, msg, &channel->tx_msgs_queue); + wake_up(&channel->tx_wait); + } else { + hsc_add_tail(channel, msg, &channel->free_msgs_list); + } +} + +static void hsc_tx_msg_destructor(struct hsi_msg *msg) +{ + msg->status = HSI_STATUS_ERROR; + hsc_msg_len_set(msg, 0); + hsc_tx_completed(msg); +} + +static void hsc_break_req_destructor(struct hsi_msg *msg) +{ + struct hsc_client_data *cl_data = hsi_client_drvdata(msg->cl); + + hsi_free_msg(msg); + clear_bit(HSC_RXBREAK, &cl_data->flags); +} + +static void hsc_break_received(struct hsi_msg *msg) +{ + struct hsc_client_data *cl_data = hsi_client_drvdata(msg->cl); + struct hsc_channel *channel = cl_data->channels; + int i, ret; + + /* Broadcast HWBREAK on all channels */ + for (i = 0; i < HSC_DEVS; i++, channel++) { + struct hsi_msg *msg2; + + if (!test_bit(HSC_CH_READ, &channel->flags)) + continue; + msg2 = hsc_get_first_msg(channel, &channel->free_msgs_list); + if (!msg2) + continue; + clear_bit(HSC_CH_READ, &channel->flags); + hsc_msg_len_set(msg2, 0); + msg2->status = HSI_STATUS_COMPLETED; + hsc_add_tail(channel, msg2, &channel->rx_msgs_queue); + wake_up(&channel->rx_wait); + } + hsi_flush(msg->cl); + ret = hsi_async_read(msg->cl, msg); + if (ret < 0) + hsc_break_req_destructor(msg); +} + +static int hsc_break_request(struct hsi_client *cl) +{ + struct hsc_client_data *cl_data = hsi_client_drvdata(cl); + struct hsi_msg *msg; + int ret; + + if (test_and_set_bit(HSC_RXBREAK, &cl_data->flags)) + return -EBUSY; + + msg = hsi_alloc_msg(0, GFP_KERNEL); + if (!msg) { + clear_bit(HSC_RXBREAK, &cl_data->flags); + return -ENOMEM; + } + msg->break_frame = 1; + msg->complete = hsc_break_received; + msg->destructor = hsc_break_req_destructor; + ret = hsi_async_read(cl, msg); + if (ret < 0) + hsc_break_req_destructor(msg); + + return ret; +} + +static int hsc_break_send(struct hsi_client *cl) +{ + struct hsi_msg *msg; + int ret; + + msg = hsi_alloc_msg(0, GFP_ATOMIC); + if (!msg) + return -ENOMEM; + msg->break_frame = 1; + msg->complete = hsi_free_msg; + msg->destructor = hsi_free_msg; + ret = hsi_async_write(cl, msg); + if (ret < 0) + hsi_free_msg(msg); + + return ret; +} + +static int hsc_rx_set(struct hsi_client *cl, struct hsc_rx_config *rxc) +{ + struct hsi_config tmp; + int ret; + + if ((rxc->mode != HSI_MODE_STREAM) && (rxc->mode != HSI_MODE_FRAME)) + return -EINVAL; + if ((rxc->channels == 0) || (rxc->channels > HSC_DEVS)) + return -EINVAL; + if (rxc->channels & (rxc->channels - 1)) + return -EINVAL; + if ((rxc->flow != HSI_FLOW_SYNC) && (rxc->flow != HSI_FLOW_PIPE)) + return -EINVAL; + tmp = cl->rx_cfg; + cl->rx_cfg.mode = rxc->mode; + cl->rx_cfg.channels = rxc->channels; + cl->rx_cfg.flow = rxc->flow; + ret = hsi_setup(cl); + if (ret < 0) { + cl->rx_cfg = tmp; + return ret; + } + if (rxc->mode == HSI_MODE_FRAME) + hsc_break_request(cl); + + return ret; +} + +static inline void hsc_rx_get(struct hsi_client *cl, struct hsc_rx_config *rxc) +{ + rxc->mode = cl->rx_cfg.mode; + rxc->channels = cl->rx_cfg.channels; + rxc->flow = cl->rx_cfg.flow; +} + +static int hsc_tx_set(struct hsi_client *cl, struct hsc_tx_config *txc) +{ + struct hsi_config tmp; + int ret; + + if ((txc->mode != HSI_MODE_STREAM) && (txc->mode != HSI_MODE_FRAME)) + return -EINVAL; + if ((txc->channels == 0) || (txc->channels > HSC_DEVS)) + return -EINVAL; + if (txc->channels & (txc->channels - 1)) + return -EINVAL; + if ((txc->arb_mode != HSI_ARB_RR) && (txc->arb_mode != HSI_ARB_PRIO)) + return -EINVAL; + tmp = cl->tx_cfg; + cl->tx_cfg.mode = txc->mode; + cl->tx_cfg.channels = txc->channels; + cl->tx_cfg.speed = txc->speed; + cl->tx_cfg.arb_mode = txc->arb_mode; + ret = hsi_setup(cl); + if (ret < 0) { + cl->tx_cfg = tmp; + return ret; + } + + return ret; +} + +static inline void hsc_tx_get(struct hsi_client *cl, struct hsc_tx_config *txc) +{ + txc->mode = cl->tx_cfg.mode; + txc->channels = cl->tx_cfg.channels; + txc->speed = cl->tx_cfg.speed; + txc->arb_mode = cl->tx_cfg.arb_mode; +} + +static ssize_t hsc_read(struct file *file, char __user *buf, size_t len, + loff_t *ppos __maybe_unused) +{ + struct hsc_channel *channel = file->private_data; + struct hsi_msg *msg; + ssize_t ret; + + if (len == 0) + return 0; + if (!IS_ALIGNED(len, sizeof(u32))) + return -EINVAL; + if (len > max_data_size) + len = max_data_size; + if (channel->ch >= channel->cl->rx_cfg.channels) + return -ECHRNG; + if (test_and_set_bit(HSC_CH_READ, &channel->flags)) + return -EBUSY; + msg = hsc_get_first_msg(channel, &channel->free_msgs_list); + if (!msg) { + ret = -ENOSPC; + goto out; + } + hsc_msg_len_set(msg, len); + msg->complete = hsc_rx_completed; + msg->destructor = hsc_rx_msg_destructor; + ret = hsi_async_read(channel->cl, msg); + if (ret < 0) { + hsc_add_tail(channel, msg, &channel->free_msgs_list); + goto out; + } + + ret = wait_event_interruptible(channel->rx_wait, + !list_empty(&channel->rx_msgs_queue)); + if (ret < 0) { + clear_bit(HSC_CH_READ, &channel->flags); + hsi_flush(channel->cl); + return -EINTR; + } + + msg = hsc_get_first_msg(channel, &channel->rx_msgs_queue); + if (msg) { + if (msg->status != HSI_STATUS_ERROR) { + ret = copy_to_user((void __user *)buf, + sg_virt(msg->sgt.sgl), hsc_msg_len_get(msg)); + if (ret) + ret = -EFAULT; + else + ret = hsc_msg_len_get(msg); + } else { + ret = -EIO; + } + hsc_add_tail(channel, msg, &channel->free_msgs_list); + } +out: + clear_bit(HSC_CH_READ, &channel->flags); + + return ret; +} + +static ssize_t hsc_write(struct file *file, const char __user *buf, size_t len, + loff_t *ppos __maybe_unused) +{ + struct hsc_channel *channel = file->private_data; + struct hsi_msg *msg; + ssize_t ret; + + if ((len == 0) || !IS_ALIGNED(len, sizeof(u32))) + return -EINVAL; + if (len > max_data_size) + len = max_data_size; + if (channel->ch >= channel->cl->tx_cfg.channels) + return -ECHRNG; + if (test_and_set_bit(HSC_CH_WRITE, &channel->flags)) + return -EBUSY; + msg = hsc_get_first_msg(channel, &channel->free_msgs_list); + if (!msg) { + clear_bit(HSC_CH_WRITE, &channel->flags); + return -ENOSPC; + } + if (copy_from_user(sg_virt(msg->sgt.sgl), (void __user *)buf, len)) { + ret = -EFAULT; + goto out; + } + hsc_msg_len_set(msg, len); + msg->complete = hsc_tx_completed; + msg->destructor = hsc_tx_msg_destructor; + ret = hsi_async_write(channel->cl, msg); + if (ret < 0) + goto out; + + ret = wait_event_interruptible(channel->tx_wait, + !list_empty(&channel->tx_msgs_queue)); + if (ret < 0) { + clear_bit(HSC_CH_WRITE, &channel->flags); + hsi_flush(channel->cl); + return -EINTR; + } + + msg = hsc_get_first_msg(channel, &channel->tx_msgs_queue); + if (msg) { + if (msg->status == HSI_STATUS_ERROR) + ret = -EIO; + else + ret = hsc_msg_len_get(msg); + + hsc_add_tail(channel, msg, &channel->free_msgs_list); + } +out: + clear_bit(HSC_CH_WRITE, &channel->flags); + + return ret; +} + +static long hsc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct hsc_channel *channel = file->private_data; + unsigned int state; + struct hsc_rx_config rxc; + struct hsc_tx_config txc; + long ret = 0; + + switch (cmd) { + case HSC_RESET: + hsi_flush(channel->cl); + break; + case HSC_SET_PM: + if (copy_from_user(&state, (void __user *)arg, sizeof(state))) + return -EFAULT; + if (state == HSC_PM_DISABLE) { + if (test_and_set_bit(HSC_CH_WLINE, &channel->flags)) + return -EINVAL; + ret = hsi_start_tx(channel->cl); + } else if (state == HSC_PM_ENABLE) { + if (!test_and_clear_bit(HSC_CH_WLINE, &channel->flags)) + return -EINVAL; + ret = hsi_stop_tx(channel->cl); + } else { + ret = -EINVAL; + } + break; + case HSC_SEND_BREAK: + return hsc_break_send(channel->cl); + case HSC_SET_RX: + if (copy_from_user(&rxc, (void __user *)arg, sizeof(rxc))) + return -EFAULT; + return hsc_rx_set(channel->cl, &rxc); + case HSC_GET_RX: + hsc_rx_get(channel->cl, &rxc); + if (copy_to_user((void __user *)arg, &rxc, sizeof(rxc))) + return -EFAULT; + break; + case HSC_SET_TX: + if (copy_from_user(&txc, (void __user *)arg, sizeof(txc))) + return -EFAULT; + return hsc_tx_set(channel->cl, &txc); + case HSC_GET_TX: + hsc_tx_get(channel->cl, &txc); + if (copy_to_user((void __user *)arg, &txc, sizeof(txc))) + return -EFAULT; + break; + default: + return -ENOIOCTLCMD; + } + + return ret; +} + +static inline void __hsc_port_release(struct hsc_client_data *cl_data) +{ + BUG_ON(cl_data->usecnt == 0); + + if (--cl_data->usecnt == 0) { + hsi_flush(cl_data->cl); + hsi_release_port(cl_data->cl); + } +} + +static int hsc_open(struct inode *inode, struct file *file) +{ + struct hsc_client_data *cl_data; + struct hsc_channel *channel; + int ret = 0; + + pr_debug("open, minor = %d\n", iminor(inode)); + + cl_data = container_of(inode->i_cdev, struct hsc_client_data, cdev); + mutex_lock(&cl_data->lock); + channel = cl_data->channels + (iminor(inode) & HSC_CH_MASK); + + if (test_and_set_bit(HSC_CH_OPEN, &channel->flags)) { + ret = -EBUSY; + goto out; + } + /* + * Check if we have already claimed the port associated to the HSI + * client. If not then try to claim it, else increase its refcount + */ + if (cl_data->usecnt == 0) { + ret = hsi_claim_port(cl_data->cl, 0); + if (ret < 0) + goto out; + hsi_setup(cl_data->cl); + } + cl_data->usecnt++; + + ret = hsc_msgs_alloc(channel); + if (ret < 0) { + __hsc_port_release(cl_data); + goto out; + } + + file->private_data = channel; + mutex_unlock(&cl_data->lock); + + return ret; +out: + mutex_unlock(&cl_data->lock); + + return ret; +} + +static int hsc_release(struct inode *inode __maybe_unused, struct file *file) +{ + struct hsc_channel *channel = file->private_data; + struct hsc_client_data *cl_data = channel->cl_data; + + mutex_lock(&cl_data->lock); + file->private_data = NULL; + if (test_and_clear_bit(HSC_CH_WLINE, &channel->flags)) + hsi_stop_tx(channel->cl); + __hsc_port_release(cl_data); + hsc_reset_list(channel, &channel->rx_msgs_queue); + hsc_reset_list(channel, &channel->tx_msgs_queue); + hsc_reset_list(channel, &channel->free_msgs_list); + clear_bit(HSC_CH_READ, &channel->flags); + clear_bit(HSC_CH_WRITE, &channel->flags); + clear_bit(HSC_CH_OPEN, &channel->flags); + wake_up(&channel->rx_wait); + wake_up(&channel->tx_wait); + mutex_unlock(&cl_data->lock); + + return 0; +} + +static const struct file_operations hsc_fops = { + .owner = THIS_MODULE, + .read = hsc_read, + .write = hsc_write, + .unlocked_ioctl = hsc_ioctl, + .open = hsc_open, + .release = hsc_release, +}; + +static void __devinit hsc_channel_init(struct hsc_channel *channel) +{ + init_waitqueue_head(&channel->rx_wait); + init_waitqueue_head(&channel->tx_wait); + spin_lock_init(&channel->lock); + INIT_LIST_HEAD(&channel->free_msgs_list); + INIT_LIST_HEAD(&channel->rx_msgs_queue); + INIT_LIST_HEAD(&channel->tx_msgs_queue); +} + +static int __devinit hsc_probe(struct device *dev) +{ + const char devname[] = "hsi_char"; + struct hsc_client_data *cl_data; + struct hsc_channel *channel; + struct hsi_client *cl = to_hsi_client(dev); + unsigned int hsc_baseminor; + dev_t hsc_dev; + int ret; + int i; + + cl_data = kzalloc(sizeof(*cl_data), GFP_KERNEL); + if (!cl_data) { + dev_err(dev, "Could not allocate hsc_client_data\n"); + return -ENOMEM; + } + hsc_baseminor = HSC_BASEMINOR(hsi_id(cl), hsi_port_id(cl)); + if (!hsc_major) { + ret = alloc_chrdev_region(&hsc_dev, hsc_baseminor, + HSC_DEVS, devname); + if (ret > 0) + hsc_major = MAJOR(hsc_dev); + } else { + hsc_dev = MKDEV(hsc_major, hsc_baseminor); + ret = register_chrdev_region(hsc_dev, HSC_DEVS, devname); + } + if (ret < 0) { + dev_err(dev, "Device %s allocation failed %d\n", + hsc_major ? "minor" : "major", ret); + goto out1; + } + mutex_init(&cl_data->lock); + hsi_client_set_drvdata(cl, cl_data); + cdev_init(&cl_data->cdev, &hsc_fops); + cl_data->cdev.owner = THIS_MODULE; + cl_data->cl = cl; + for (i = 0, channel = cl_data->channels; i < HSC_DEVS; i++, channel++) { + hsc_channel_init(channel); + channel->ch = i; + channel->cl = cl; + channel->cl_data = cl_data; + } + + /* 1 hsi client -> N char devices (one for each channel) */ + ret = cdev_add(&cl_data->cdev, hsc_dev, HSC_DEVS); + if (ret) { + dev_err(dev, "Could not add char device %d\n", ret); + goto out2; + } + + return 0; +out2: + unregister_chrdev_region(hsc_dev, HSC_DEVS); +out1: + kfree(cl_data); + + return ret; +} + +static int __devexit hsc_remove(struct device *dev) +{ + struct hsi_client *cl = to_hsi_client(dev); + struct hsc_client_data *cl_data = hsi_client_drvdata(cl); + dev_t hsc_dev = cl_data->cdev.dev; + + cdev_del(&cl_data->cdev); + unregister_chrdev_region(hsc_dev, HSC_DEVS); + hsi_client_set_drvdata(cl, NULL); + kfree(cl_data); + + return 0; +} + +static struct hsi_client_driver hsc_driver = { + .driver = { + .name = "hsi_char", + .owner = THIS_MODULE, + .probe = hsc_probe, + .remove = __devexit_p(hsc_remove), + }, +}; + +static int __init hsc_init(void) +{ + int ret; + + if ((max_data_size < 4) || (max_data_size > 0x10000) || + (max_data_size & (max_data_size - 1))) { + pr_err("Invalid max read/write data size"); + return -EINVAL; + } + + ret = hsi_register_client_driver(&hsc_driver); + if (ret) { + pr_err("Error while registering HSI/SSI driver %d", ret); + return ret; + } + + pr_info("HSI/SSI char device loaded\n"); + + return 0; +} +module_init(hsc_init); + +static void __exit hsc_exit(void) +{ + hsi_unregister_client_driver(&hsc_driver); + pr_info("HSI char device removed\n"); +} +module_exit(hsc_exit); + +MODULE_AUTHOR("Andras Domokos "); +MODULE_ALIAS("hsi:hsi_char"); +MODULE_DESCRIPTION("HSI character device"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/hsi/hsi_char.h b/include/linux/hsi/hsi_char.h new file mode 100644 index 000000000000..76160b4f455d --- /dev/null +++ b/include/linux/hsi/hsi_char.h @@ -0,0 +1,63 @@ +/* + * Part of the HSI character device driver. + * + * Copyright (C) 2010 Nokia Corporation. All rights reserved. + * + * Contact: Andras Domokos + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + + +#ifndef __HSI_CHAR_H +#define __HSI_CHAR_H + +#define HSI_CHAR_MAGIC 'k' +#define HSC_IOW(num, dtype) _IOW(HSI_CHAR_MAGIC, num, dtype) +#define HSC_IOR(num, dtype) _IOR(HSI_CHAR_MAGIC, num, dtype) +#define HSC_IOWR(num, dtype) _IOWR(HSI_CHAR_MAGIC, num, dtype) +#define HSC_IO(num) _IO(HSI_CHAR_MAGIC, num) + +#define HSC_RESET HSC_IO(16) +#define HSC_SET_PM HSC_IO(17) +#define HSC_SEND_BREAK HSC_IO(18) +#define HSC_SET_RX HSC_IOW(19, struct hsc_rx_config) +#define HSC_GET_RX HSC_IOW(20, struct hsc_rx_config) +#define HSC_SET_TX HSC_IOW(21, struct hsc_tx_config) +#define HSC_GET_TX HSC_IOW(22, struct hsc_tx_config) + +#define HSC_PM_DISABLE 0 +#define HSC_PM_ENABLE 1 + +#define HSC_MODE_STREAM 1 +#define HSC_MODE_FRAME 2 +#define HSC_FLOW_SYNC 0 +#define HSC_ARB_RR 0 +#define HSC_ARB_PRIO 1 + +struct hsc_rx_config { + uint32_t mode; + uint32_t flow; + uint32_t channels; +}; + +struct hsc_tx_config { + uint32_t mode; + uint32_t channels; + uint32_t speed; + uint32_t arb_mode; +}; + +#endif /* __HSI_CHAR_H */ -- cgit v1.2.3 From f9e402016de91c2444e46ecfd706880969b1ae9e Mon Sep 17 00:00:00 2001 From: Andras Domokos Date: Wed, 21 Apr 2010 12:04:21 +0300 Subject: HSI: hsi_char: Add HSI char device kernel configuration Add HSI character device kernel configuration Signed-off-by: Andras Domokos Signed-off-by: Carlos Chinea --- drivers/hsi/Kconfig | 2 ++ drivers/hsi/Makefile | 1 + drivers/hsi/clients/Kconfig | 13 +++++++++++++ drivers/hsi/clients/Makefile | 5 +++++ include/linux/Kbuild | 1 + include/linux/hsi/Kbuild | 1 + 6 files changed, 23 insertions(+) create mode 100644 drivers/hsi/clients/Kconfig create mode 100644 drivers/hsi/clients/Makefile create mode 100644 include/linux/hsi/Kbuild (limited to 'drivers') diff --git a/drivers/hsi/Kconfig b/drivers/hsi/Kconfig index 937062e8bcd0..d94e38dd80c7 100644 --- a/drivers/hsi/Kconfig +++ b/drivers/hsi/Kconfig @@ -14,4 +14,6 @@ config HSI_BOARDINFO bool default y +source "drivers/hsi/clients/Kconfig" + endif # HSI diff --git a/drivers/hsi/Makefile b/drivers/hsi/Makefile index ed94a3a334a4..9d5d33f90de2 100644 --- a/drivers/hsi/Makefile +++ b/drivers/hsi/Makefile @@ -3,3 +3,4 @@ # obj-$(CONFIG_HSI_BOARDINFO) += hsi_boardinfo.o obj-$(CONFIG_HSI) += hsi.o +obj-y += clients/ diff --git a/drivers/hsi/clients/Kconfig b/drivers/hsi/clients/Kconfig new file mode 100644 index 000000000000..3bacd275f479 --- /dev/null +++ b/drivers/hsi/clients/Kconfig @@ -0,0 +1,13 @@ +# +# HSI clients configuration +# + +comment "HSI clients" + +config HSI_CHAR + tristate "HSI/SSI character driver" + depends on HSI + ---help--- + If you say Y here, you will enable the HSI/SSI character driver. + This driver provides a simple character device interface for + serial communication with the cellular modem over HSI/SSI bus. diff --git a/drivers/hsi/clients/Makefile b/drivers/hsi/clients/Makefile new file mode 100644 index 000000000000..327c0e27c8b0 --- /dev/null +++ b/drivers/hsi/clients/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for HSI clients +# + +obj-$(CONFIG_HSI_CHAR) += hsi_char.o diff --git a/include/linux/Kbuild b/include/linux/Kbuild index 619b5657af77..3171939e6261 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -3,6 +3,7 @@ header-y += can/ header-y += caif/ header-y += dvb/ header-y += hdlc/ +header-y += hsi/ header-y += isdn/ header-y += mmc/ header-y += nfsd/ diff --git a/include/linux/hsi/Kbuild b/include/linux/hsi/Kbuild new file mode 100644 index 000000000000..271a770b4784 --- /dev/null +++ b/include/linux/hsi/Kbuild @@ -0,0 +1 @@ +header-y += hsi_char.h -- cgit v1.2.3 From c29f40ca19b8ca284a2d1415e26b802bc9b2fb67 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Tue, 6 Mar 2012 07:52:38 +0000 Subject: ixgbe: Fix issues with SR-IOV loopback when flow control is disabled This patch allows us to avoid a Tx hang when SR-IOV is enabled. This hang can be triggered by sending small packets at a rate that was triggering Rx missed errors from the adapter while the internal Tx switch and at least one VF are enabled. This was all due to the fact that under heavy stress the Rx FIFO never drained below the flow control high water mark. This resulted in the Tx FIFO being head of line blocked due to the fact that it relies on the flow control high water mark to determine when it is acceptable for the Tx to place a packet in the Rx FIFO. The resolution for this is to set the FCRTH value to the RXPBSIZE - 32 so that even if the ring is almost completely full we can still place Tx packets on the Rx ring and drop incoming Rx traffic if we do not have sufficient space available in the Rx FIFO. Signed-off-by: Alexander Duyck Tested-by: Sibai Li Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_common.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c index 383b9413292e..7d81bee4f681 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c @@ -2011,13 +2011,20 @@ s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw, s32 packetbuf_num) IXGBE_WRITE_REG(hw, IXGBE_MFLCN, mflcn_reg); IXGBE_WRITE_REG(hw, IXGBE_FCCFG, fccfg_reg); - fcrth = hw->fc.high_water[packetbuf_num] << 10; fcrtl = hw->fc.low_water << 10; if (hw->fc.current_mode & ixgbe_fc_tx_pause) { + fcrth = hw->fc.high_water[packetbuf_num] << 10; fcrth |= IXGBE_FCRTH_FCEN; if (hw->fc.send_xon) fcrtl |= IXGBE_FCRTL_XONE; + } else { + /* + * If Tx flow control is disabled, set our high water mark + * to Rx FIFO size minus 32 in order prevent Tx switch + * loopback from stalling on DMA. + */ + fcrth = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(packetbuf_num)) - 32; } IXGBE_WRITE_REG(hw, IXGBE_FCRTH_82599(packetbuf_num), fcrth); -- cgit v1.2.3 From c98291ee1ceac03912e24b3219fa6e7dc0d52f5e Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Fri, 16 Mar 2012 00:18:54 +0000 Subject: fcoe: use CHECKSUM_UNNECESSARY instead of CHECKSUM_PARTIAL on tx Fix a bug when using 'ethtool -K ethx tx off' to turn off tx ip checksum, FCoE CRC offload should not be impacte. The skb_checksum_help() is needed only if it's not FCoE traffic for ip checksum, regardless of ethtool toggling the tx ip checksum on or off. Instead of using CHECKSUM_PARTIAL, we will use CHECKSUM_UNNECESSARY as a proper indication to avoid sw ip checksum on FCoE frames. Ref. to original discussion thread: http://patchwork.ozlabs.org/patch/146567/ CC: "James E.J. Bottomley" CC: Robert Love Signed-off-by: Yi Zou Tested-by: Ross Brattain Signed-off-by: Jeff Kirsher --- drivers/scsi/fcoe/fcoe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index e9599600aa23..c164890224d2 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -1498,7 +1498,7 @@ static int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp) /* crc offload */ if (likely(lport->crc_offload)) { - skb->ip_summed = CHECKSUM_PARTIAL; + skb->ip_summed = CHECKSUM_UNNECESSARY; skb->csum_start = skb_headroom(skb); skb->csum_offset = skb->len; crc = 0; -- cgit v1.2.3 From 51579137c500362018b5341f5dca47807ed558aa Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 24 Mar 2012 09:37:30 +0800 Subject: regulator: tps6586x: Fix list minimal voltage setting for LDO0 According to the datasheet, LDO0 has minimal voltage 1.2V rather than 1.25V. Table 3-39. VLDO0[2:0] Settings VLDOx[2:0] VOUT (V) VLDOx[2:0] VOUT (V) 000 1.20 100 2.70 001 1.50 101 2.85 010 1.80 110 3.10 011 2.50 111 3.30 Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/tps6586x-regulator.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c index 29b615ce3aff..cfc1f16f7771 100644 --- a/drivers/regulator/tps6586x-regulator.c +++ b/drivers/regulator/tps6586x-regulator.c @@ -79,6 +79,11 @@ static int tps6586x_ldo_list_voltage(struct regulator_dev *rdev, unsigned selector) { struct tps6586x_regulator *info = rdev_get_drvdata(rdev); + int rid = rdev_get_id(rdev); + + /* LDO0 has minimal voltage 1.2V rather than 1.25V */ + if ((rid == TPS6586X_ID_LDO_0) && (selector == 0)) + return (info->voltages[0] - 50) * 1000; return info->voltages[selector] * 1000; } -- cgit v1.2.3 From 09bf14b901f2c1908b6a72fe934457acdd1fa430 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 15 Mar 2012 15:53:05 +0800 Subject: regulator: Fix set and get current limit for wm831x_buckv WM831X_DC1_HC_THR_MASK is 0x0070. We need to do proper shift for setting and getting current limit. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/wm831x-dcdc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c index 4904a40b0d46..3044001f3cf6 100644 --- a/drivers/regulator/wm831x-dcdc.c +++ b/drivers/regulator/wm831x-dcdc.c @@ -386,7 +386,8 @@ static int wm831x_buckv_set_current_limit(struct regulator_dev *rdev, if (i == ARRAY_SIZE(wm831x_dcdc_ilim)) return -EINVAL; - return wm831x_set_bits(wm831x, reg, WM831X_DC1_HC_THR_MASK, i); + return wm831x_set_bits(wm831x, reg, WM831X_DC1_HC_THR_MASK, + i << WM831X_DC1_HC_THR_SHIFT); } static int wm831x_buckv_get_current_limit(struct regulator_dev *rdev) @@ -400,7 +401,8 @@ static int wm831x_buckv_get_current_limit(struct regulator_dev *rdev) if (val < 0) return val; - return wm831x_dcdc_ilim[val & WM831X_DC1_HC_THR_MASK]; + val = (val & WM831X_DC1_HC_THR_MASK) >> WM831X_DC1_HC_THR_SHIFT; + return wm831x_dcdc_ilim[val]; } static struct regulator_ops wm831x_buckv_ops = { -- cgit v1.2.3 From 5777d9b34aec841429ddade56403b3f53a821a1d Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 15 Mar 2012 12:49:09 +0800 Subject: regulator: Fix unbalanced lock/unlock in mc13892_regulator_probe error path We do not hold a lock while registering regulator, thus should not call unlock if regulator_register fails. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/mc13892-regulator.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c index e8cfc99dd8f0..845aa2263b8a 100644 --- a/drivers/regulator/mc13892-regulator.c +++ b/drivers/regulator/mc13892-regulator.c @@ -552,7 +552,7 @@ static int __devinit mc13892_regulator_probe(struct platform_device *pdev) mc13xxx_lock(mc13892); ret = mc13xxx_reg_read(mc13892, MC13892_REVISION, &val); if (ret) - goto err_free; + goto err_unlock; /* enable switch auto mode */ if ((val & 0x0000FFFF) == 0x45d0) { @@ -562,7 +562,7 @@ static int __devinit mc13892_regulator_probe(struct platform_device *pdev) MC13892_SWITCHERS4_SW1MODE_AUTO | MC13892_SWITCHERS4_SW2MODE_AUTO); if (ret) - goto err_free; + goto err_unlock; ret = mc13xxx_reg_rmw(mc13892, MC13892_SWITCHERS5, MC13892_SWITCHERS5_SW3MODE_M | @@ -570,7 +570,7 @@ static int __devinit mc13892_regulator_probe(struct platform_device *pdev) MC13892_SWITCHERS5_SW3MODE_AUTO | MC13892_SWITCHERS5_SW4MODE_AUTO); if (ret) - goto err_free; + goto err_unlock; } mc13xxx_unlock(mc13892); @@ -612,10 +612,10 @@ static int __devinit mc13892_regulator_probe(struct platform_device *pdev) err: while (--i >= 0) regulator_unregister(priv->regulators[i]); + return ret; -err_free: +err_unlock: mc13xxx_unlock(mc13892); - return ret; } -- cgit v1.2.3 From eb4168158f79237498e4d3ddcef6e9436db15a4a Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 23 Mar 2012 06:25:05 +0800 Subject: regulator: Fix restoring pmic.dcdcx_hib_mode settings in wm8350_dcdc_set_suspend_enable What we want is to restore wm8350->pmic.dcdcx_hib_mode settings to WM8350_DCDCx_LOW_POWER registers. Current code also clears all other bits of WM8350_DCDCx_LOW_POWER registers which is wrong. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/wm8350-regulator.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index ab1e183a74b5..1c548218e12a 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c @@ -495,25 +495,25 @@ static int wm8350_dcdc_set_suspend_enable(struct regulator_dev *rdev) val = wm8350_reg_read(wm8350, WM8350_DCDC1_LOW_POWER) & ~WM8350_DCDC_HIB_MODE_MASK; wm8350_reg_write(wm8350, WM8350_DCDC1_LOW_POWER, - wm8350->pmic.dcdc1_hib_mode); + val | wm8350->pmic.dcdc1_hib_mode); break; case WM8350_DCDC_3: val = wm8350_reg_read(wm8350, WM8350_DCDC3_LOW_POWER) & ~WM8350_DCDC_HIB_MODE_MASK; wm8350_reg_write(wm8350, WM8350_DCDC3_LOW_POWER, - wm8350->pmic.dcdc3_hib_mode); + val | wm8350->pmic.dcdc3_hib_mode); break; case WM8350_DCDC_4: val = wm8350_reg_read(wm8350, WM8350_DCDC4_LOW_POWER) & ~WM8350_DCDC_HIB_MODE_MASK; wm8350_reg_write(wm8350, WM8350_DCDC4_LOW_POWER, - wm8350->pmic.dcdc4_hib_mode); + val | wm8350->pmic.dcdc4_hib_mode); break; case WM8350_DCDC_6: val = wm8350_reg_read(wm8350, WM8350_DCDC6_LOW_POWER) & ~WM8350_DCDC_HIB_MODE_MASK; wm8350_reg_write(wm8350, WM8350_DCDC6_LOW_POWER, - wm8350->pmic.dcdc6_hib_mode); + val | wm8350->pmic.dcdc6_hib_mode); break; case WM8350_DCDC_2: case WM8350_DCDC_5: -- cgit v1.2.3 From 9300928692f835f76f5604b3b51c3085977edf68 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 23 Mar 2012 06:27:10 +0800 Subject: regulator: Do proper shift to set correct bit for DC[2|5]_HIB_MODE setting DC[2|5]_HIB_MODE is BIT 12 of DCDC[2|5] Control register. WM8350_DC2_HIB_MODE_ACTIVE/WM8350_DC2_HIB_MODE_DISABLE are defined as 1/0. Thus we need to left shift WM8350_DC2_HIB_MODE_SHIFT bits. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/wm8350-regulator.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index 1c548218e12a..ff3465423be1 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c @@ -575,13 +575,13 @@ static int wm8350_dcdc25_set_suspend_enable(struct regulator_dev *rdev) val = wm8350_reg_read(wm8350, WM8350_DCDC2_CONTROL) & ~WM8350_DC2_HIB_MODE_MASK; wm8350_reg_write(wm8350, WM8350_DCDC2_CONTROL, val | - WM8350_DC2_HIB_MODE_ACTIVE); + (WM8350_DC2_HIB_MODE_ACTIVE << WM8350_DC2_HIB_MODE_SHIFT)); break; case WM8350_DCDC_5: val = wm8350_reg_read(wm8350, WM8350_DCDC5_CONTROL) - & ~WM8350_DC2_HIB_MODE_MASK; + & ~WM8350_DC5_HIB_MODE_MASK; wm8350_reg_write(wm8350, WM8350_DCDC5_CONTROL, val | - WM8350_DC5_HIB_MODE_ACTIVE); + (WM8350_DC5_HIB_MODE_ACTIVE << WM8350_DC5_HIB_MODE_SHIFT)); break; default: return -EINVAL; @@ -600,13 +600,13 @@ static int wm8350_dcdc25_set_suspend_disable(struct regulator_dev *rdev) val = wm8350_reg_read(wm8350, WM8350_DCDC2_CONTROL) & ~WM8350_DC2_HIB_MODE_MASK; wm8350_reg_write(wm8350, WM8350_DCDC2_CONTROL, val | - WM8350_DC2_HIB_MODE_DISABLE); + (WM8350_DC2_HIB_MODE_DISABLE << WM8350_DC2_HIB_MODE_SHIFT)); break; case WM8350_DCDC_5: val = wm8350_reg_read(wm8350, WM8350_DCDC5_CONTROL) - & ~WM8350_DC2_HIB_MODE_MASK; + & ~WM8350_DC5_HIB_MODE_MASK; wm8350_reg_write(wm8350, WM8350_DCDC5_CONTROL, val | - WM8350_DC2_HIB_MODE_DISABLE); + (WM8350_DC5_HIB_MODE_DISABLE << WM8350_DC5_HIB_MODE_SHIFT)); break; default: return -EINVAL; -- cgit v1.2.3 From 883a649b737cdbe3ede7e50f3f939fd706ed5c4e Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 13 Mar 2012 16:11:27 +0100 Subject: iwlegacy: do not nulify il->vif on reset This il->vif is dereferenced in different part of iwlegacy code, so do not nullify it. This should fix random crashes observed in companion with microcode errors i.e. crash in il3945_config_ap(). Additionally this should address also WARNING: at drivers/net/wireless/iwlegacy/common.c:4656 il_mac_remove_interface at least one of the possible reasons of that warning. Cc: stable@vger.kernel.org Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville --- drivers/net/wireless/iwlegacy/3945-mac.c | 2 -- drivers/net/wireless/iwlegacy/4965-mac.c | 2 -- drivers/net/wireless/iwlegacy/common.c | 15 ++++++++++++--- 3 files changed, 12 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c index 0c1209390169..faec40467208 100644 --- a/drivers/net/wireless/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/iwlegacy/3945-mac.c @@ -2673,8 +2673,6 @@ il3945_bg_restart(struct work_struct *data) if (test_and_clear_bit(S_FW_ERROR, &il->status)) { mutex_lock(&il->mutex); - /* FIXME: vif can be dereferenced */ - il->vif = NULL; il->is_open = 0; mutex_unlock(&il->mutex); il3945_down(il); diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c index 7b54dbb338be..b88bb2734197 100644 --- a/drivers/net/wireless/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/iwlegacy/4965-mac.c @@ -5651,8 +5651,6 @@ il4965_bg_restart(struct work_struct *data) if (test_and_clear_bit(S_FW_ERROR, &il->status)) { mutex_lock(&il->mutex); - /* FIXME: do we dereference vif without mutex locked ? */ - il->vif = NULL; il->is_open = 0; __il4965_down(il); diff --git a/drivers/net/wireless/iwlegacy/common.c b/drivers/net/wireless/iwlegacy/common.c index e5ac04739bcc..6a692a534ffc 100644 --- a/drivers/net/wireless/iwlegacy/common.c +++ b/drivers/net/wireless/iwlegacy/common.c @@ -4508,6 +4508,7 @@ il_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct il_priv *il = hw->priv; int err; + bool reset; mutex_lock(&il->mutex); D_MAC80211("enter: type %d, addr %pM\n", vif->type, vif->addr); @@ -4518,7 +4519,12 @@ il_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) goto out; } - if (il->vif) { + /* + * We do not support multiple virtual interfaces, but on hardware reset + * we have to add the same interface again. + */ + reset = (il->vif == vif); + if (il->vif && !reset) { err = -EOPNOTSUPP; goto out; } @@ -4528,8 +4534,11 @@ il_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) err = il_set_mode(il); if (err) { - il->vif = NULL; - il->iw_mode = NL80211_IFTYPE_STATION; + IL_WARN("Fail to set mode %d\n", vif->type); + if (!reset) { + il->vif = NULL; + il->iw_mode = NL80211_IFTYPE_STATION; + } } out: -- cgit v1.2.3 From 2ee0a07028d2cde6e131b73f029dae2b93c50f3a Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Thu, 15 Mar 2012 06:08:04 +0530 Subject: ath9k: fix max noise floor threshold Currently the maximum noise floor limit is set as too high (-60dB). The assumption of having a higher threshold limit is that it would help de-sensitize the receiver (reduce phy errors) from continuous interference. But when we have a bursty interference where there are collisions and then free air time and if the receiver is desensitized too much, it will miss the normal packets too. Lets make use of chips specific min, nom and max limits always. This patch helps to improve the connection stability in congested networks. Cc: stable@vger.kernel.org Cc: Paul Stewart Tested-by: Gary Morain Signed-off-by: Madhan Jaganathan Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/calib.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index 2f4b48e6fb03..e5cceb077574 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -20,7 +20,6 @@ /* Common calibration code */ -#define ATH9K_NF_TOO_HIGH -60 static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer) { @@ -346,10 +345,10 @@ static void ath9k_hw_nf_sanitize(struct ath_hw *ah, s16 *nf) "NF calibrated [%s] [chain %d] is %d\n", (i >= 3 ? "ext" : "ctl"), i % 3, nf[i]); - if (nf[i] > ATH9K_NF_TOO_HIGH) { + if (nf[i] > limit->max) { ath_dbg(common, CALIBRATE, "NF[%d] (%d) > MAX (%d), correcting to MAX\n", - i, nf[i], ATH9K_NF_TOO_HIGH); + i, nf[i], limit->max); nf[i] = limit->max; } else if (nf[i] < limit->min) { ath_dbg(common, CALIBRATE, -- cgit v1.2.3 From e92109be7a6a04808c3ed586475ba1e5ea56ecbd Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 15 Mar 2012 11:42:49 +0100 Subject: iwlegacy: fix BSSID setting Current commit 0775f9f90cdaf40fbf69b3192b3dddb2b3436f45 "mac80211: remove spurious BSSID change flag" exposed bug on iwlegacy, that we do not set BSSID address correctly and then device was not able to receive frames after successful associate. On the way fix scan canceling comment. Apparently ->post_associate() do cancel scan itself, but scan cancel on BSS_CHANGED_BSSID is needed. I'm not sure why, but when I removed it, I had frequent auth failures: wlan4: send auth to 54:e6:fc:98:63:fe (try 1/3) wlan4: send auth to 54:e6:fc:98:63:fe (try 2/3) wlan4: send auth to 54:e6:fc:98:63:fe (try 3/3) wlan4: authentication with 54:e6:fc:98:63:fe timed out Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville --- drivers/net/wireless/iwlegacy/common.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlegacy/common.c b/drivers/net/wireless/iwlegacy/common.c index 6a692a534ffc..eaf249452e51 100644 --- a/drivers/net/wireless/iwlegacy/common.c +++ b/drivers/net/wireless/iwlegacy/common.c @@ -5288,9 +5288,9 @@ il_mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, D_MAC80211("BSSID %pM\n", bss_conf->bssid); /* - * If there is currently a HW scan going on in the - * background then we need to cancel it else the RXON - * below/in post_associate will fail. + * If there is currently a HW scan going on in the background, + * then we need to cancel it, otherwise sometimes we are not + * able to authenticate (FIXME: why ?) */ if (il_scan_cancel_timeout(il, 100)) { D_MAC80211("leave - scan abort failed\n"); @@ -5299,14 +5299,10 @@ il_mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } /* mac80211 only sets assoc when in STATION mode */ - if (vif->type == NL80211_IFTYPE_ADHOC || bss_conf->assoc) { - memcpy(il->staging.bssid_addr, bss_conf->bssid, - ETH_ALEN); + memcpy(il->staging.bssid_addr, bss_conf->bssid, ETH_ALEN); - /* currently needed in a few places */ - memcpy(il->bssid, bss_conf->bssid, ETH_ALEN); - } else - il->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + /* FIXME: currently needed in a few places */ + memcpy(il->bssid, bss_conf->bssid, ETH_ALEN); } /* -- cgit v1.2.3 From 195ca3b122c02cf21ce64f211d9474600da80e80 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Thu, 15 Mar 2012 23:05:28 +0530 Subject: ath9k: reduce listen time period When we have downlink traffic alone and the station is going thru bgscan, the client is out of operating channel for around 1000ms which is too long. The mac80211 decides when to switch back to oper channel based on tx queue, bad latency and listen time. As the station does not have tx traffic, the bgscan can easily affect downlink throughput. By reducing the listen time, it helps the associated AP to retain the downstream rate. Cc: Paul Stewart Tested-by: Gary Morain Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 60159f4ee532..cb006458fc4b 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -680,7 +680,7 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) hw->queues = 4; hw->max_rates = 4; hw->channel_change_time = 5000; - hw->max_listen_interval = 10; + hw->max_listen_interval = 1; hw->max_rate_tries = 10; hw->sta_data_size = sizeof(struct ath_node); hw->vif_data_size = sizeof(struct ath_vif); -- cgit v1.2.3 From b5447ff92b5169eab843a76d83e98d0cd7b7f5b6 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 15 Mar 2012 13:43:29 -0700 Subject: ath9k: fix a memory leak in ath_rx_tasklet() commit 0d95521ea7 (ath9k: use split rx buffers to get rid of order-1 skb allocations) added in memory leak in error path. sc->rx.frag should be cleared after the pskb_expand_head() call, or else we jump to requeue_drop_frag and leak an skb. Signed-off-by: Eric Dumazet Cc: Jouni Malinen Cc: Felix Fietkau Cc: John W. Linville Cc: Trond Wuellner Cc: Grant Grundler Cc: Paul Stewart Cc: David Miller Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index f4ae3ba994a8..1c4583c7ff7c 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -1913,13 +1913,13 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) if (sc->rx.frag) { int space = skb->len - skb_tailroom(hdr_skb); - sc->rx.frag = NULL; - if (pskb_expand_head(hdr_skb, 0, space, GFP_ATOMIC) < 0) { dev_kfree_skb(skb); goto requeue_drop_frag; } + sc->rx.frag = NULL; + skb_copy_from_linear_data(skb, skb_put(hdr_skb, skb->len), skb->len); dev_kfree_skb_any(skb); -- cgit v1.2.3 From b9fc106108f3faf2e4430c3bd5721677c3d6a4a1 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 19 Mar 2012 09:39:45 +0100 Subject: rt2x00: rt2800usb: schedule txdone work on timeout This is fix for my current commit ed61e2b02027935520d1be884fac0b2ffce8379a "rt2x00: rt2800usb: rework txdone code" We should schedule txdone work on timeout, otherwise if newer get tx status from hardware, we will never report tx status to mac80211 and eventually never wakeup tx queue. Reported-by: Jakub Kicinski Signed-off-by: Stanislaw Gruszka Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index cd490abced91..f97f84606f56 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -163,7 +163,13 @@ static bool rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev, /* Reschedule urb to read TX status again instantly */ return true; - } else if (rt2800usb_txstatus_pending(rt2x00dev)) { + } + + /* Check if there is any entry that timedout waiting on TX status */ + if (rt2800usb_txstatus_timeout(rt2x00dev)) + queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work); + + if (rt2800usb_txstatus_pending(rt2x00dev)) { /* Read register after 250 us */ hrtimer_start(&rt2x00dev->txstatus_timer, ktime_set(0, 250000), HRTIMER_MODE_REL); -- cgit v1.2.3 From 4e808a38fdcaeeeddbc05942623279ebe7c02373 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 19 Mar 2012 15:59:41 +0100 Subject: rt2x00: rt2800usb: fix status register reread logic Another good catch from Jakub Kicinski. This patch fixes my recent commit: ed61e2b02027935520d1be884fac0b2ffce8379a "rt2x00: rt2800usb: rework txdone code" We should reread status register only when nobody else start already reading status i.e. test_and_set_bit(TX_STATUS_READING, flags) return 0. Reported-by: Jakub Kicinski Signed-off-by: Stanislaw Gruszka Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index f97f84606f56..001735f7a661 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -184,7 +184,7 @@ stop_reading: * here again if status reading is needed. */ if (rt2800usb_txstatus_pending(rt2x00dev) && - test_and_set_bit(TX_STATUS_READING, &rt2x00dev->flags)) + !test_and_set_bit(TX_STATUS_READING, &rt2x00dev->flags)) return true; else return false; -- cgit v1.2.3 From 643c61e119459e9d750087b7b34be94491efebf9 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 26 Mar 2012 09:59:48 -0500 Subject: rtlwifi: rtl8192ce: rtl8192cu: rtl8192de: Fix low-gain setting when scanning In https://bugzilla.redhat.com/show_bug.cgi?id=770207, slowdowns of driver rtl8192ce are reported. One fix (commit a9b89e2) has already been applied, and it helped, but the maximum RX speed would still drop to 1 Mbps. As in the previous fix, the initial gain was determined to be the problem; however, the problem arises from a setting of the gain when scans are started. Driver rtl8192de also has the same code structure - this one is fixed as well. Reported-and-Tested-by: Ivan Pesin Signed-off-by: Larry Finger Cc: Stable Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c | 2 +- drivers/net/wireless/rtlwifi/rtl8192de/phy.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c index 1eec3a06d1f3..4c016241f340 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c @@ -1893,7 +1893,7 @@ void rtl92c_phy_set_io(struct ieee80211_hw *hw) break; case IO_CMD_PAUSE_DM_BY_SCAN: rtlphy->initgain_backup.xaagccore1 = dm_digtable.cur_igvalue; - dm_digtable.cur_igvalue = 0x17; + dm_digtable.cur_igvalue = 0x37; rtl92c_dm_write_dig(hw); break; default: diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c index 34591eeb8376..28fc5fb8057b 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c @@ -3077,7 +3077,7 @@ static void rtl92d_phy_set_io(struct ieee80211_hw *hw) break; case IO_CMD_PAUSE_DM_BY_SCAN: rtlphy->initgain_backup.xaagccore1 = de_digtable.cur_igvalue; - de_digtable.cur_igvalue = 0x17; + de_digtable.cur_igvalue = 0x37; rtl92d_dm_write_dig(hw); break; default: -- cgit v1.2.3 From f2791d733a2f06997b573d1a3cfde21e6f529826 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 26 Mar 2012 22:46:52 +0200 Subject: PM / Runtime: don't forget to wake up waitqueue on failure This patch (as1535) fixes a bug in the runtime PM core. When a runtime suspend attempt completes, whether successfully or not, the device's power.wait_queue is supposed to be signalled. But this doesn't happen in the failure pathway of rpm_suspend() when another autosuspend attempt is rescheduled. As a result, a task can get stuck indefinitely on the wait queue (I have seen this happen in testing). The patch fixes the problem by moving the wake_up_all() call up near the start of the failure code. Signed-off-by: Alan Stern CC: Signed-off-by: Rafael J. Wysocki --- drivers/base/power/runtime.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 541f821d4ea6..bd0f3949bcf9 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -532,6 +532,8 @@ static int rpm_suspend(struct device *dev, int rpmflags) dev->power.suspend_time = ktime_set(0, 0); dev->power.max_time_suspended_ns = -1; dev->power.deferred_resume = false; + wake_up_all(&dev->power.wait_queue); + if (retval == -EAGAIN || retval == -EBUSY) { dev->power.runtime_error = 0; @@ -547,7 +549,6 @@ static int rpm_suspend(struct device *dev, int rpmflags) } else { pm_runtime_cancel_pending(dev); } - wake_up_all(&dev->power.wait_queue); goto out; } -- cgit v1.2.3 From 52f5509fe8ccb607ff9b84ad618f244262336475 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 20 Mar 2012 18:10:01 +0000 Subject: e1000: fix vlan processing regression This patch fixes a regression introduced by commit "e1000: do vlan cleanup (799d531)". Apparently some e1000 chips (not mine) are sensitive about the order of setting vlan filter and vlan stripping/inserting functionality. So this patch changes the order so it's the same as before vlan cleanup. Reported-by: Ben Greear Signed-off-by: Jiri Pirko Tested-by: Ben Greear Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000/e1000_main.c | 35 +++++++++++++++++---------- 1 file changed, 22 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c index 0e9aec8f6917..bcba9cfe3d03 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_main.c +++ b/drivers/net/ethernet/intel/e1000/e1000_main.c @@ -164,6 +164,8 @@ static int e1000_82547_fifo_workaround(struct e1000_adapter *adapter, static bool e1000_vlan_used(struct e1000_adapter *adapter); static void e1000_vlan_mode(struct net_device *netdev, netdev_features_t features); +static void e1000_vlan_filter_on_off(struct e1000_adapter *adapter, + bool filter_on); static int e1000_vlan_rx_add_vid(struct net_device *netdev, u16 vid); static int e1000_vlan_rx_kill_vid(struct net_device *netdev, u16 vid); static void e1000_restore_vlan(struct e1000_adapter *adapter); @@ -1214,7 +1216,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev, if (err) goto err_register; - e1000_vlan_mode(netdev, netdev->features); + e1000_vlan_filter_on_off(adapter, false); /* print bus type/speed/width info */ e_info(probe, "(PCI%s:%dMHz:%d-bit) %pM\n", @@ -4770,6 +4772,22 @@ static bool e1000_vlan_used(struct e1000_adapter *adapter) return false; } +static void __e1000_vlan_mode(struct e1000_adapter *adapter, + netdev_features_t features) +{ + struct e1000_hw *hw = &adapter->hw; + u32 ctrl; + + ctrl = er32(CTRL); + if (features & NETIF_F_HW_VLAN_RX) { + /* enable VLAN tag insert/strip */ + ctrl |= E1000_CTRL_VME; + } else { + /* disable VLAN tag insert/strip */ + ctrl &= ~E1000_CTRL_VME; + } + ew32(CTRL, ctrl); +} static void e1000_vlan_filter_on_off(struct e1000_adapter *adapter, bool filter_on) { @@ -4779,6 +4797,7 @@ static void e1000_vlan_filter_on_off(struct e1000_adapter *adapter, if (!test_bit(__E1000_DOWN, &adapter->flags)) e1000_irq_disable(adapter); + __e1000_vlan_mode(adapter, adapter->netdev->features); if (filter_on) { /* enable VLAN receive filtering */ rctl = er32(RCTL); @@ -4799,24 +4818,14 @@ static void e1000_vlan_filter_on_off(struct e1000_adapter *adapter, } static void e1000_vlan_mode(struct net_device *netdev, - netdev_features_t features) + netdev_features_t features) { struct e1000_adapter *adapter = netdev_priv(netdev); - struct e1000_hw *hw = &adapter->hw; - u32 ctrl; if (!test_bit(__E1000_DOWN, &adapter->flags)) e1000_irq_disable(adapter); - ctrl = er32(CTRL); - if (features & NETIF_F_HW_VLAN_RX) { - /* enable VLAN tag insert/strip */ - ctrl |= E1000_CTRL_VME; - } else { - /* disable VLAN tag insert/strip */ - ctrl &= ~E1000_CTRL_VME; - } - ew32(CTRL, ctrl); + __e1000_vlan_mode(adapter, features); if (!test_bit(__E1000_DOWN, &adapter->flags)) e1000_irq_enable(adapter); -- cgit v1.2.3 From 4eee6a3a04e8bb53fbe7de0f64d0524d3fbe3f80 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 26 Mar 2012 09:01:30 +0000 Subject: wimax: i2400m - prevent a possible kernel bug due to missing fw_name string This happened on a machine with a custom hotplug script calling nameif, probably due to slow firmware loading. At the time nameif uses ethtool to gather interface information, i2400m->fw_name is zero and so a null pointer dereference occurs from within i2400m_get_drvinfo(). Signed-off-by: Phil Sutter Signed-off-by: David S. Miller --- drivers/net/wimax/i2400m/netdev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wimax/i2400m/netdev.c b/drivers/net/wimax/i2400m/netdev.c index 63e4b709efa9..1d76ae855f07 100644 --- a/drivers/net/wimax/i2400m/netdev.c +++ b/drivers/net/wimax/i2400m/netdev.c @@ -597,7 +597,8 @@ static void i2400m_get_drvinfo(struct net_device *net_dev, struct i2400m *i2400m = net_dev_to_i2400m(net_dev); strncpy(info->driver, KBUILD_MODNAME, sizeof(info->driver) - 1); - strncpy(info->fw_version, i2400m->fw_name, sizeof(info->fw_version) - 1); + strncpy(info->fw_version, + i2400m->fw_name ? : "", sizeof(info->fw_version) - 1); if (net_dev->dev.parent) strncpy(info->bus_info, dev_name(net_dev->dev.parent), sizeof(info->bus_info) - 1); -- cgit v1.2.3 From b7440892802be38e6eeb0a17897deeb85476eff4 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 26 Mar 2012 09:01:31 +0000 Subject: wimax: i2400m-usb - use a private struct ethtool_ops This way the USB variant of the driver uses usb_make_path in order to provide bus-info compatible to other USB drivers (like e.g. asix.c). Signed-off-by: Phil Sutter Signed-off-by: David S. Miller --- drivers/net/wimax/i2400m/usb.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c index 2c1b8b687646..29b1e033a10b 100644 --- a/drivers/net/wimax/i2400m/usb.c +++ b/drivers/net/wimax/i2400m/usb.c @@ -339,6 +339,23 @@ int i2400mu_bus_reset(struct i2400m *i2400m, enum i2400m_reset_type rt) return result; } +static void i2400mu_get_drvinfo(struct net_device *net_dev, + struct ethtool_drvinfo *info) +{ + struct i2400m *i2400m = net_dev_to_i2400m(net_dev); + struct i2400mu *i2400mu = container_of(i2400m, struct i2400mu, i2400m); + struct usb_device *udev = i2400mu->usb_dev; + + strncpy(info->driver, KBUILD_MODNAME, sizeof(info->driver) - 1); + strncpy(info->fw_version, + i2400m->fw_name ? : "", sizeof(info->fw_version) - 1); + usb_make_path(udev, info->bus_info, sizeof(info->bus_info)); +} + +static const struct ethtool_ops i2400mu_ethtool_ops = { + .get_drvinfo = i2400mu_get_drvinfo, + .get_link = ethtool_op_get_link, +}; static void i2400mu_netdev_setup(struct net_device *net_dev) @@ -347,6 +364,7 @@ void i2400mu_netdev_setup(struct net_device *net_dev) struct i2400mu *i2400mu = container_of(i2400m, struct i2400mu, i2400m); i2400mu_init(i2400mu); i2400m_netdev_setup(net_dev); + net_dev->ethtool_ops = &i2400mu_ethtool_ops; } -- cgit v1.2.3 From f0e81fecd4f83de7854262c8a6b3af19dfa99bf9 Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Sun, 25 Mar 2012 18:59:51 +0000 Subject: net: sh_eth: Add support SH7734 Add define of SH7734 register and sh_eth_reset_hw_crc function. V3: Rebase net/HEAD. V2: Do not split line of #if defined. Signed-off-by: Nobuhiro Iwamatsu Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/Kconfig | 5 +++-- drivers/net/ethernet/renesas/sh_eth.c | 20 +++++++++++++++++--- drivers/net/ethernet/renesas/sh_eth.h | 11 ++++++++--- 3 files changed, 28 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/renesas/Kconfig b/drivers/net/ethernet/renesas/Kconfig index 9755b49bbefb..3fb2355af37e 100644 --- a/drivers/net/ethernet/renesas/Kconfig +++ b/drivers/net/ethernet/renesas/Kconfig @@ -7,7 +7,8 @@ config SH_ETH depends on SUPERH && \ (CPU_SUBTYPE_SH7710 || CPU_SUBTYPE_SH7712 || \ CPU_SUBTYPE_SH7763 || CPU_SUBTYPE_SH7619 || \ - CPU_SUBTYPE_SH7724 || CPU_SUBTYPE_SH7757) + CPU_SUBTYPE_SH7724 || CPU_SUBTYPE_SH7734 || \ + CPU_SUBTYPE_SH7757) select CRC32 select NET_CORE select MII @@ -16,4 +17,4 @@ config SH_ETH ---help--- Renesas SuperH Ethernet device driver. This driver supporting CPUs are: - - SH7710, SH7712, SH7763, SH7619, SH7724, and SH7757. + - SH7619, SH7710, SH7712, SH7724, SH7734, SH7763 and SH7757. diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 8615961c1287..8bdf070ace90 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -1,8 +1,8 @@ /* * SuperH Ethernet device driver * - * Copyright (C) 2006-2008 Nobuhiro Iwamatsu - * Copyright (C) 2008-2009 Renesas Solutions Corp. + * Copyright (C) 2006-2012 Nobuhiro Iwamatsu + * Copyright (C) 2008-2012 Renesas Solutions Corp. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -38,6 +38,7 @@ #include #include #include +#include #include #include "sh_eth.h" @@ -279,8 +280,9 @@ static struct sh_eth_cpu_data *sh_eth_get_cpu_data(struct sh_eth_private *mdp) return &sh_eth_my_cpu_data; } -#elif defined(CONFIG_CPU_SUBTYPE_SH7763) +#elif defined(CONFIG_CPU_SUBTYPE_SH7734) || defined(CONFIG_CPU_SUBTYPE_SH7763) #define SH_ETH_HAS_TSU 1 +static void sh_eth_reset_hw_crc(struct net_device *ndev); static void sh_eth_chip_reset(struct net_device *ndev) { struct sh_eth_private *mdp = netdev_priv(ndev); @@ -314,6 +316,9 @@ static void sh_eth_reset(struct net_device *ndev) sh_eth_write(ndev, 0x0, RDFAR); sh_eth_write(ndev, 0x0, RDFXR); sh_eth_write(ndev, 0x0, RDFFR); + + /* Reset HW CRC register */ + sh_eth_reset_hw_crc(ndev); } static void sh_eth_set_duplex(struct net_device *ndev) @@ -370,8 +375,17 @@ static struct sh_eth_cpu_data sh_eth_my_cpu_data = { .no_trimd = 1, .no_ade = 1, .tsu = 1, +#if defined(CONFIG_CPU_SUBTYPE_SH7734) + .hw_crc = 1, +#endif }; +static void sh_eth_reset_hw_crc(struct net_device *ndev) +{ + if (sh_eth_my_cpu_data.hw_crc) + sh_eth_write(ndev, 0x0, CSMR); +} + #elif defined(CONFIG_CPU_SUBTYPE_SH7619) #define SH_ETH_RESET_DEFAULT 1 static struct sh_eth_cpu_data sh_eth_my_cpu_data = { diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h index 57dc26261116..e66de1823532 100644 --- a/drivers/net/ethernet/renesas/sh_eth.h +++ b/drivers/net/ethernet/renesas/sh_eth.h @@ -1,8 +1,8 @@ /* * SuperH Ethernet device driver * - * Copyright (C) 2006-2008 Nobuhiro Iwamatsu - * Copyright (C) 2008-2011 Renesas Solutions Corp. + * Copyright (C) 2006-2012 Nobuhiro Iwamatsu + * Copyright (C) 2008-2012 Renesas Solutions Corp. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -98,6 +98,8 @@ enum { CEECR, MAFCR, RTRATE, + CSMR, + RMII_MII, /* TSU Absolute address */ ARSTR, @@ -172,6 +174,7 @@ static const u16 sh_eth_offset_gigabit[SH_ETH_MAX_REGISTER_OFFSET] = { [RMCR] = 0x0458, [RPADIR] = 0x0460, [FCFTR] = 0x0468, + [CSMR] = 0x04E4, [ECMR] = 0x0500, [ECSR] = 0x0510, @@ -200,6 +203,7 @@ static const u16 sh_eth_offset_gigabit[SH_ETH_MAX_REGISTER_OFFSET] = { [CERCR] = 0x0768, [CEECR] = 0x0770, [MAFCR] = 0x0778, + [RMII_MII] = 0x0790, [ARSTR] = 0x0000, [TSU_CTRST] = 0x0004, @@ -377,7 +381,7 @@ static const u16 sh_eth_offset_fast_sh3_sh2[SH_ETH_MAX_REGISTER_OFFSET] = { /* * Register's bits */ -#ifdef CONFIG_CPU_SUBTYPE_SH7763 +#if defined(CONFIG_CPU_SUBTYPE_SH7734) || defined(CONFIG_CPU_SUBTYPE_SH7763) /* EDSR */ enum EDSR_BIT { EDSR_ENT = 0x01, EDSR_ENR = 0x02, @@ -751,6 +755,7 @@ struct sh_eth_cpu_data { unsigned rpadir:1; /* E-DMAC have RPADIR */ unsigned no_trimd:1; /* E-DMAC DO NOT have TRIMD */ unsigned no_ade:1; /* E-DMAC DO NOT have ADE bit in EESR */ + unsigned hw_crc:1; /* E-DMAC have CSMR */ }; struct sh_eth_private { -- cgit v1.2.3 From a2daf263107ba3eb6db33931881731fa51c95045 Mon Sep 17 00:00:00 2001 From: Guan Xin Date: Mon, 26 Mar 2012 04:11:46 +0000 Subject: USB: Add Motorola Rokr E6 Id to the USBNet driver "zaurus" Added Vendor/Device Id of Motorola Rokr E6 (22b8:6027) so it can be recognized by the "zaurus" USBNet driver. Applies to Linux 3.2.13 and 2.6.39.4. Signed-off-by: Guan Xin Signed-off-by: David S. Miller --- drivers/net/usb/zaurus.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/net/usb/zaurus.c b/drivers/net/usb/zaurus.c index c3197ce0e2ad..34db195fb8b0 100644 --- a/drivers/net/usb/zaurus.c +++ b/drivers/net/usb/zaurus.c @@ -337,6 +337,11 @@ static const struct usb_device_id products [] = { .driver_info = ZAURUS_PXA_INFO, }, { + /* Motorola Rokr E6 */ + USB_DEVICE_AND_INTERFACE_INFO(0x22b8, 0x6027, USB_CLASS_COMM, + USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE), + .driver_info = (unsigned long) &bogus_mdlm_info, +}, { /* Motorola MOTOMAGX phones */ USB_DEVICE_AND_INTERFACE_INFO(0x22b8, 0x6425, USB_CLASS_COMM, USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE), -- cgit v1.2.3 From 452427b015b1b0cbbef7b6207908726837d39d57 Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Mon, 26 Mar 2012 20:47:07 +0000 Subject: bnx2x: previous driver unload revised The flow in which the bnx2x driver starts after a previous driver has been terminated in an 'unclean' manner has several bugs and FW risks, which makes it possible for the driver to fail after boot-from-SAN or kdump. This patch contains a revised flow which performs a safer initialization, solving the possible crash scenarios. Notice this patch contains lines with over 80 characters, as it keeps print-strings in a single line. Signed-off-by: Yuval Mintz Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x.h | 7 + drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 40 +- drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h | 3 + drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h | 3 + drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c | 1 - drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h | 2 + drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 464 ++++++++++++++++++----- drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h | 4 + 8 files changed, 417 insertions(+), 107 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h index e37161f19250..2c9ee552dffc 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h @@ -1173,6 +1173,13 @@ enum { }; +struct bnx2x_prev_path_list { + u8 bus; + u8 slot; + u8 path; + struct list_head list; +}; + struct bnx2x { /* Fields used in the tx and intr/napi performance paths * are grouped together in the beginning of the structure diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index f1f3ca65667a..44556b719e81 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -1721,6 +1721,29 @@ static void bnx2x_squeeze_objects(struct bnx2x *bp) } while (0) #endif +bool bnx2x_test_firmware_version(struct bnx2x *bp, bool is_err) +{ + /* build FW version dword */ + u32 my_fw = (BCM_5710_FW_MAJOR_VERSION) + + (BCM_5710_FW_MINOR_VERSION << 8) + + (BCM_5710_FW_REVISION_VERSION << 16) + + (BCM_5710_FW_ENGINEERING_VERSION << 24); + + /* read loaded FW from chip */ + u32 loaded_fw = REG_RD(bp, XSEM_REG_PRAM); + + DP(NETIF_MSG_IFUP, "loaded fw %x, my fw %x\n", loaded_fw, my_fw); + + if (loaded_fw != my_fw) { + if (is_err) + BNX2X_ERR("bnx2x with FW %x was already loaded, which mismatches my %x FW. aborting\n", + loaded_fw, my_fw); + return false; + } + + return true; +} + /* must be called with rtnl_lock */ int bnx2x_nic_load(struct bnx2x *bp, int load_mode) { @@ -1815,23 +1838,8 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode) } if (load_code != FW_MSG_CODE_DRV_LOAD_COMMON_CHIP && load_code != FW_MSG_CODE_DRV_LOAD_COMMON) { - /* build FW version dword */ - u32 my_fw = (BCM_5710_FW_MAJOR_VERSION) + - (BCM_5710_FW_MINOR_VERSION << 8) + - (BCM_5710_FW_REVISION_VERSION << 16) + - (BCM_5710_FW_ENGINEERING_VERSION << 24); - - /* read loaded FW from chip */ - u32 loaded_fw = REG_RD(bp, XSEM_REG_PRAM); - - DP(BNX2X_MSG_SP, "loaded fw %x, my fw %x", - loaded_fw, my_fw); - /* abort nic load if version mismatch */ - if (my_fw != loaded_fw) { - BNX2X_ERR("bnx2x with FW %x already loaded, " - "which mismatches my %x FW. aborting", - loaded_fw, my_fw); + if (!bnx2x_test_firmware_version(bp, true)) { rc = -EBUSY; LOAD_ERROR_EXIT(bp, load_error2); } diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h index 8b163388659a..5c27454d2ec2 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h @@ -431,6 +431,9 @@ void bnx2x_panic_dump(struct bnx2x *bp); void bnx2x_fw_dump_lvl(struct bnx2x *bp, const char *lvl); +/* validate currect fw is loaded */ +bool bnx2x_test_firmware_version(struct bnx2x *bp, bool is_err); + /* dev_close main block */ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h index 5d71b7d43237..dbff5915b81a 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h @@ -1251,6 +1251,9 @@ struct drv_func_mb { #define DRV_MSG_CODE_LINK_STATUS_CHANGED 0x01000000 + #define DRV_MSG_CODE_INITIATE_FLR 0x02000000 + #define REQ_BC_VER_4_INITIATE_FLR 0x00070213 + #define BIOS_MSG_CODE_LIC_CHALLENGE 0xff010000 #define BIOS_MSG_CODE_LIC_RESPONSE 0xff020000 #define BIOS_MSG_CODE_VIRT_MAC_PRIM 0xff030000 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c index beb4cdbdb6e1..efa557b76ac7 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c @@ -35,7 +35,6 @@ #define ETH_MAX_PACKET_SIZE 1500 #define ETH_MAX_JUMBO_PACKET_SIZE 9600 #define MDIO_ACCESS_TIMEOUT 1000 -#define BMAC_CONTROL_RX_ENABLE 2 #define WC_LANE_MAX 4 #define I2C_SWITCH_WIDTH 2 #define I2C_BSC0 0 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h index 7ba557a610da..763535ee4832 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h @@ -89,6 +89,8 @@ #define PFC_BRB_FULL_LB_XON_THRESHOLD 250 #define MAXVAL(a, b) (((a) > (b)) ? (a) : (b)) + +#define BMAC_CONTROL_RX_ENABLE 2 /***********************************************************/ /* Structs */ /***********************************************************/ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index f7f9aa807264..e077d2508727 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -52,6 +52,7 @@ #include #include #include +#include #include #include @@ -211,6 +212,10 @@ static DEFINE_PCI_DEVICE_TABLE(bnx2x_pci_tbl) = { MODULE_DEVICE_TABLE(pci, bnx2x_pci_tbl); +/* Global resources for unloading a previously loaded device */ +#define BNX2X_PREV_WAIT_NEEDED 1 +static DEFINE_SEMAPHORE(bnx2x_prev_sem); +static LIST_HEAD(bnx2x_prev_list); /**************************************************************************** * General service functions ****************************************************************************/ @@ -8812,109 +8817,371 @@ static inline void bnx2x_undi_int_disable(struct bnx2x *bp) bnx2x_undi_int_disable_e1h(bp); } -static void __devinit bnx2x_undi_unload(struct bnx2x *bp) +static void __devinit bnx2x_prev_unload_close_mac(struct bnx2x *bp) { - u32 val; + u32 val, base_addr, offset, mask, reset_reg; + bool mac_stopped = false; + u8 port = BP_PORT(bp); - /* possibly another driver is trying to reset the chip */ - bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_RESET); + reset_reg = REG_RD(bp, MISC_REG_RESET_REG_2); - /* check if doorbell queue is reset */ - if (REG_RD(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET) - & MISC_REGISTERS_RESET_REG_1_RST_DORQ) { + if (!CHIP_IS_E3(bp)) { + val = REG_RD(bp, NIG_REG_BMAC0_REGS_OUT_EN + port * 4); + mask = MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port; + if ((mask & reset_reg) && val) { + u32 wb_data[2]; + BNX2X_DEV_INFO("Disable bmac Rx\n"); + base_addr = BP_PORT(bp) ? NIG_REG_INGRESS_BMAC1_MEM + : NIG_REG_INGRESS_BMAC0_MEM; + offset = CHIP_IS_E2(bp) ? BIGMAC2_REGISTER_BMAC_CONTROL + : BIGMAC_REGISTER_BMAC_CONTROL; - /* - * Check if it is the UNDI driver + /* + * use rd/wr since we cannot use dmae. This is safe + * since MCP won't access the bus due to the request + * to unload, and no function on the path can be + * loaded at this time. + */ + wb_data[0] = REG_RD(bp, base_addr + offset); + wb_data[1] = REG_RD(bp, base_addr + offset + 0x4); + wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE; + REG_WR(bp, base_addr + offset, wb_data[0]); + REG_WR(bp, base_addr + offset + 0x4, wb_data[1]); + + } + BNX2X_DEV_INFO("Disable emac Rx\n"); + REG_WR(bp, NIG_REG_NIG_EMAC0_EN + BP_PORT(bp)*4, 0); + + mac_stopped = true; + } else { + if (reset_reg & MISC_REGISTERS_RESET_REG_2_XMAC) { + BNX2X_DEV_INFO("Disable xmac Rx\n"); + base_addr = BP_PORT(bp) ? GRCBASE_XMAC1 : GRCBASE_XMAC0; + val = REG_RD(bp, base_addr + XMAC_REG_PFC_CTRL_HI); + REG_WR(bp, base_addr + XMAC_REG_PFC_CTRL_HI, + val & ~(1 << 1)); + REG_WR(bp, base_addr + XMAC_REG_PFC_CTRL_HI, + val | (1 << 1)); + REG_WR(bp, base_addr + XMAC_REG_CTRL, 0); + mac_stopped = true; + } + mask = MISC_REGISTERS_RESET_REG_2_UMAC0 << port; + if (mask & reset_reg) { + BNX2X_DEV_INFO("Disable umac Rx\n"); + base_addr = BP_PORT(bp) ? GRCBASE_UMAC1 : GRCBASE_UMAC0; + REG_WR(bp, base_addr + UMAC_REG_COMMAND_CONFIG, 0); + mac_stopped = true; + } + } + + if (mac_stopped) + msleep(20); + +} + +#define BNX2X_PREV_UNDI_PROD_ADDR(p) (BAR_TSTRORM_INTMEM + 0x1508 + ((p) << 4)) +#define BNX2X_PREV_UNDI_RCQ(val) ((val) & 0xffff) +#define BNX2X_PREV_UNDI_BD(val) ((val) >> 16 & 0xffff) +#define BNX2X_PREV_UNDI_PROD(rcq, bd) ((bd) << 16 | (rcq)) + +static void __devinit bnx2x_prev_unload_undi_inc(struct bnx2x *bp, u8 port, + u8 inc) +{ + u16 rcq, bd; + u32 tmp_reg = REG_RD(bp, BNX2X_PREV_UNDI_PROD_ADDR(port)); + + rcq = BNX2X_PREV_UNDI_RCQ(tmp_reg) + inc; + bd = BNX2X_PREV_UNDI_BD(tmp_reg) + inc; + + tmp_reg = BNX2X_PREV_UNDI_PROD(rcq, bd); + REG_WR(bp, BNX2X_PREV_UNDI_PROD_ADDR(port), tmp_reg); + + BNX2X_DEV_INFO("UNDI producer [%d] rings bd -> 0x%04x, rcq -> 0x%04x\n", + port, bd, rcq); +} + +static int __devinit bnx2x_prev_mcp_done(struct bnx2x *bp) +{ + u32 rc = bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE, 0); + if (!rc) { + BNX2X_ERR("MCP response failure, aborting\n"); + return -EBUSY; + } + + return 0; +} + +static bool __devinit bnx2x_prev_is_path_marked(struct bnx2x *bp) +{ + struct bnx2x_prev_path_list *tmp_list; + int rc = false; + + if (down_trylock(&bnx2x_prev_sem)) + return false; + + list_for_each_entry(tmp_list, &bnx2x_prev_list, list) { + if (PCI_SLOT(bp->pdev->devfn) == tmp_list->slot && + bp->pdev->bus->number == tmp_list->bus && + BP_PATH(bp) == tmp_list->path) { + rc = true; + BNX2X_DEV_INFO("Path %d was already cleaned from previous drivers\n", + BP_PATH(bp)); + break; + } + } + + up(&bnx2x_prev_sem); + + return rc; +} + +static int __devinit bnx2x_prev_mark_path(struct bnx2x *bp) +{ + struct bnx2x_prev_path_list *tmp_list; + int rc; + + tmp_list = (struct bnx2x_prev_path_list *) + kmalloc(sizeof(struct bnx2x_prev_path_list), GFP_KERNEL); + if (!tmp_list) { + BNX2X_ERR("Failed to allocate 'bnx2x_prev_path_list'\n"); + return -ENOMEM; + } + + tmp_list->bus = bp->pdev->bus->number; + tmp_list->slot = PCI_SLOT(bp->pdev->devfn); + tmp_list->path = BP_PATH(bp); + + rc = down_interruptible(&bnx2x_prev_sem); + if (rc) { + BNX2X_ERR("Received %d when tried to take lock\n", rc); + kfree(tmp_list); + } else { + BNX2X_DEV_INFO("Marked path [%d] - finished previous unload\n", + BP_PATH(bp)); + list_add(&tmp_list->list, &bnx2x_prev_list); + up(&bnx2x_prev_sem); + } + + return rc; +} + +static bool __devinit bnx2x_can_flr(struct bnx2x *bp) +{ + int pos; + u32 cap; + struct pci_dev *dev = bp->pdev; + + pos = pci_pcie_cap(dev); + if (!pos) + return false; + + pci_read_config_dword(dev, pos + PCI_EXP_DEVCAP, &cap); + if (!(cap & PCI_EXP_DEVCAP_FLR)) + return false; + + return true; +} + +static int __devinit bnx2x_do_flr(struct bnx2x *bp) +{ + int i, pos; + u16 status; + struct pci_dev *dev = bp->pdev; + + /* probe the capability first */ + if (bnx2x_can_flr(bp)) + return -ENOTTY; + + pos = pci_pcie_cap(dev); + if (!pos) + return -ENOTTY; + + /* Wait for Transaction Pending bit clean */ + for (i = 0; i < 4; i++) { + if (i) + msleep((1 << (i - 1)) * 100); + + pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, &status); + if (!(status & PCI_EXP_DEVSTA_TRPND)) + goto clear; + } + + dev_err(&dev->dev, + "transaction is not cleared; proceeding with reset anyway\n"); + +clear: + if (bp->common.bc_ver < REQ_BC_VER_4_INITIATE_FLR) { + BNX2X_ERR("FLR not supported by BC_VER: 0x%x\n", + bp->common.bc_ver); + return -EINVAL; + } + + bnx2x_fw_command(bp, DRV_MSG_CODE_INITIATE_FLR, 0); + + return 0; +} + +static int __devinit bnx2x_prev_unload_uncommon(struct bnx2x *bp) +{ + int rc; + + BNX2X_DEV_INFO("Uncommon unload Flow\n"); + + /* Test if previous unload process was already finished for this path */ + if (bnx2x_prev_is_path_marked(bp)) + return bnx2x_prev_mcp_done(bp); + + /* If function has FLR capabilities, and existing FW version matches + * the one required, then FLR will be sufficient to clean any residue + * left by previous driver + */ + if (bnx2x_test_firmware_version(bp, false) && bnx2x_can_flr(bp)) + return bnx2x_do_flr(bp); + + /* Close the MCP request, return failure*/ + rc = bnx2x_prev_mcp_done(bp); + if (!rc) + rc = BNX2X_PREV_WAIT_NEEDED; + + return rc; +} + +static int __devinit bnx2x_prev_unload_common(struct bnx2x *bp) +{ + u32 reset_reg, tmp_reg = 0, rc; + /* It is possible a previous function received 'common' answer, + * but hasn't loaded yet, therefore creating a scenario of + * multiple functions receiving 'common' on the same path. + */ + BNX2X_DEV_INFO("Common unload Flow\n"); + + if (bnx2x_prev_is_path_marked(bp)) + return bnx2x_prev_mcp_done(bp); + + reset_reg = REG_RD(bp, MISC_REG_RESET_REG_1); + + /* Reset should be performed after BRB is emptied */ + if (reset_reg & MISC_REGISTERS_RESET_REG_1_RST_BRB1) { + u32 timer_count = 1000; + bool prev_undi = false; + + /* Close the MAC Rx to prevent BRB from filling up */ + bnx2x_prev_unload_close_mac(bp); + + /* Check if the UNDI driver was previously loaded * UNDI driver initializes CID offset for normal bell to 0x7 */ - val = REG_RD(bp, DORQ_REG_NORM_CID_OFST); - if (val == 0x7) { - u32 reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS; - /* save our pf_num */ - int orig_pf_num = bp->pf_num; - int port; - u32 swap_en, swap_val, value; - - /* clear the UNDI indication */ - REG_WR(bp, DORQ_REG_NORM_CID_OFST, 0); - - BNX2X_DEV_INFO("UNDI is active! reset device\n"); - - /* try unload UNDI on port 0 */ - bp->pf_num = 0; - bp->fw_seq = - (SHMEM_RD(bp, func_mb[bp->pf_num].drv_mb_header) & - DRV_MSG_SEQ_NUMBER_MASK); - reset_code = bnx2x_fw_command(bp, reset_code, 0); - - /* if UNDI is loaded on the other port */ - if (reset_code != FW_MSG_CODE_DRV_UNLOAD_COMMON) { - - /* send "DONE" for previous unload */ - bnx2x_fw_command(bp, - DRV_MSG_CODE_UNLOAD_DONE, 0); - - /* unload UNDI on port 1 */ - bp->pf_num = 1; - bp->fw_seq = - (SHMEM_RD(bp, func_mb[bp->pf_num].drv_mb_header) & - DRV_MSG_SEQ_NUMBER_MASK); - reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS; - - bnx2x_fw_command(bp, reset_code, 0); + reset_reg = REG_RD(bp, MISC_REG_RESET_REG_1); + if (reset_reg & MISC_REGISTERS_RESET_REG_1_RST_DORQ) { + tmp_reg = REG_RD(bp, DORQ_REG_NORM_CID_OFST); + if (tmp_reg == 0x7) { + BNX2X_DEV_INFO("UNDI previously loaded\n"); + prev_undi = true; + /* clear the UNDI indication */ + REG_WR(bp, DORQ_REG_NORM_CID_OFST, 0); } + } + /* wait until BRB is empty */ + tmp_reg = REG_RD(bp, BRB1_REG_NUM_OF_FULL_BLOCKS); + while (timer_count) { + u32 prev_brb = tmp_reg; - bnx2x_undi_int_disable(bp); - port = BP_PORT(bp); - - /* close input traffic and wait for it */ - /* Do not rcv packets to BRB */ - REG_WR(bp, (port ? NIG_REG_LLH1_BRB1_DRV_MASK : - NIG_REG_LLH0_BRB1_DRV_MASK), 0x0); - /* Do not direct rcv packets that are not for MCP to - * the BRB */ - REG_WR(bp, (port ? NIG_REG_LLH1_BRB1_NOT_MCP : - NIG_REG_LLH0_BRB1_NOT_MCP), 0x0); - /* clear AEU */ - REG_WR(bp, (port ? MISC_REG_AEU_MASK_ATTN_FUNC_1 : - MISC_REG_AEU_MASK_ATTN_FUNC_0), 0); - msleep(10); - - /* save NIG port swap info */ - swap_val = REG_RD(bp, NIG_REG_PORT_SWAP); - swap_en = REG_RD(bp, NIG_REG_STRAP_OVERRIDE); - /* reset device */ - REG_WR(bp, - GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR, - 0xd3ffffff); - - value = 0x1400; - if (CHIP_IS_E3(bp)) { - value |= MISC_REGISTERS_RESET_REG_2_MSTAT0; - value |= MISC_REGISTERS_RESET_REG_2_MSTAT1; - } + tmp_reg = REG_RD(bp, BRB1_REG_NUM_OF_FULL_BLOCKS); + if (!tmp_reg) + break; - REG_WR(bp, - GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, - value); + BNX2X_DEV_INFO("BRB still has 0x%08x\n", tmp_reg); - /* take the NIG out of reset and restore swap values */ - REG_WR(bp, - GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, - MISC_REGISTERS_RESET_REG_1_RST_NIG); - REG_WR(bp, NIG_REG_PORT_SWAP, swap_val); - REG_WR(bp, NIG_REG_STRAP_OVERRIDE, swap_en); + /* reset timer as long as BRB actually gets emptied */ + if (prev_brb > tmp_reg) + timer_count = 1000; + else + timer_count--; - /* send unload done to the MCP */ - bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE, 0); + /* If UNDI resides in memory, manually increment it */ + if (prev_undi) + bnx2x_prev_unload_undi_inc(bp, BP_PORT(bp), 1); - /* restore our func and fw_seq */ - bp->pf_num = orig_pf_num; + udelay(10); } + + if (!timer_count) + BNX2X_ERR("Failed to empty BRB, hope for the best\n"); + } - /* now it's safe to release the lock */ - bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_RESET); + /* No packets are in the pipeline, path is ready for reset */ + bnx2x_reset_common(bp); + + rc = bnx2x_prev_mark_path(bp); + if (rc) { + bnx2x_prev_mcp_done(bp); + return rc; + } + + return bnx2x_prev_mcp_done(bp); +} + +static int __devinit bnx2x_prev_unload(struct bnx2x *bp) +{ + int time_counter = 10; + u32 rc, fw, hw_lock_reg, hw_lock_val; + BNX2X_DEV_INFO("Entering Previous Unload Flow\n"); + + /* Release previously held locks */ + hw_lock_reg = (BP_FUNC(bp) <= 5) ? + (MISC_REG_DRIVER_CONTROL_1 + BP_FUNC(bp) * 8) : + (MISC_REG_DRIVER_CONTROL_7 + (BP_FUNC(bp) - 6) * 8); + + hw_lock_val = (REG_RD(bp, hw_lock_reg)); + if (hw_lock_val) { + if (hw_lock_val & HW_LOCK_RESOURCE_NVRAM) { + BNX2X_DEV_INFO("Release Previously held NVRAM lock\n"); + REG_WR(bp, MCP_REG_MCPR_NVM_SW_ARB, + (MCPR_NVM_SW_ARB_ARB_REQ_CLR1 << BP_PORT(bp))); + } + + BNX2X_DEV_INFO("Release Previously held hw lock\n"); + REG_WR(bp, hw_lock_reg, 0xffffffff); + } else + BNX2X_DEV_INFO("No need to release hw/nvram locks\n"); + + if (MCPR_ACCESS_LOCK_LOCK & REG_RD(bp, MCP_REG_MCPR_ACCESS_LOCK)) { + BNX2X_DEV_INFO("Release previously held alr\n"); + REG_WR(bp, MCP_REG_MCPR_ACCESS_LOCK, 0); + } + + + do { + /* Lock MCP using an unload request */ + fw = bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS, 0); + if (!fw) { + BNX2X_ERR("MCP response failure, aborting\n"); + rc = -EBUSY; + break; + } + + if (fw == FW_MSG_CODE_DRV_UNLOAD_COMMON) { + rc = bnx2x_prev_unload_common(bp); + break; + } + + /* non-common reply from MCP night require looping */ + rc = bnx2x_prev_unload_uncommon(bp); + if (rc != BNX2X_PREV_WAIT_NEEDED) + break; + + msleep(20); + } while (--time_counter); + + if (!time_counter || rc) { + BNX2X_ERR("Failed unloading previous driver, aborting\n"); + rc = -EBUSY; + } + + BNX2X_DEV_INFO("Finished Previous Unload Flow [%d]\n", rc); + + return rc; } static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp) @@ -10100,8 +10367,16 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp) func = BP_FUNC(bp); /* need to reset chip if undi was active */ - if (!BP_NOMCP(bp)) - bnx2x_undi_unload(bp); + if (!BP_NOMCP(bp)) { + /* init fw_seq */ + bp->fw_seq = + SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_mb_header) & + DRV_MSG_SEQ_NUMBER_MASK; + BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq); + + bnx2x_prev_unload(bp); + } + if (CHIP_REV_IS_FPGA(bp)) dev_err(&bp->pdev->dev, "FPGA detected\n"); @@ -11431,9 +11706,18 @@ static int __init bnx2x_init(void) static void __exit bnx2x_cleanup(void) { + struct list_head *pos, *q; pci_unregister_driver(&bnx2x_pci_driver); destroy_workqueue(bnx2x_wq); + + /* Free globablly allocated resources */ + list_for_each_safe(pos, q, &bnx2x_prev_list) { + struct bnx2x_prev_path_list *tmp = + list_entry(pos, struct bnx2x_prev_path_list, list); + list_del(pos); + kfree(tmp); + } } void bnx2x_notify_link_changed(struct bnx2x *bp) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h index fd7fb4581849..ab0a250f95fa 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h @@ -987,6 +987,7 @@ * clear; 1 = set. Data valid only in addresses 0-4. all the rest are zero. */ #define IGU_REG_WRITE_DONE_PENDING 0x130480 #define MCP_A_REG_MCPR_SCRATCH 0x3a0000 +#define MCP_REG_MCPR_ACCESS_LOCK 0x8009c #define MCP_REG_MCPR_CPU_PROGRAM_COUNTER 0x8501c #define MCP_REG_MCPR_GP_INPUTS 0x800c0 #define MCP_REG_MCPR_GP_OENABLE 0x800c8 @@ -1686,6 +1687,7 @@ [10] rst_dbg; [11] rst_misc_core; [12] rst_dbue (UART); [13] Pci_resetmdio_n; [14] rst_emac0_hard_core; [15] rst_emac1_hard_core; 16] rst_pxp_rq_rd_wr; 31:17] reserved */ +#define MISC_REG_RESET_REG_1 0xa580 #define MISC_REG_RESET_REG_2 0xa590 /* [RW 20] 20 bit GRC address where the scratch-pad of the MCP that is shared with the driver resides */ @@ -5606,6 +5608,7 @@ /* [RC 32] Parity register #0 read clear */ #define XSEM_REG_XSEM_PRTY_STS_CLR_0 0x280128 #define XSEM_REG_XSEM_PRTY_STS_CLR_1 0x280138 +#define MCPR_ACCESS_LOCK_LOCK (1L<<31) #define MCPR_NVM_ACCESS_ENABLE_EN (1L<<0) #define MCPR_NVM_ACCESS_ENABLE_WR_EN (1L<<1) #define MCPR_NVM_ADDR_NVM_ADDR_VALUE (0xffffffL<<0) @@ -5732,6 +5735,7 @@ #define MISC_REGISTERS_GPIO_PORT_SHIFT 4 #define MISC_REGISTERS_GPIO_SET_POS 8 #define MISC_REGISTERS_RESET_REG_1_CLEAR 0x588 +#define MISC_REGISTERS_RESET_REG_1_RST_BRB1 (0x1<<0) #define MISC_REGISTERS_RESET_REG_1_RST_DORQ (0x1<<19) #define MISC_REGISTERS_RESET_REG_1_RST_HC (0x1<<29) #define MISC_REGISTERS_RESET_REG_1_RST_NIG (0x1<<7) -- cgit v1.2.3 From c54e9bd38a06babf94fd45e5f1df9a1109e12818 Mon Sep 17 00:00:00 2001 From: Dmitry Kravkov Date: Mon, 26 Mar 2012 21:08:55 +0000 Subject: bnx2x: fix vector traveling while looking for an empty entry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the bug that may prevent from mac to be configured, while there is an empty slot for it. Reported-by: Maciej Żenczykowski Signed-off-by: Dmitry Kravkov Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c index 3f52fadee3ed..513573321625 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c @@ -3847,7 +3847,7 @@ static bool bnx2x_credit_pool_get_entry( continue; /* If we've got here we are going to find a free entry */ - for (idx = vec * BNX2X_POOL_VEC_SIZE, i = 0; + for (idx = vec * BIT_VEC64_ELEM_SZ, i = 0; i < BIT_VEC64_ELEM_SZ; idx++, i++) if (BIT_VEC64_TEST_BIT(o->pool_mirror, idx)) { -- cgit v1.2.3 From 819a100846295461bc0f1bfcb8e5ab11c1bc4cdb Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 26 Mar 2012 21:20:48 +0000 Subject: mISDN: array underflow in open_bchannel() There are two channels here. User space starts counting channels at one but in the kernel we start at zero. If the user passes in a zero channel that's invalid and could lead to memory corruption. Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- drivers/isdn/hardware/mISDN/avmfritz.c | 2 +- drivers/isdn/hardware/mISDN/hfcpci.c | 2 +- drivers/isdn/hardware/mISDN/hfcsusb.c | 2 +- drivers/isdn/hardware/mISDN/mISDNipac.c | 2 +- drivers/isdn/hardware/mISDN/mISDNisar.c | 2 +- drivers/isdn/hardware/mISDN/netjet.c | 2 +- drivers/isdn/hardware/mISDN/w6692.c | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/hardware/mISDN/avmfritz.c b/drivers/isdn/hardware/mISDN/avmfritz.c index 05ed4d0cb18b..c0b8c960ee3f 100644 --- a/drivers/isdn/hardware/mISDN/avmfritz.c +++ b/drivers/isdn/hardware/mISDN/avmfritz.c @@ -891,7 +891,7 @@ open_bchannel(struct fritzcard *fc, struct channel_req *rq) { struct bchannel *bch; - if (rq->adr.channel > 2) + if (rq->adr.channel == 0 || rq->adr.channel > 2) return -EINVAL; if (rq->protocol == ISDN_P_NONE) return -EINVAL; diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index d055ae7fa040..e2c83a2d7691 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c @@ -1962,7 +1962,7 @@ open_bchannel(struct hfc_pci *hc, struct channel_req *rq) { struct bchannel *bch; - if (rq->adr.channel > 2) + if (rq->adr.channel == 0 || rq->adr.channel > 2) return -EINVAL; if (rq->protocol == ISDN_P_NONE) return -EINVAL; diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c index 602338734634..8cde2a0538ab 100644 --- a/drivers/isdn/hardware/mISDN/hfcsusb.c +++ b/drivers/isdn/hardware/mISDN/hfcsusb.c @@ -486,7 +486,7 @@ open_bchannel(struct hfcsusb *hw, struct channel_req *rq) { struct bchannel *bch; - if (rq->adr.channel > 2) + if (rq->adr.channel == 0 || rq->adr.channel > 2) return -EINVAL; if (rq->protocol == ISDN_P_NONE) return -EINVAL; diff --git a/drivers/isdn/hardware/mISDN/mISDNipac.c b/drivers/isdn/hardware/mISDN/mISDNipac.c index b47e9bed2185..884369f09cad 100644 --- a/drivers/isdn/hardware/mISDN/mISDNipac.c +++ b/drivers/isdn/hardware/mISDN/mISDNipac.c @@ -1506,7 +1506,7 @@ open_bchannel(struct ipac_hw *ipac, struct channel_req *rq) { struct bchannel *bch; - if (rq->adr.channel > 2) + if (rq->adr.channel == 0 || rq->adr.channel > 2) return -EINVAL; if (rq->protocol == ISDN_P_NONE) return -EINVAL; diff --git a/drivers/isdn/hardware/mISDN/mISDNisar.c b/drivers/isdn/hardware/mISDN/mISDNisar.c index 10446ab404b5..9a6da6edcfa8 100644 --- a/drivers/isdn/hardware/mISDN/mISDNisar.c +++ b/drivers/isdn/hardware/mISDN/mISDNisar.c @@ -1670,7 +1670,7 @@ isar_open(struct isar_hw *isar, struct channel_req *rq) { struct bchannel *bch; - if (rq->adr.channel > 2) + if (rq->adr.channel == 0 || rq->adr.channel > 2) return -EINVAL; if (rq->protocol == ISDN_P_NONE) return -EINVAL; diff --git a/drivers/isdn/hardware/mISDN/netjet.c b/drivers/isdn/hardware/mISDN/netjet.c index dd6de9f7a8a3..c726e09d0981 100644 --- a/drivers/isdn/hardware/mISDN/netjet.c +++ b/drivers/isdn/hardware/mISDN/netjet.c @@ -860,7 +860,7 @@ open_bchannel(struct tiger_hw *card, struct channel_req *rq) { struct bchannel *bch; - if (rq->adr.channel > 2) + if (rq->adr.channel == 0 || rq->adr.channel > 2) return -EINVAL; if (rq->protocol == ISDN_P_NONE) return -EINVAL; diff --git a/drivers/isdn/hardware/mISDN/w6692.c b/drivers/isdn/hardware/mISDN/w6692.c index 7f1e7ba75cd1..2183357f0799 100644 --- a/drivers/isdn/hardware/mISDN/w6692.c +++ b/drivers/isdn/hardware/mISDN/w6692.c @@ -1015,7 +1015,7 @@ open_bchannel(struct w6692_hw *card, struct channel_req *rq) { struct bchannel *bch; - if (rq->adr.channel > 2) + if (rq->adr.channel == 0 || rq->adr.channel > 2) return -EINVAL; if (rq->protocol == ISDN_P_NONE) return -EINVAL; -- cgit v1.2.3 From 09e79d6ea65d66e0a5e9ba76865320e74832dc7c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 26 Mar 2012 22:52:00 +0000 Subject: eql: dont rely on HZ=100 HZ is more likely to be 1000 these days. timer handlers are run from softirq, no need to disable bh skb priority 1 is TC_PRIO_FILLER Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/eql.c | 7 ++++--- include/linux/if_eql.h | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/eql.c b/drivers/net/eql.c index a59cf961a436..f219d38acf58 100644 --- a/drivers/net/eql.c +++ b/drivers/net/eql.c @@ -125,6 +125,7 @@ #include #include #include +#include #include @@ -143,7 +144,7 @@ static void eql_timer(unsigned long param) equalizer_t *eql = (equalizer_t *) param; struct list_head *this, *tmp, *head; - spin_lock_bh(&eql->queue.lock); + spin_lock(&eql->queue.lock); head = &eql->queue.all_slaves; list_for_each_safe(this, tmp, head) { slave_t *slave = list_entry(this, slave_t, list); @@ -157,7 +158,7 @@ static void eql_timer(unsigned long param) } } - spin_unlock_bh(&eql->queue.lock); + spin_unlock(&eql->queue.lock); eql->timer.expires = jiffies + EQL_DEFAULT_RESCHED_IVAL; add_timer(&eql->timer); @@ -341,7 +342,7 @@ static netdev_tx_t eql_slave_xmit(struct sk_buff *skb, struct net_device *dev) struct net_device *slave_dev = slave->dev; skb->dev = slave_dev; - skb->priority = 1; + skb->priority = TC_PRIO_FILLER; slave->bytes_queued += skb->len; dev_queue_xmit(skb); dev->stats.tx_packets++; diff --git a/include/linux/if_eql.h b/include/linux/if_eql.h index 79c4f268410d..18a5d02a8644 100644 --- a/include/linux/if_eql.h +++ b/include/linux/if_eql.h @@ -22,7 +22,7 @@ #define EQL_DEFAULT_SLAVE_PRIORITY 28800 #define EQL_DEFAULT_MAX_SLAVES 4 #define EQL_DEFAULT_MTU 576 -#define EQL_DEFAULT_RESCHED_IVAL 100 +#define EQL_DEFAULT_RESCHED_IVAL HZ #define EQL_ENSLAVE (SIOCDEVPRIVATE) #define EQL_EMANCIPATE (SIOCDEVPRIVATE + 1) -- cgit v1.2.3 From 21dcda6083a0573686acabca39b3f92ba032d333 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 27 Mar 2012 03:04:02 +0000 Subject: f_phonet: fix skb truesize underestimation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now skb_add_rx_frag() has a truesize parameter, we can fix f_phonet to properly account truesize of each fragment : a full page. Signed-off-by: Eric Dumazet Cc: Felipe Balbi Cc: Greg Kroah-Hartman Cc: Rémi Denis-Courmont Signed-off-by: David S. Miller --- drivers/usb/gadget/f_phonet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c index 85a5cebe96b3..965a6293206a 100644 --- a/drivers/usb/gadget/f_phonet.c +++ b/drivers/usb/gadget/f_phonet.c @@ -345,7 +345,7 @@ static void pn_rx_complete(struct usb_ep *ep, struct usb_request *req) } skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, - skb->len <= 1, req->actual, req->actual); + skb->len <= 1, req->actual, PAGE_SIZE); page = NULL; if (req->actual < req->length) { /* Last fragment */ -- cgit v1.2.3 From 094b5855bf37eae4b297bc47bb5bc5454f1f6fab Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 27 Mar 2012 03:17:26 +0000 Subject: cdc-phonet: fix skb truesize underestimation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now skb_add_rx_frag() has a truesize parameter, we can fix cdc-phonet to properly account truesize of each fragment : a full page. Signed-off-by: Eric Dumazet Cc: Felipe Balbi Cc: Greg Kroah-Hartman Cc: Rémi Denis-Courmont Acked-by: Rémi Denis-Courmont Signed-off-by: David S. Miller --- drivers/net/usb/cdc-phonet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/cdc-phonet.c b/drivers/net/usb/cdc-phonet.c index 3886b30ed373..3e41b00c6806 100644 --- a/drivers/net/usb/cdc-phonet.c +++ b/drivers/net/usb/cdc-phonet.c @@ -165,13 +165,13 @@ static void rx_complete(struct urb *req) memcpy(skb_put(skb, 1), page_address(page), 1); skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, 1, req->actual_length, - req->actual_length); + PAGE_SIZE); page = NULL; } } else { skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, 0, req->actual_length, - req->actual_length); + PAGE_SIZE); page = NULL; } if (req->actual_length < PAGE_SIZE) -- cgit v1.2.3 From b3f4d5990bfc8b060e5010c1464789fca1f4c5b4 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Tue, 13 Mar 2012 06:04:20 +0000 Subject: intel: make wired ethernet driver message level consistent (rev2) Dan Carpenter noticed that ixgbevf initial default was different than the rest. But the problem is broader than that, only one Intel driver (ixgb) was doing it almost right. The convention for default debug level should be consistent among Intel drivers and follow established convention. Signed-off-by: Stephen Hemminger Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000/e1000_main.c | 5 +++-- drivers/net/ethernet/intel/e1000e/netdev.c | 7 ++++++- drivers/net/ethernet/intel/igb/igb_main.c | 7 ++++++- drivers/net/ethernet/intel/igbvf/netdev.c | 7 ++++++- drivers/net/ethernet/intel/ixgb/ixgb_main.c | 6 +++--- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 9 ++++++--- drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 7 +++++-- 7 files changed, 35 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c index bcba9cfe3d03..4348b6fd44fa 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_main.c +++ b/drivers/net/ethernet/intel/e1000/e1000_main.c @@ -217,7 +217,8 @@ MODULE_DESCRIPTION("Intel(R) PRO/1000 Network Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); -static int debug = NETIF_MSG_DRV | NETIF_MSG_PROBE; +#define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV|NETIF_MSG_PROBE|NETIF_MSG_LINK) +static int debug = -1; module_param(debug, int, 0); MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); @@ -981,7 +982,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev, adapter = netdev_priv(netdev); adapter->netdev = netdev; adapter->pdev = pdev; - adapter->msg_enable = (1 << debug) - 1; + adapter->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE); adapter->bars = bars; adapter->need_ioport = need_ioport; diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 7152eb11b7b9..2c38a65ade87 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -60,6 +60,11 @@ char e1000e_driver_name[] = "e1000e"; const char e1000e_driver_version[] = DRV_VERSION; +#define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV|NETIF_MSG_PROBE|NETIF_MSG_LINK) +static int debug = -1; +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); + static void e1000e_disable_aspm(struct pci_dev *pdev, u16 state); static const struct e1000_info *e1000_info_tbl[] = { @@ -6172,7 +6177,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev, adapter->hw.adapter = adapter; adapter->hw.mac.type = ei->mac; adapter->max_hw_frame_size = ei->max_hw_frame_size; - adapter->msg_enable = (1 << NETIF_MSG_DRV | NETIF_MSG_PROBE) - 1; + adapter->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE); mmio_start = pci_resource_start(pdev, 0); mmio_len = pci_resource_len(pdev, 0); diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index c4902411d749..5ec31598ee47 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -238,6 +238,11 @@ MODULE_DESCRIPTION("Intel(R) Gigabit Ethernet Network Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); +#define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV|NETIF_MSG_PROBE|NETIF_MSG_LINK) +static int debug = -1; +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); + struct igb_reg_info { u32 ofs; char *name; @@ -1893,7 +1898,7 @@ static int __devinit igb_probe(struct pci_dev *pdev, adapter->pdev = pdev; hw = &adapter->hw; hw->back = adapter; - adapter->msg_enable = NETIF_MSG_DRV | NETIF_MSG_PROBE; + adapter->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE); mmio_start = pci_resource_start(pdev, 0); mmio_len = pci_resource_len(pdev, 0); diff --git a/drivers/net/ethernet/intel/igbvf/netdev.c b/drivers/net/ethernet/intel/igbvf/netdev.c index 217c143686d2..d61ca2a732f0 100644 --- a/drivers/net/ethernet/intel/igbvf/netdev.c +++ b/drivers/net/ethernet/intel/igbvf/netdev.c @@ -55,6 +55,11 @@ static const char igbvf_driver_string[] = static const char igbvf_copyright[] = "Copyright (c) 2009 - 2012 Intel Corporation."; +#define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV|NETIF_MSG_PROBE|NETIF_MSG_LINK) +static int debug = -1; +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); + static int igbvf_poll(struct napi_struct *napi, int budget); static void igbvf_reset(struct igbvf_adapter *); static void igbvf_set_interrupt_capability(struct igbvf_adapter *); @@ -2649,7 +2654,7 @@ static int __devinit igbvf_probe(struct pci_dev *pdev, adapter->flags = ei->flags; adapter->hw.back = adapter; adapter->hw.mac.type = ei->mac; - adapter->msg_enable = (1 << NETIF_MSG_DRV | NETIF_MSG_PROBE) - 1; + adapter->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE); /* PCI config space info */ diff --git a/drivers/net/ethernet/intel/ixgb/ixgb_main.c b/drivers/net/ethernet/intel/ixgb/ixgb_main.c index 82aaa792cbf3..5fce363d810a 100644 --- a/drivers/net/ethernet/intel/ixgb/ixgb_main.c +++ b/drivers/net/ethernet/intel/ixgb/ixgb_main.c @@ -134,8 +134,8 @@ MODULE_DESCRIPTION("Intel(R) PRO/10GbE Network Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); -#define DEFAULT_DEBUG_LEVEL_SHIFT 3 -static int debug = DEFAULT_DEBUG_LEVEL_SHIFT; +#define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV|NETIF_MSG_PROBE|NETIF_MSG_LINK) +static int debug = -1; module_param(debug, int, 0); MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); @@ -442,7 +442,7 @@ ixgb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) adapter->netdev = netdev; adapter->pdev = pdev; adapter->hw.back = adapter; - adapter->msg_enable = netif_msg_init(debug, DEFAULT_DEBUG_LEVEL_SHIFT); + adapter->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE); adapter->hw.hw_addr = pci_ioremap_bar(pdev, BAR_0); if (!adapter->hw.hw_addr) { diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 398fc223cab9..6dbad2b2d0b5 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -141,13 +141,16 @@ module_param(allow_unsupported_sfp, uint, 0); MODULE_PARM_DESC(allow_unsupported_sfp, "Allow unsupported and untested SFP+ modules on 82599-based adapters"); +#define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV|NETIF_MSG_PROBE|NETIF_MSG_LINK) +static int debug = -1; +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); + MODULE_AUTHOR("Intel Corporation, "); MODULE_DESCRIPTION("Intel(R) 10 Gigabit PCI Express Network Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); -#define DEFAULT_DEBUG_LEVEL_SHIFT 3 - static void ixgbe_service_event_schedule(struct ixgbe_adapter *adapter) { if (!test_bit(__IXGBE_DOWN, &adapter->state) && @@ -6834,7 +6837,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, adapter->pdev = pdev; hw = &adapter->hw; hw->back = adapter; - adapter->msg_enable = (1 << DEFAULT_DEBUG_LEVEL_SHIFT) - 1; + adapter->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE); hw->hw_addr = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index 581c65976bb4..307611ae831d 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -91,7 +91,10 @@ MODULE_DESCRIPTION("Intel(R) 82599 Virtual Function Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); -#define DEFAULT_DEBUG_LEVEL_SHIFT 3 +#define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV|NETIF_MSG_PROBE|NETIF_MSG_LINK) +static int debug = -1; +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); /* forward decls */ static void ixgbevf_set_itr_msix(struct ixgbevf_q_vector *q_vector); @@ -3367,7 +3370,7 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev, adapter->pdev = pdev; hw = &adapter->hw; hw->back = adapter; - adapter->msg_enable = (1 << DEFAULT_DEBUG_LEVEL_SHIFT) - 1; + adapter->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE); /* * call save state here in standalone driver because it relies on -- cgit v1.2.3 From 70e5576cb0af5c1351432704a39319af119584bb Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Thu, 15 Mar 2012 04:55:59 +0000 Subject: ixgbe: fix typo in enumeration name This was pointed out to me by Xiaojun Zhang on Source Forge. CC: Xiaojun Zhang Signed-off-by: Don Skidmore Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h index 80e26ff30ebf..74e192107f9a 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h @@ -544,7 +544,7 @@ struct ixgbe_fdir_filter { u16 action; }; -enum ixbge_state_t { +enum ixgbe_state_t { __IXGBE_TESTING, __IXGBE_RESETTING, __IXGBE_DOWN, -- cgit v1.2.3 From 8e4f3250f4162315fd57190d3364210eacafd7c7 Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Fri, 16 Mar 2012 05:41:48 +0000 Subject: ixgbe: update version number Update the driver version number to better match version of out of tree driver that has similar functionality. Signed-off-by: Don Skidmore Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 6dbad2b2d0b5..3e26b1f9ac75 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -63,8 +63,8 @@ static char ixgbe_default_device_descr[] = "Intel(R) 10 Gigabit Network Connection"; #endif #define MAJ 3 -#define MIN 6 -#define BUILD 7 +#define MIN 8 +#define BUILD 21 #define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) "." \ __stringify(BUILD) "-k" const char ixgbe_driver_version[] = DRV_VERSION; -- cgit v1.2.3 From 2e57b79ccef1ff1422fdf45a9b28fe60f8f084f7 Mon Sep 17 00:00:00 2001 From: Rick Jones Date: Tue, 27 Mar 2012 07:28:09 +0000 Subject: virtio_net: do not rate limit counter increments While it is desirable to rate limit certain messages, it is not desirable to rate limit the incrementing of counters associated with those messages. Signed-off-by: Rick Jones Acked-by: Rusty Russell Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 019da012669f..4de2760c5937 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -625,12 +625,13 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev) /* This can happen with OOM and indirect buffers. */ if (unlikely(capacity < 0)) { - if (net_ratelimit()) { - if (likely(capacity == -ENOMEM)) { + if (likely(capacity == -ENOMEM)) { + if (net_ratelimit()) { dev_warn(&dev->dev, "TX queue failure: out of memory\n"); } else { - dev->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; + if (net_ratelimit()) dev_warn(&dev->dev, "Unexpected TX queue failure: %d\n", capacity); -- cgit v1.2.3 From 2f2cc27f50e3d232602d3b7c972071b4a30e5e38 Mon Sep 17 00:00:00 2001 From: "Ying-Chun Liu (PaulLiu)" Date: Tue, 27 Mar 2012 15:54:01 +0800 Subject: regulator: anatop: patching to device-tree property "reg". Change "reg" to "anatop-reg-offset" due to there is a warning of handling no size field in reg. This patch also adds the missing device-tree binding documentation. Signed-off-by: Ying-Chun Liu (PaulLiu) Acked-by: Shawn Guo Signed-off-by: Mark Brown --- .../bindings/regulator/anatop-regulator.txt | 29 ++++++++++++++++++++++ drivers/regulator/anatop-regulator.c | 5 ++-- 2 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 Documentation/devicetree/bindings/regulator/anatop-regulator.txt (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/regulator/anatop-regulator.txt b/Documentation/devicetree/bindings/regulator/anatop-regulator.txt new file mode 100644 index 000000000000..357758cb6e92 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/anatop-regulator.txt @@ -0,0 +1,29 @@ +Anatop Voltage regulators + +Required properties: +- compatible: Must be "fsl,anatop-regulator" +- anatop-reg-offset: Anatop MFD register offset +- anatop-vol-bit-shift: Bit shift for the register +- anatop-vol-bit-width: Number of bits used in the register +- anatop-min-bit-val: Minimum value of this register +- anatop-min-voltage: Minimum voltage of this regulator +- anatop-max-voltage: Maximum voltage of this regulator + +Any property defined as part of the core regulator +binding, defined in regulator.txt, can also be used. + +Example: + + regulator-vddpu { + compatible = "fsl,anatop-regulator"; + regulator-name = "vddpu"; + regulator-min-microvolt = <725000>; + regulator-max-microvolt = <1300000>; + regulator-always-on; + anatop-reg-offset = <0x140>; + anatop-vol-bit-shift = <9>; + anatop-vol-bit-width = <5>; + anatop-min-bit-val = <1>; + anatop-min-voltage = <725000>; + anatop-max-voltage = <1300000>; + }; diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c index 17499a55113d..53969af17558 100644 --- a/drivers/regulator/anatop-regulator.c +++ b/drivers/regulator/anatop-regulator.c @@ -138,9 +138,10 @@ static int __devinit anatop_regulator_probe(struct platform_device *pdev) rdesc->type = REGULATOR_VOLTAGE; rdesc->owner = THIS_MODULE; sreg->mfd = anatopmfd; - ret = of_property_read_u32(np, "reg", &sreg->control_reg); + ret = of_property_read_u32(np, "anatop-reg-offset", + &sreg->control_reg); if (ret) { - dev_err(dev, "no reg property set\n"); + dev_err(dev, "no anatop-reg-offset property set\n"); goto anatop_probe_end; } ret = of_property_read_u32(np, "anatop-vol-bit-width", -- cgit v1.2.3 From a171e782a97d4ba55d7fa02f9a46904288b2c229 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 27 Mar 2012 15:17:26 +0800 Subject: regulator: wm831x-dcdc: Fix the logic to choose best current limit setting Current code in wm831x_buckv_set_current_limit actually set the current limit setting greater than specified range. Fix the logic in wm831x_buckv_set_current_limit to choose the smallest current limit setting falls within the specified range. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/wm831x-dcdc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c index 3044001f3cf6..ff810e787eac 100644 --- a/drivers/regulator/wm831x-dcdc.c +++ b/drivers/regulator/wm831x-dcdc.c @@ -380,7 +380,8 @@ static int wm831x_buckv_set_current_limit(struct regulator_dev *rdev, int i; for (i = 0; i < ARRAY_SIZE(wm831x_dcdc_ilim); i++) { - if (max_uA <= wm831x_dcdc_ilim[i]) + if ((min_uA <= wm831x_dcdc_ilim[i]) && + (wm831x_dcdc_ilim[i] <= max_uA)) break; } if (i == ARRAY_SIZE(wm831x_dcdc_ilim)) -- cgit v1.2.3 From ed3be9a0e3c1050fe07d69a8c600d86cac76cdc4 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 27 Mar 2012 15:18:53 +0800 Subject: regulator: wm831x-isink: Fix the logic to choose best current limit setting Current code in wm831x_isink_set_current actually set the current limit setting smaller than specified range. Fix the logic in wm831x_isink_set_current to choose the smallest current limit setting falls within the specified range. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/wm831x-isink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/wm831x-isink.c b/drivers/regulator/wm831x-isink.c index 634aac3f2d5f..b414e09c5620 100644 --- a/drivers/regulator/wm831x-isink.c +++ b/drivers/regulator/wm831x-isink.c @@ -101,7 +101,7 @@ static int wm831x_isink_set_current(struct regulator_dev *rdev, for (i = 0; i < ARRAY_SIZE(wm831x_isinkv_values); i++) { int val = wm831x_isinkv_values[i]; - if (min_uA >= val && val <= max_uA) { + if (min_uA <= val && val <= max_uA) { ret = wm831x_set_bits(wm831x, isink->reg, WM831X_CS1_ISEL_MASK, i); return ret; -- cgit v1.2.3 From 3a744038b3709cd467b693f3e146c6d5b8120a18 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 27 Mar 2012 15:20:08 +0800 Subject: regulator: wm8350: Fix the logic to choose best current limit setting Current implementation in get_isink_val actually choose the biggest current limit setting falls within the specified range. What we want is to choose the smallest current limit setting falls within the specified range. Fix it. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/wm8350-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index ff3465423be1..f29803cfd0cb 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c @@ -99,7 +99,7 @@ static int get_isink_val(int min_uA, int max_uA, u16 *setting) { int i; - for (i = ARRAY_SIZE(isink_cur) - 1; i >= 0; i--) { + for (i = 0; i < ARRAY_SIZE(isink_cur); i++) { if (min_uA <= isink_cur[i] && max_uA >= isink_cur[i]) { *setting = i; return 0; -- cgit v1.2.3 From fa5a97bb0c65cb8d0382b72a55e2b87e15268289 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 27 Mar 2012 15:21:45 +0800 Subject: regulator: Return microamps in wm8350_isink_get_current The values in isink_cur array are microamps. The regulator core expects get_current_limit callback to return microamps. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/wm8350-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index f29803cfd0cb..c5f3b4090d87 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c @@ -186,7 +186,7 @@ static int wm8350_isink_get_current(struct regulator_dev *rdev) return 0; } - return DIV_ROUND_CLOSEST(isink_cur[val], 100); + return isink_cur[val]; } /* turn on ISINK followed by DCDC */ -- cgit v1.2.3 From baa676fcf8d555269bd0a5a2496782beee55824d Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Tue, 27 Mar 2012 14:28:18 +0200 Subject: X86 & IA64: adapt for dma_map_ops changes Adapt core x86 and IA64 architecture code for dma_map_ops changes: replace alloc/free_coherent with generic alloc/free methods. Signed-off-by: Andrzej Pietrasiewicz Acked-by: Kyungmin Park [removed swiotlb related changes and replaced it with wrappers, merged with IA64 patch to avoid inter-patch dependences in intel-iommu code] Signed-off-by: Marek Szyprowski Reviewed-by: Arnd Bergmann Acked-by: Tony Luck --- arch/ia64/hp/common/sba_iommu.c | 11 ++++++----- arch/ia64/include/asm/dma-mapping.h | 18 ++++++++++++------ arch/ia64/kernel/pci-swiotlb.c | 14 +++++++++++--- arch/ia64/sn/pci/pci_dma.c | 9 +++++---- arch/x86/include/asm/dma-mapping.h | 26 ++++++++++++++++---------- arch/x86/kernel/amd_gart_64.c | 11 ++++++----- arch/x86/kernel/pci-calgary_64.c | 9 +++++---- arch/x86/kernel/pci-dma.c | 3 ++- arch/x86/kernel/pci-nommu.c | 6 +++--- arch/x86/kernel/pci-swiotlb.c | 17 +++++++++++++---- arch/x86/xen/pci-swiotlb-xen.c | 4 ++-- drivers/iommu/amd_iommu.c | 10 ++++++---- drivers/iommu/intel-iommu.c | 9 +++++---- drivers/xen/swiotlb-xen.c | 5 +++-- include/xen/swiotlb-xen.h | 6 ++++-- 15 files changed, 99 insertions(+), 59 deletions(-) (limited to 'drivers') diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c index f5f4ef149aac..e5eb9c4b2198 100644 --- a/arch/ia64/hp/common/sba_iommu.c +++ b/arch/ia64/hp/common/sba_iommu.c @@ -1130,7 +1130,8 @@ void sba_unmap_single_attrs(struct device *dev, dma_addr_t iova, size_t size, * See Documentation/DMA-API-HOWTO.txt */ static void * -sba_alloc_coherent (struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flags) +sba_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, + gfp_t flags, struct dma_attrs *attrs) { struct ioc *ioc; void *addr; @@ -1192,8 +1193,8 @@ sba_alloc_coherent (struct device *dev, size_t size, dma_addr_t *dma_handle, gfp * * See Documentation/DMA-API-HOWTO.txt */ -static void sba_free_coherent (struct device *dev, size_t size, void *vaddr, - dma_addr_t dma_handle) +static void sba_free_coherent(struct device *dev, size_t size, void *vaddr, + dma_addr_t dma_handle, struct dma_attrs *attrs) { sba_unmap_single_attrs(dev, dma_handle, size, 0, NULL); free_pages((unsigned long) vaddr, get_order(size)); @@ -2213,8 +2214,8 @@ sba_page_override(char *str) __setup("sbapagesize=",sba_page_override); struct dma_map_ops sba_dma_ops = { - .alloc_coherent = sba_alloc_coherent, - .free_coherent = sba_free_coherent, + .alloc = sba_alloc_coherent, + .free = sba_free_coherent, .map_page = sba_map_page, .unmap_page = sba_unmap_page, .map_sg = sba_map_sg_attrs, diff --git a/arch/ia64/include/asm/dma-mapping.h b/arch/ia64/include/asm/dma-mapping.h index 4336d080b241..4f5e8148440d 100644 --- a/arch/ia64/include/asm/dma-mapping.h +++ b/arch/ia64/include/asm/dma-mapping.h @@ -23,23 +23,29 @@ extern void machvec_dma_sync_single(struct device *, dma_addr_t, size_t, extern void machvec_dma_sync_sg(struct device *, struct scatterlist *, int, enum dma_data_direction); -static inline void *dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *daddr, gfp_t gfp) +#define dma_alloc_coherent(d,s,h,f) dma_alloc_attrs(d,s,h,f,NULL) + +static inline void *dma_alloc_attrs(struct device *dev, size_t size, + dma_addr_t *daddr, gfp_t gfp, + struct dma_attrs *attrs) { struct dma_map_ops *ops = platform_dma_get_ops(dev); void *caddr; - caddr = ops->alloc_coherent(dev, size, daddr, gfp); + caddr = ops->alloc(dev, size, daddr, gfp, attrs); debug_dma_alloc_coherent(dev, size, *daddr, caddr); return caddr; } -static inline void dma_free_coherent(struct device *dev, size_t size, - void *caddr, dma_addr_t daddr) +#define dma_free_coherent(d,s,c,h) dma_free_attrs(d,s,c,h,NULL) + +static inline void dma_free_attrs(struct device *dev, size_t size, + void *caddr, dma_addr_t daddr, + struct dma_attrs *attrs) { struct dma_map_ops *ops = platform_dma_get_ops(dev); debug_dma_free_coherent(dev, size, caddr, daddr); - ops->free_coherent(dev, size, caddr, daddr); + ops->free(dev, size, caddr, daddr, attrs); } #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) diff --git a/arch/ia64/kernel/pci-swiotlb.c b/arch/ia64/kernel/pci-swiotlb.c index d9485d952ed0..939260aeac98 100644 --- a/arch/ia64/kernel/pci-swiotlb.c +++ b/arch/ia64/kernel/pci-swiotlb.c @@ -15,16 +15,24 @@ int swiotlb __read_mostly; EXPORT_SYMBOL(swiotlb); static void *ia64_swiotlb_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t gfp) + dma_addr_t *dma_handle, gfp_t gfp, + struct dma_attrs *attrs) { if (dev->coherent_dma_mask != DMA_BIT_MASK(64)) gfp |= GFP_DMA; return swiotlb_alloc_coherent(dev, size, dma_handle, gfp); } +static void ia64_swiotlb_free_coherent(struct device *dev, size_t size, + void *vaddr, dma_addr_t dma_addr, + struct dma_attrs *attrs) +{ + swiotlb_free_coherent(dev, size, vaddr, dma_addr); +} + struct dma_map_ops swiotlb_dma_ops = { - .alloc_coherent = ia64_swiotlb_alloc_coherent, - .free_coherent = swiotlb_free_coherent, + .alloc = ia64_swiotlb_alloc_coherent, + .free = ia64_swiotlb_free_coherent, .map_page = swiotlb_map_page, .unmap_page = swiotlb_unmap_page, .map_sg = swiotlb_map_sg_attrs, diff --git a/arch/ia64/sn/pci/pci_dma.c b/arch/ia64/sn/pci/pci_dma.c index a9d310de57da..3290d6e00c31 100644 --- a/arch/ia64/sn/pci/pci_dma.c +++ b/arch/ia64/sn/pci/pci_dma.c @@ -76,7 +76,8 @@ EXPORT_SYMBOL(sn_dma_set_mask); * more information. */ static void *sn_dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t * dma_handle, gfp_t flags) + dma_addr_t * dma_handle, gfp_t flags, + struct dma_attrs *attrs) { void *cpuaddr; unsigned long phys_addr; @@ -137,7 +138,7 @@ static void *sn_dma_alloc_coherent(struct device *dev, size_t size, * any associated IOMMU mappings. */ static void sn_dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, - dma_addr_t dma_handle) + dma_addr_t dma_handle, struct dma_attrs *attrs) { struct pci_dev *pdev = to_pci_dev(dev); struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); @@ -466,8 +467,8 @@ int sn_pci_legacy_write(struct pci_bus *bus, u16 port, u32 val, u8 size) } static struct dma_map_ops sn_dma_ops = { - .alloc_coherent = sn_dma_alloc_coherent, - .free_coherent = sn_dma_free_coherent, + .alloc = sn_dma_alloc_coherent, + .free = sn_dma_free_coherent, .map_page = sn_dma_map_page, .unmap_page = sn_dma_unmap_page, .map_sg = sn_dma_map_sg, diff --git a/arch/x86/include/asm/dma-mapping.h b/arch/x86/include/asm/dma-mapping.h index ed3065fd6314..4b4331d71935 100644 --- a/arch/x86/include/asm/dma-mapping.h +++ b/arch/x86/include/asm/dma-mapping.h @@ -59,7 +59,8 @@ extern int dma_supported(struct device *hwdev, u64 mask); extern int dma_set_mask(struct device *dev, u64 mask); extern void *dma_generic_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_addr, gfp_t flag); + dma_addr_t *dma_addr, gfp_t flag, + struct dma_attrs *attrs); static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) { @@ -111,9 +112,11 @@ static inline gfp_t dma_alloc_coherent_gfp_flags(struct device *dev, gfp_t gfp) return gfp; } +#define dma_alloc_coherent(d,s,h,f) dma_alloc_attrs(d,s,h,f,NULL) + static inline void * -dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, - gfp_t gfp) +dma_alloc_attrs(struct device *dev, size_t size, dma_addr_t *dma_handle, + gfp_t gfp, struct dma_attrs *attrs) { struct dma_map_ops *ops = get_dma_ops(dev); void *memory; @@ -129,18 +132,21 @@ dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, if (!is_device_dma_capable(dev)) return NULL; - if (!ops->alloc_coherent) + if (!ops->alloc) return NULL; - memory = ops->alloc_coherent(dev, size, dma_handle, - dma_alloc_coherent_gfp_flags(dev, gfp)); + memory = ops->alloc(dev, size, dma_handle, + dma_alloc_coherent_gfp_flags(dev, gfp), attrs); debug_dma_alloc_coherent(dev, size, *dma_handle, memory); return memory; } -static inline void dma_free_coherent(struct device *dev, size_t size, - void *vaddr, dma_addr_t bus) +#define dma_free_coherent(d,s,c,h) dma_free_attrs(d,s,c,h,NULL) + +static inline void dma_free_attrs(struct device *dev, size_t size, + void *vaddr, dma_addr_t bus, + struct dma_attrs *attrs) { struct dma_map_ops *ops = get_dma_ops(dev); @@ -150,8 +156,8 @@ static inline void dma_free_coherent(struct device *dev, size_t size, return; debug_dma_free_coherent(dev, size, vaddr, bus); - if (ops->free_coherent) - ops->free_coherent(dev, size, vaddr, bus); + if (ops->free) + ops->free(dev, size, vaddr, bus, attrs); } #endif diff --git a/arch/x86/kernel/amd_gart_64.c b/arch/x86/kernel/amd_gart_64.c index b1e7c7f7a0af..e66311200cbd 100644 --- a/arch/x86/kernel/amd_gart_64.c +++ b/arch/x86/kernel/amd_gart_64.c @@ -477,7 +477,7 @@ error: /* allocate and map a coherent mapping */ static void * gart_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_addr, - gfp_t flag) + gfp_t flag, struct dma_attrs *attrs) { dma_addr_t paddr; unsigned long align_mask; @@ -500,7 +500,8 @@ gart_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_addr, } __free_pages(page, get_order(size)); } else - return dma_generic_alloc_coherent(dev, size, dma_addr, flag); + return dma_generic_alloc_coherent(dev, size, dma_addr, flag, + attrs); return NULL; } @@ -508,7 +509,7 @@ gart_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_addr, /* free a coherent mapping */ static void gart_free_coherent(struct device *dev, size_t size, void *vaddr, - dma_addr_t dma_addr) + dma_addr_t dma_addr, struct dma_attrs *attrs) { gart_unmap_page(dev, dma_addr, size, DMA_BIDIRECTIONAL, NULL); free_pages((unsigned long)vaddr, get_order(size)); @@ -700,8 +701,8 @@ static struct dma_map_ops gart_dma_ops = { .unmap_sg = gart_unmap_sg, .map_page = gart_map_page, .unmap_page = gart_unmap_page, - .alloc_coherent = gart_alloc_coherent, - .free_coherent = gart_free_coherent, + .alloc = gart_alloc_coherent, + .free = gart_free_coherent, .mapping_error = gart_mapping_error, }; diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c index 726494b58345..07b587c5a2d2 100644 --- a/arch/x86/kernel/pci-calgary_64.c +++ b/arch/x86/kernel/pci-calgary_64.c @@ -431,7 +431,7 @@ static void calgary_unmap_page(struct device *dev, dma_addr_t dma_addr, } static void* calgary_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t flag) + dma_addr_t *dma_handle, gfp_t flag, struct dma_attrs *attrs) { void *ret = NULL; dma_addr_t mapping; @@ -464,7 +464,8 @@ error: } static void calgary_free_coherent(struct device *dev, size_t size, - void *vaddr, dma_addr_t dma_handle) + void *vaddr, dma_addr_t dma_handle, + struct dma_attrs *attrs) { unsigned int npages; struct iommu_table *tbl = find_iommu_table(dev); @@ -477,8 +478,8 @@ static void calgary_free_coherent(struct device *dev, size_t size, } static struct dma_map_ops calgary_dma_ops = { - .alloc_coherent = calgary_alloc_coherent, - .free_coherent = calgary_free_coherent, + .alloc = calgary_alloc_coherent, + .free = calgary_free_coherent, .map_sg = calgary_map_sg, .unmap_sg = calgary_unmap_sg, .map_page = calgary_map_page, diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c index 1c4d769e21ea..75e1cc19e630 100644 --- a/arch/x86/kernel/pci-dma.c +++ b/arch/x86/kernel/pci-dma.c @@ -96,7 +96,8 @@ void __init pci_iommu_alloc(void) } } void *dma_generic_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_addr, gfp_t flag) + dma_addr_t *dma_addr, gfp_t flag, + struct dma_attrs *attrs) { unsigned long dma_mask; struct page *page; diff --git a/arch/x86/kernel/pci-nommu.c b/arch/x86/kernel/pci-nommu.c index 3af4af810c07..f96050685b46 100644 --- a/arch/x86/kernel/pci-nommu.c +++ b/arch/x86/kernel/pci-nommu.c @@ -75,7 +75,7 @@ static int nommu_map_sg(struct device *hwdev, struct scatterlist *sg, } static void nommu_free_coherent(struct device *dev, size_t size, void *vaddr, - dma_addr_t dma_addr) + dma_addr_t dma_addr, struct dma_attrs *attrs) { free_pages((unsigned long)vaddr, get_order(size)); } @@ -96,8 +96,8 @@ static void nommu_sync_sg_for_device(struct device *dev, } struct dma_map_ops nommu_dma_ops = { - .alloc_coherent = dma_generic_alloc_coherent, - .free_coherent = nommu_free_coherent, + .alloc = dma_generic_alloc_coherent, + .free = nommu_free_coherent, .map_sg = nommu_map_sg, .map_page = nommu_map_page, .sync_single_for_device = nommu_sync_single_for_device, diff --git a/arch/x86/kernel/pci-swiotlb.c b/arch/x86/kernel/pci-swiotlb.c index 8f972cbddef0..6c483ba98b9c 100644 --- a/arch/x86/kernel/pci-swiotlb.c +++ b/arch/x86/kernel/pci-swiotlb.c @@ -15,21 +15,30 @@ int swiotlb __read_mostly; static void *x86_swiotlb_alloc_coherent(struct device *hwdev, size_t size, - dma_addr_t *dma_handle, gfp_t flags) + dma_addr_t *dma_handle, gfp_t flags, + struct dma_attrs *attrs) { void *vaddr; - vaddr = dma_generic_alloc_coherent(hwdev, size, dma_handle, flags); + vaddr = dma_generic_alloc_coherent(hwdev, size, dma_handle, flags, + attrs); if (vaddr) return vaddr; return swiotlb_alloc_coherent(hwdev, size, dma_handle, flags); } +static void x86_swiotlb_free_coherent(struct device *dev, size_t size, + void *vaddr, dma_addr_t dma_addr, + struct dma_attrs *attrs) +{ + swiotlb_free_coherent(dev, size, vaddr, dma_addr); +} + static struct dma_map_ops swiotlb_dma_ops = { .mapping_error = swiotlb_dma_mapping_error, - .alloc_coherent = x86_swiotlb_alloc_coherent, - .free_coherent = swiotlb_free_coherent, + .alloc = x86_swiotlb_alloc_coherent, + .free = x86_swiotlb_free_coherent, .sync_single_for_cpu = swiotlb_sync_single_for_cpu, .sync_single_for_device = swiotlb_sync_single_for_device, .sync_sg_for_cpu = swiotlb_sync_sg_for_cpu, diff --git a/arch/x86/xen/pci-swiotlb-xen.c b/arch/x86/xen/pci-swiotlb-xen.c index b480d4207a4c..967633ad98c4 100644 --- a/arch/x86/xen/pci-swiotlb-xen.c +++ b/arch/x86/xen/pci-swiotlb-xen.c @@ -12,8 +12,8 @@ int xen_swiotlb __read_mostly; static struct dma_map_ops xen_swiotlb_dma_ops = { .mapping_error = xen_swiotlb_dma_mapping_error, - .alloc_coherent = xen_swiotlb_alloc_coherent, - .free_coherent = xen_swiotlb_free_coherent, + .alloc = xen_swiotlb_alloc_coherent, + .free = xen_swiotlb_free_coherent, .sync_single_for_cpu = xen_swiotlb_sync_single_for_cpu, .sync_single_for_device = xen_swiotlb_sync_single_for_device, .sync_sg_for_cpu = xen_swiotlb_sync_sg_for_cpu, diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index f75e0608be5b..daa333f97b78 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -2707,7 +2707,8 @@ static void unmap_sg(struct device *dev, struct scatterlist *sglist, * The exported alloc_coherent function for dma_ops. */ static void *alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_addr, gfp_t flag) + dma_addr_t *dma_addr, gfp_t flag, + struct dma_attrs *attrs) { unsigned long flags; void *virt_addr; @@ -2765,7 +2766,8 @@ out_free: * The exported free_coherent function for dma_ops. */ static void free_coherent(struct device *dev, size_t size, - void *virt_addr, dma_addr_t dma_addr) + void *virt_addr, dma_addr_t dma_addr, + struct dma_attrs *attrs) { unsigned long flags; struct protection_domain *domain; @@ -2846,8 +2848,8 @@ static void prealloc_protection_domains(void) } static struct dma_map_ops amd_iommu_dma_ops = { - .alloc_coherent = alloc_coherent, - .free_coherent = free_coherent, + .alloc = alloc_coherent, + .free = free_coherent, .map_page = map_page, .unmap_page = unmap_page, .map_sg = map_sg, diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index c9c6053198d4..e39bfdc055c3 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -2938,7 +2938,8 @@ static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr, } static void *intel_alloc_coherent(struct device *hwdev, size_t size, - dma_addr_t *dma_handle, gfp_t flags) + dma_addr_t *dma_handle, gfp_t flags, + struct dma_attrs *attrs) { void *vaddr; int order; @@ -2970,7 +2971,7 @@ static void *intel_alloc_coherent(struct device *hwdev, size_t size, } static void intel_free_coherent(struct device *hwdev, size_t size, void *vaddr, - dma_addr_t dma_handle) + dma_addr_t dma_handle, struct dma_attrs *attrs) { int order; @@ -3115,8 +3116,8 @@ static int intel_mapping_error(struct device *dev, dma_addr_t dma_addr) } struct dma_map_ops intel_dma_ops = { - .alloc_coherent = intel_alloc_coherent, - .free_coherent = intel_free_coherent, + .alloc = intel_alloc_coherent, + .free = intel_free_coherent, .map_sg = intel_map_sg, .unmap_sg = intel_unmap_sg, .map_page = intel_map_page, diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c index 19e6a2041371..1afb4fba11b4 100644 --- a/drivers/xen/swiotlb-xen.c +++ b/drivers/xen/swiotlb-xen.c @@ -204,7 +204,8 @@ error: void * xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size, - dma_addr_t *dma_handle, gfp_t flags) + dma_addr_t *dma_handle, gfp_t flags, + struct dma_attrs *attrs) { void *ret; int order = get_order(size); @@ -253,7 +254,7 @@ EXPORT_SYMBOL_GPL(xen_swiotlb_alloc_coherent); void xen_swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr, - dma_addr_t dev_addr) + dma_addr_t dev_addr, struct dma_attrs *attrs) { int order = get_order(size); phys_addr_t phys; diff --git a/include/xen/swiotlb-xen.h b/include/xen/swiotlb-xen.h index 2ea2fdc79c16..4f4d449f00f6 100644 --- a/include/xen/swiotlb-xen.h +++ b/include/xen/swiotlb-xen.h @@ -7,11 +7,13 @@ extern void xen_swiotlb_init(int verbose); extern void *xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size, - dma_addr_t *dma_handle, gfp_t flags); + dma_addr_t *dma_handle, gfp_t flags, + struct dma_attrs *attrs); extern void xen_swiotlb_free_coherent(struct device *hwdev, size_t size, - void *vaddr, dma_addr_t dma_handle); + void *vaddr, dma_addr_t dma_handle, + struct dma_attrs *attrs); extern dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page, unsigned long offset, size_t size, -- cgit v1.2.3 From 75836b8daefdde84f8b5dde1be5b67d858139df3 Mon Sep 17 00:00:00 2001 From: Stanislav Yakovlev Date: Tue, 20 Mar 2012 17:52:57 -0400 Subject: net/wireless: ipw2x00: fix a typo in wiphy struct initilization Fix comment as well. Signed-off-by: Stanislav Yakovlev Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2x00/ipw2200.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 4fcdac63a300..2b022571a859 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -11507,9 +11507,9 @@ static int ipw_wdev_init(struct net_device *dev) rc = -ENOMEM; goto out; } - /* translate geo->bg to a_band.channels */ + /* translate geo->a to a_band.channels */ for (i = 0; i < geo->a_channels; i++) { - a_band->channels[i].band = IEEE80211_BAND_2GHZ; + a_band->channels[i].band = IEEE80211_BAND_5GHZ; a_band->channels[i].center_freq = geo->a[i].freq; a_band->channels[i].hw_value = geo->a[i].channel; a_band->channels[i].max_power = geo->a[i].max_power; -- cgit v1.2.3 From e90c7e712980bf794f88f749e2a1270e4a4a116e Mon Sep 17 00:00:00 2001 From: Santosh Nayak Date: Thu, 22 Mar 2012 12:42:41 +0530 Subject: net: orinoco: add error handling for failed kmalloc(). With flag 'GFP_ATOMIC', probability of allocation failure is more. Add error handling after kmalloc() call to avoid null dereference. Signed-off-by: Santosh Nayak Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/main.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index dd6c64ac406e..88e3ad2d1db8 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -1336,6 +1336,10 @@ static void qbuf_scan(struct orinoco_private *priv, void *buf, unsigned long flags; sd = kmalloc(sizeof(*sd), GFP_ATOMIC); + if (!sd) { + printk(KERN_ERR "%s: failed to alloc memory\n", __func__); + return; + } sd->buf = buf; sd->len = len; sd->type = type; @@ -1353,6 +1357,10 @@ static void qabort_scan(struct orinoco_private *priv) unsigned long flags; sd = kmalloc(sizeof(*sd), GFP_ATOMIC); + if (!sd) { + printk(KERN_ERR "%s: failed to alloc memory\n", __func__); + return; + } sd->len = -1; /* Abort */ spin_lock_irqsave(&priv->scan_lock, flags); -- cgit v1.2.3 From a4d6367fa77fb604ce62582e1c0998e0ed098927 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Tue, 27 Mar 2012 10:08:55 +0530 Subject: ath9k: Use HW HT capabilites properly The commit "ath9k: Remove aggregation flags" changed how nodes were being initialized. Use the HW HT cap bits to initialize/de-initialize nodes, else we would be accessing an uninitialized entry during a suspend/resume cycle, resulting in a panic. Reported-by: Justin P. Mattock Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 38794850f005..215eb2536b1e 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -640,7 +640,7 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta, an->sta = sta; an->vif = vif; - if (sta->ht_cap.ht_supported) { + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { ath_tx_node_init(sc, an); an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + sta->ht_cap.ampdu_factor); @@ -659,7 +659,7 @@ static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) an->sta = NULL; #endif - if (sta->ht_cap.ht_supported) + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) ath_tx_node_cleanup(sc, an); } -- cgit v1.2.3 From fe2e39d8782d885755139304d8dba0b3e5bfa878 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 28 Mar 2012 23:29:45 +0200 Subject: firmware_class: Rework usermodehelper check Instead of two functions, read_lock_usermodehelper() and usermodehelper_is_disabled(), used in combination, introduce usermodehelper_read_trylock() that will only return with umhelper_sem held if usermodehelper_disabled is unset (and will return -EAGAIN otherwise) and make _request_firmware() use it. Rename read_unlock_usermodehelper() to usermodehelper_read_unlock() to follow the naming convention of the new function. Signed-off-by: Rafael J. Wysocki Acked-by: Greg Kroah-Hartman Cc: stable@vger.kernel.org --- drivers/base/firmware_class.c | 11 +++++------ include/linux/kmod.h | 5 ++--- kernel/kmod.c | 24 +++++++++++------------- 3 files changed, 18 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 6c9387d646ec..deee871e509c 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -533,12 +533,10 @@ static int _request_firmware(const struct firmware **firmware_p, return 0; } - read_lock_usermodehelper(); - - if (WARN_ON(usermodehelper_is_disabled())) { + retval = usermodehelper_read_trylock(); + if (WARN_ON(retval)) { dev_err(device, "firmware: %s will not be loaded\n", name); - retval = -EBUSY; - goto out; + goto out_nolock; } if (uevent) @@ -573,8 +571,9 @@ static int _request_firmware(const struct firmware **firmware_p, fw_destroy_instance(fw_priv); out: - read_unlock_usermodehelper(); + usermodehelper_read_unlock(); +out_nolock: if (retval) { release_firmware(firmware); *firmware_p = NULL; diff --git a/include/linux/kmod.h b/include/linux/kmod.h index 9efeae679106..97d22c3e08b1 100644 --- a/include/linux/kmod.h +++ b/include/linux/kmod.h @@ -114,8 +114,7 @@ extern void usermodehelper_init(void); extern int usermodehelper_disable(void); extern void usermodehelper_enable(void); -extern bool usermodehelper_is_disabled(void); -extern void read_lock_usermodehelper(void); -extern void read_unlock_usermodehelper(void); +extern int usermodehelper_read_trylock(void); +extern void usermodehelper_read_unlock(void); #endif /* __LINUX_KMOD_H__ */ diff --git a/kernel/kmod.c b/kernel/kmod.c index 957a7aab8ebc..4079ac1d5e79 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -339,17 +339,24 @@ static DECLARE_WAIT_QUEUE_HEAD(running_helpers_waitq); */ #define RUNNING_HELPERS_TIMEOUT (5 * HZ) -void read_lock_usermodehelper(void) +int usermodehelper_read_trylock(void) { + int ret = 0; + down_read(&umhelper_sem); + if (usermodehelper_disabled) { + up_read(&umhelper_sem); + ret = -EAGAIN; + } + return ret; } -EXPORT_SYMBOL_GPL(read_lock_usermodehelper); +EXPORT_SYMBOL_GPL(usermodehelper_read_trylock); -void read_unlock_usermodehelper(void) +void usermodehelper_read_unlock(void) { up_read(&umhelper_sem); } -EXPORT_SYMBOL_GPL(read_unlock_usermodehelper); +EXPORT_SYMBOL_GPL(usermodehelper_read_unlock); /** * usermodehelper_disable - prevent new helpers from being started @@ -390,15 +397,6 @@ void usermodehelper_enable(void) up_write(&umhelper_sem); } -/** - * usermodehelper_is_disabled - check if new helpers are allowed to be started - */ -bool usermodehelper_is_disabled(void) -{ - return usermodehelper_disabled; -} -EXPORT_SYMBOL_GPL(usermodehelper_is_disabled); - static void helper_lock(void) { atomic_inc(&running_helpers); -- cgit v1.2.3 From 811fa4004485dec8977176bf605a5b0508ee206c Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 28 Mar 2012 23:29:55 +0200 Subject: firmware_class: Split _request_firmware() into three functions, v2 Split _request_firmware() into three functions, _request_firmware_prepare() doing preparatory work that need not be done under umhelper_sem, _request_firmware_cleanup() doing the post-error cleanup and _request_firmware() carrying out the remaining operations. This change is requisite for moving the acquisition of umhelper_sem from _request_firmware() to the callers, which is going to be done subsequently. Signed-off-by: Rafael J. Wysocki Acked-by: Greg Kroah-Hartman Reviewed-by: Stephen Boyd Cc: stable@vger.kernel.org --- drivers/base/firmware_class.c | 58 ++++++++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index deee871e509c..60290671f04a 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -435,7 +435,7 @@ static void firmware_class_timeout(u_long data) } static struct firmware_priv * -fw_create_instance(struct firmware *firmware, const char *fw_name, +fw_create_instance(const struct firmware *firmware, const char *fw_name, struct device *device, bool uevent, bool nowait) { struct firmware_priv *fw_priv; @@ -449,7 +449,7 @@ fw_create_instance(struct firmware *firmware, const char *fw_name, goto err_out; } - fw_priv->fw = firmware; + fw_priv->fw = (struct firmware *)firmware; fw_priv->nowait = nowait; strcpy(fw_priv->fw_id, fw_name); init_completion(&fw_priv->completion); @@ -510,13 +510,10 @@ static void fw_destroy_instance(struct firmware_priv *fw_priv) device_unregister(f_dev); } -static int _request_firmware(const struct firmware **firmware_p, - const char *name, struct device *device, - bool uevent, bool nowait) +static int _request_firmware_prepare(const struct firmware **firmware_p, + const char *name, struct device *device) { - struct firmware_priv *fw_priv; struct firmware *firmware; - int retval = 0; if (!firmware_p) return -EINVAL; @@ -533,10 +530,26 @@ static int _request_firmware(const struct firmware **firmware_p, return 0; } + return 1; +} + +static void _request_firmware_cleanup(const struct firmware **firmware_p) +{ + release_firmware(*firmware_p); + *firmware_p = NULL; +} + +static int _request_firmware(const struct firmware *firmware, + const char *name, struct device *device, + bool uevent, bool nowait) +{ + struct firmware_priv *fw_priv; + int retval; + retval = usermodehelper_read_trylock(); if (WARN_ON(retval)) { dev_err(device, "firmware: %s will not be loaded\n", name); - goto out_nolock; + return retval; } if (uevent) @@ -572,13 +585,6 @@ static int _request_firmware(const struct firmware **firmware_p, out: usermodehelper_read_unlock(); - -out_nolock: - if (retval) { - release_firmware(firmware); - *firmware_p = NULL; - } - return retval; } @@ -601,7 +607,17 @@ int request_firmware(const struct firmware **firmware_p, const char *name, struct device *device) { - return _request_firmware(firmware_p, name, device, true, false); + int ret; + + ret = _request_firmware_prepare(firmware_p, name, device); + if (ret <= 0) + return ret; + + ret = _request_firmware(*firmware_p, name, device, true, false); + if (ret) + _request_firmware_cleanup(firmware_p); + + return ret; } /** @@ -639,8 +655,16 @@ static int request_firmware_work_func(void *arg) return 0; } - ret = _request_firmware(&fw, fw_work->name, fw_work->device, + ret = _request_firmware_prepare(&fw, fw_work->name, fw_work->device); + if (ret <= 0) + goto out; + + ret = _request_firmware(fw, fw_work->name, fw_work->device, fw_work->uevent, true); + if (ret) + _request_firmware_cleanup(&fw); + + out: fw_work->cont(fw, fw_work->context); module_put(fw_work->module); -- cgit v1.2.3 From 9b78c1da60b3c62ccdd1509f0902ad19ceaf776b Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 28 Mar 2012 23:30:02 +0200 Subject: firmware_class: Do not warn that system is not ready from async loads If firmware is requested asynchronously, by calling request_firmware_nowait(), there is no reason to fail the request (and warn the user) when the system is (presumably temporarily) unready to handle it (because user space is not available yet or frozen). For this reason, introduce an alternative routine for read-locking umhelper_sem, usermodehelper_read_lock_wait(), that will wait for usermodehelper_disabled to be unset (possibly with a timeout) and make request_firmware_work_func() use it instead of usermodehelper_read_trylock(). Accordingly, modify request_firmware() so that it uses usermodehelper_read_trylock() to acquire umhelper_sem and remove the code related to that lock from _request_firmware(). Signed-off-by: Rafael J. Wysocki Acked-by: Greg Kroah-Hartman Cc: stable@vger.kernel.org --- drivers/base/firmware_class.c | 51 +++++++++++++++++++++---------------- include/linux/kmod.h | 1 + kernel/kmod.c | 58 +++++++++++++++++++++++++++++++++---------- 3 files changed, 76 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 60290671f04a..72c644b191a4 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -81,6 +81,11 @@ enum { static int loading_timeout = 60; /* In seconds */ +static inline long firmware_loading_timeout(void) +{ + return loading_timeout > 0 ? loading_timeout * HZ : MAX_SCHEDULE_TIMEOUT; +} + /* fw_lock could be moved to 'struct firmware_priv' but since it is just * guarding for corner cases a global lock should be OK */ static DEFINE_MUTEX(fw_lock); @@ -541,31 +546,22 @@ static void _request_firmware_cleanup(const struct firmware **firmware_p) static int _request_firmware(const struct firmware *firmware, const char *name, struct device *device, - bool uevent, bool nowait) + bool uevent, bool nowait, long timeout) { struct firmware_priv *fw_priv; - int retval; - - retval = usermodehelper_read_trylock(); - if (WARN_ON(retval)) { - dev_err(device, "firmware: %s will not be loaded\n", name); - return retval; - } + int retval = 0; if (uevent) dev_dbg(device, "firmware: requesting %s\n", name); fw_priv = fw_create_instance(firmware, name, device, uevent, nowait); - if (IS_ERR(fw_priv)) { - retval = PTR_ERR(fw_priv); - goto out; - } + if (IS_ERR(fw_priv)) + return PTR_ERR(fw_priv); if (uevent) { - if (loading_timeout > 0) + if (timeout != MAX_SCHEDULE_TIMEOUT) mod_timer(&fw_priv->timeout, - round_jiffies_up(jiffies + - loading_timeout * HZ)); + round_jiffies_up(jiffies + timeout)); kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD); } @@ -582,9 +578,6 @@ static int _request_firmware(const struct firmware *firmware, mutex_unlock(&fw_lock); fw_destroy_instance(fw_priv); - -out: - usermodehelper_read_unlock(); return retval; } @@ -613,7 +606,14 @@ request_firmware(const struct firmware **firmware_p, const char *name, if (ret <= 0) return ret; - ret = _request_firmware(*firmware_p, name, device, true, false); + ret = usermodehelper_read_trylock(); + if (WARN_ON(ret)) { + dev_err(device, "firmware: %s will not be loaded\n", name); + } else { + ret = _request_firmware(*firmware_p, name, device, true, false, + firmware_loading_timeout()); + usermodehelper_read_unlock(); + } if (ret) _request_firmware_cleanup(firmware_p); @@ -648,6 +648,7 @@ static int request_firmware_work_func(void *arg) { struct firmware_work *fw_work = arg; const struct firmware *fw; + long timeout; int ret; if (!arg) { @@ -659,8 +660,16 @@ static int request_firmware_work_func(void *arg) if (ret <= 0) goto out; - ret = _request_firmware(fw, fw_work->name, fw_work->device, - fw_work->uevent, true); + timeout = usermodehelper_read_lock_wait(firmware_loading_timeout()); + if (timeout) { + ret = _request_firmware(fw, fw_work->name, fw_work->device, + fw_work->uevent, true, timeout); + usermodehelper_read_unlock(); + } else { + dev_dbg(fw_work->device, "firmware: %s loading timed out\n", + fw_work->name); + ret = -EAGAIN; + } if (ret) _request_firmware_cleanup(&fw); diff --git a/include/linux/kmod.h b/include/linux/kmod.h index 97d22c3e08b1..b087377ae2c4 100644 --- a/include/linux/kmod.h +++ b/include/linux/kmod.h @@ -115,6 +115,7 @@ extern void usermodehelper_init(void); extern int usermodehelper_disable(void); extern void usermodehelper_enable(void); extern int usermodehelper_read_trylock(void); +extern long usermodehelper_read_lock_wait(long timeout); extern void usermodehelper_read_unlock(void); #endif /* __LINUX_KMOD_H__ */ diff --git a/kernel/kmod.c b/kernel/kmod.c index 4079ac1d5e79..da7fcca279f9 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -333,6 +333,12 @@ static atomic_t running_helpers = ATOMIC_INIT(0); */ static DECLARE_WAIT_QUEUE_HEAD(running_helpers_waitq); +/* + * Used by usermodehelper_read_lock_wait() to wait for usermodehelper_disabled + * to become 'false'. + */ +static DECLARE_WAIT_QUEUE_HEAD(usermodehelper_disabled_waitq); + /* * Time to wait for running_helpers to become zero before the setting of * usermodehelper_disabled in usermodehelper_disable() fails @@ -352,12 +358,50 @@ int usermodehelper_read_trylock(void) } EXPORT_SYMBOL_GPL(usermodehelper_read_trylock); +long usermodehelper_read_lock_wait(long timeout) +{ + DEFINE_WAIT(wait); + + if (timeout < 0) + return -EINVAL; + + down_read(&umhelper_sem); + for (;;) { + prepare_to_wait(&usermodehelper_disabled_waitq, &wait, + TASK_UNINTERRUPTIBLE); + if (!usermodehelper_disabled) + break; + + up_read(&umhelper_sem); + + timeout = schedule_timeout(timeout); + if (!timeout) + break; + + down_read(&umhelper_sem); + } + finish_wait(&usermodehelper_disabled_waitq, &wait); + return timeout; +} +EXPORT_SYMBOL_GPL(usermodehelper_read_lock_wait); + void usermodehelper_read_unlock(void) { up_read(&umhelper_sem); } EXPORT_SYMBOL_GPL(usermodehelper_read_unlock); +/** + * usermodehelper_enable - allow new helpers to be started again + */ +void usermodehelper_enable(void) +{ + down_write(&umhelper_sem); + usermodehelper_disabled = 0; + wake_up(&usermodehelper_disabled_waitq); + up_write(&umhelper_sem); +} + /** * usermodehelper_disable - prevent new helpers from being started */ @@ -381,22 +425,10 @@ int usermodehelper_disable(void) if (retval) return 0; - down_write(&umhelper_sem); - usermodehelper_disabled = 0; - up_write(&umhelper_sem); + usermodehelper_enable(); return -EAGAIN; } -/** - * usermodehelper_enable - allow new helpers to be started again - */ -void usermodehelper_enable(void) -{ - down_write(&umhelper_sem); - usermodehelper_disabled = 0; - up_write(&umhelper_sem); -} - static void helper_lock(void) { atomic_inc(&running_helpers); -- cgit v1.2.3 From dddb5549da6b15ea8b9ce9ee0859c8d1fa268b5b Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 28 Mar 2012 23:30:43 +0200 Subject: firmware_class: Reorganize fw_create_instance() Recent patches to split up the three phases of request_firmware() lead to a casting away of const in fw_create_instance(). We can avoid this cast by splitting up fw_create_instance() a bit. Make _request_firmware_setup() return a struct fw_priv and use that struct instead of passing struct firmware to _request_firmware(). Move the uevent and device file creation bits to the loading phase and rename the function to _request_firmware_load() to better reflect its purpose. Signed-off-by: Stephen Boyd Acked-by: Greg Kroah-Hartman Signed-off-by: Rafael J. Wysocki --- drivers/base/firmware_class.c | 135 +++++++++++++++++++----------------------- 1 file changed, 62 insertions(+), 73 deletions(-) (limited to 'drivers') diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 72c644b191a4..ae00a2fd280f 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -440,21 +440,19 @@ static void firmware_class_timeout(u_long data) } static struct firmware_priv * -fw_create_instance(const struct firmware *firmware, const char *fw_name, +fw_create_instance(struct firmware *firmware, const char *fw_name, struct device *device, bool uevent, bool nowait) { struct firmware_priv *fw_priv; struct device *f_dev; - int error; fw_priv = kzalloc(sizeof(*fw_priv) + strlen(fw_name) + 1 , GFP_KERNEL); if (!fw_priv) { dev_err(device, "%s: kmalloc failed\n", __func__); - error = -ENOMEM; - goto err_out; + return ERR_PTR(-ENOMEM); } - fw_priv->fw = (struct firmware *)firmware; + fw_priv->fw = firmware; fw_priv->nowait = nowait; strcpy(fw_priv->fw_id, fw_name); init_completion(&fw_priv->completion); @@ -468,74 +466,37 @@ fw_create_instance(const struct firmware *firmware, const char *fw_name, f_dev->parent = device; f_dev->class = &firmware_class; - dev_set_uevent_suppress(f_dev, true); - - /* Need to pin this module until class device is destroyed */ - __module_get(THIS_MODULE); - - error = device_add(f_dev); - if (error) { - dev_err(device, "%s: device_register failed\n", __func__); - goto err_put_dev; - } - - error = device_create_bin_file(f_dev, &firmware_attr_data); - if (error) { - dev_err(device, "%s: sysfs_create_bin_file failed\n", __func__); - goto err_del_dev; - } - - error = device_create_file(f_dev, &dev_attr_loading); - if (error) { - dev_err(device, "%s: device_create_file failed\n", __func__); - goto err_del_bin_attr; - } - - if (uevent) - dev_set_uevent_suppress(f_dev, false); - return fw_priv; - -err_del_bin_attr: - device_remove_bin_file(f_dev, &firmware_attr_data); -err_del_dev: - device_del(f_dev); -err_put_dev: - put_device(f_dev); -err_out: - return ERR_PTR(error); -} - -static void fw_destroy_instance(struct firmware_priv *fw_priv) -{ - struct device *f_dev = &fw_priv->dev; - - device_remove_file(f_dev, &dev_attr_loading); - device_remove_bin_file(f_dev, &firmware_attr_data); - device_unregister(f_dev); } -static int _request_firmware_prepare(const struct firmware **firmware_p, - const char *name, struct device *device) +static struct firmware_priv * +_request_firmware_prepare(const struct firmware **firmware_p, const char *name, + struct device *device, bool uevent, bool nowait) { struct firmware *firmware; + struct firmware_priv *fw_priv; if (!firmware_p) - return -EINVAL; + return ERR_PTR(-EINVAL); *firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL); if (!firmware) { dev_err(device, "%s: kmalloc(struct firmware) failed\n", __func__); - return -ENOMEM; + return ERR_PTR(-ENOMEM); } if (fw_get_builtin_firmware(firmware, name)) { dev_dbg(device, "firmware: using built-in firmware %s\n", name); - return 0; + return NULL; } - return 1; + fw_priv = fw_create_instance(firmware, name, device, uevent, nowait); + if (IS_ERR(fw_priv)) { + release_firmware(firmware); + *firmware_p = NULL; + } + return fw_priv; } static void _request_firmware_cleanup(const struct firmware **firmware_p) @@ -544,21 +505,38 @@ static void _request_firmware_cleanup(const struct firmware **firmware_p) *firmware_p = NULL; } -static int _request_firmware(const struct firmware *firmware, - const char *name, struct device *device, - bool uevent, bool nowait, long timeout) +static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent, + long timeout) { - struct firmware_priv *fw_priv; int retval = 0; + struct device *f_dev = &fw_priv->dev; + + dev_set_uevent_suppress(f_dev, true); - if (uevent) - dev_dbg(device, "firmware: requesting %s\n", name); + /* Need to pin this module until class device is destroyed */ + __module_get(THIS_MODULE); - fw_priv = fw_create_instance(firmware, name, device, uevent, nowait); - if (IS_ERR(fw_priv)) - return PTR_ERR(fw_priv); + retval = device_add(f_dev); + if (retval) { + dev_err(f_dev, "%s: device_register failed\n", __func__); + goto err_put_dev; + } + + retval = device_create_bin_file(f_dev, &firmware_attr_data); + if (retval) { + dev_err(f_dev, "%s: sysfs_create_bin_file failed\n", __func__); + goto err_del_dev; + } + + retval = device_create_file(f_dev, &dev_attr_loading); + if (retval) { + dev_err(f_dev, "%s: device_create_file failed\n", __func__); + goto err_del_bin_attr; + } if (uevent) { + dev_set_uevent_suppress(f_dev, false); + dev_dbg(f_dev, "firmware: requesting %s\n", fw_priv->fw_id); if (timeout != MAX_SCHEDULE_TIMEOUT) mod_timer(&fw_priv->timeout, round_jiffies_up(jiffies + timeout)); @@ -577,7 +555,13 @@ static int _request_firmware(const struct firmware *firmware, fw_priv->fw = NULL; mutex_unlock(&fw_lock); - fw_destroy_instance(fw_priv); + device_remove_file(f_dev, &dev_attr_loading); +err_del_bin_attr: + device_remove_bin_file(f_dev, &firmware_attr_data); +err_del_dev: + device_del(f_dev); +err_put_dev: + put_device(f_dev); return retval; } @@ -600,17 +584,19 @@ int request_firmware(const struct firmware **firmware_p, const char *name, struct device *device) { + struct firmware_priv *fw_priv; int ret; - ret = _request_firmware_prepare(firmware_p, name, device); - if (ret <= 0) - return ret; + fw_priv = _request_firmware_prepare(firmware_p, name, device, true, + false); + if (IS_ERR_OR_NULL(fw_priv)) + return PTR_RET(fw_priv); ret = usermodehelper_read_trylock(); if (WARN_ON(ret)) { dev_err(device, "firmware: %s will not be loaded\n", name); } else { - ret = _request_firmware(*firmware_p, name, device, true, false, + ret = _request_firmware_load(fw_priv, true, firmware_loading_timeout()); usermodehelper_read_unlock(); } @@ -648,6 +634,7 @@ static int request_firmware_work_func(void *arg) { struct firmware_work *fw_work = arg; const struct firmware *fw; + struct firmware_priv *fw_priv; long timeout; int ret; @@ -656,14 +643,16 @@ static int request_firmware_work_func(void *arg) return 0; } - ret = _request_firmware_prepare(&fw, fw_work->name, fw_work->device); - if (ret <= 0) + fw_priv = _request_firmware_prepare(&fw, fw_work->name, fw_work->device, + fw_work->uevent, true); + if (IS_ERR_OR_NULL(fw_priv)) { + ret = PTR_RET(fw_priv); goto out; + } timeout = usermodehelper_read_lock_wait(firmware_loading_timeout()); if (timeout) { - ret = _request_firmware(fw, fw_work->name, fw_work->device, - fw_work->uevent, true, timeout); + ret = _request_firmware_load(fw_priv, fw_work->uevent, timeout); usermodehelper_read_unlock(); } else { dev_dbg(fw_work->device, "firmware: %s loading timed out\n", -- cgit v1.2.3 From a36cf844c543c6193445a7b1492d16e5a8cf376e Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 28 Mar 2012 23:31:00 +0200 Subject: firmware_class: Move request_firmware_nowait() to workqueues Oddly enough a work_struct was already part of the firmware_work structure but nobody was using it. Instead of creating a new kthread for each request_firmware_nowait() call just schedule the work on the system workqueue. This should avoid some overhead in forking new threads when they're not strictly necessary. Signed-off-by: Stephen Boyd Acked-by: Greg Kroah-Hartman Signed-off-by: Rafael J. Wysocki --- drivers/base/firmware_class.c | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index ae00a2fd280f..5401814c874d 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -16,10 +16,11 @@ #include #include #include -#include +#include #include #include #include +#include #define to_dev(obj) container_of(obj, struct device, kobj) @@ -630,19 +631,15 @@ struct firmware_work { bool uevent; }; -static int request_firmware_work_func(void *arg) +static void request_firmware_work_func(struct work_struct *work) { - struct firmware_work *fw_work = arg; + struct firmware_work *fw_work; const struct firmware *fw; struct firmware_priv *fw_priv; long timeout; int ret; - if (!arg) { - WARN_ON(1); - return 0; - } - + fw_work = container_of(work, struct firmware_work, work); fw_priv = _request_firmware_prepare(&fw, fw_work->name, fw_work->device, fw_work->uevent, true); if (IS_ERR_OR_NULL(fw_priv)) { @@ -667,8 +664,6 @@ static int request_firmware_work_func(void *arg) module_put(fw_work->module); kfree(fw_work); - - return ret; } /** @@ -694,7 +689,6 @@ request_firmware_nowait( const char *name, struct device *device, gfp_t gfp, void *context, void (*cont)(const struct firmware *fw, void *context)) { - struct task_struct *task; struct firmware_work *fw_work; fw_work = kzalloc(sizeof (struct firmware_work), gfp); @@ -713,15 +707,8 @@ request_firmware_nowait( return -EFAULT; } - task = kthread_run(request_firmware_work_func, fw_work, - "firmware/%s", name); - if (IS_ERR(task)) { - fw_work->cont(NULL, fw_work->context); - module_put(fw_work->module); - kfree(fw_work); - return PTR_ERR(task); - } - + INIT_WORK(&fw_work->work, request_firmware_work_func); + schedule_work(&fw_work->work); return 0; } -- cgit v1.2.3 From 88d8cd52bc9dd7696617b31ea91263d6c47f22e4 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 29 Mar 2012 15:38:30 +1030 Subject: drivers/cpufreq/db8500-cpufreq: remove references to cpu_*_map. This has been obsolescent for a while; time for the final push. Signed-off-by: Rusty Russell Cc: Dave Jones Cc: cpufreq@vger.kernel.org Cc: Sundar Iyer Cc: Martin Persson Cc: Jonas Aaberg --- drivers/cpufreq/db8500-cpufreq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/cpufreq/db8500-cpufreq.c b/drivers/cpufreq/db8500-cpufreq.c index a22ffa5bff9f..0bf1b8910eeb 100644 --- a/drivers/cpufreq/db8500-cpufreq.c +++ b/drivers/cpufreq/db8500-cpufreq.c @@ -142,7 +142,7 @@ static int __cpuinit db8500_cpufreq_init(struct cpufreq_policy *policy) policy->cpuinfo.transition_latency = 20 * 1000; /* in ns */ /* policy sharing between dual CPUs */ - cpumask_copy(policy->cpus, &cpu_present_map); + cpumask_copy(policy->cpus, cpu_present_mask); policy->shared_type = CPUFREQ_SHARED_TYPE_ALL; -- cgit v1.2.3 From e841a36abb0f95ea356d52e4386b8e8f762e9c40 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 29 Mar 2012 15:02:55 +0800 Subject: regulator: Fix setting low power mode for wm831x aldo Set BIT[8] of LDO7 ON Control mode for low power mode. R16507 (407Bh) LDO7 ON Control BIT[8] LDO7_ON_MODE: LDO7 ON Operating Mode 0 = Normal mode 1 = Low Power mode Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/wm831x-ldo.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c index f1e4ab0f9fda..641e9f6499d1 100644 --- a/drivers/regulator/wm831x-ldo.c +++ b/drivers/regulator/wm831x-ldo.c @@ -506,22 +506,19 @@ static int wm831x_aldo_set_mode(struct regulator_dev *rdev, { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); struct wm831x *wm831x = ldo->wm831x; - int ctrl_reg = ldo->base + WM831X_LDO_CONTROL; int on_reg = ldo->base + WM831X_LDO_ON_CONTROL; int ret; switch (mode) { case REGULATOR_MODE_NORMAL: - ret = wm831x_set_bits(wm831x, on_reg, - WM831X_LDO7_ON_MODE, 0); + ret = wm831x_set_bits(wm831x, on_reg, WM831X_LDO7_ON_MODE, 0); if (ret < 0) return ret; break; case REGULATOR_MODE_IDLE: - ret = wm831x_set_bits(wm831x, ctrl_reg, - WM831X_LDO7_ON_MODE, + ret = wm831x_set_bits(wm831x, on_reg, WM831X_LDO7_ON_MODE, WM831X_LDO7_ON_MODE); if (ret < 0) return ret; -- cgit v1.2.3 From cee1a799eb044657922c4d63003d7bf71f8c8b8d Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 29 Mar 2012 10:47:36 +0800 Subject: regulator: Only update [LDOx|DCx]_HIB_MODE bits in wm8350_[ldo|dcdc]_set_suspend_disable What we want is to disable output by setting [LDOx|DCx]_HIB_MODE bits. Current code also clears other bits in LDOx/DCDCx Low Power register. R202 (CAh) LDO1 Low Power BIT[13:12] LDO1 Hibernate behaviour: 00 = Select voltage image settings 01 = disable output 10 = reserved 11 = reserved R182 (B6h) DCDC1 Low Power BIT[14:12] DC-DC1 Hibernate behaviour: 000 = Use current settings (no change) 001 = Select voltage image settings 010 = Force standby mode 011 = Force standby mode and voltage image settings. 100 = Force LDO mode 101 = Force LDO mode and voltage image settings. 110 = Reserved. 111 = Disable output Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/wm8350-regulator.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index c5f3b4090d87..05ecfb872319 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c @@ -535,25 +535,25 @@ static int wm8350_dcdc_set_suspend_disable(struct regulator_dev *rdev) val = wm8350_reg_read(wm8350, WM8350_DCDC1_LOW_POWER); wm8350->pmic.dcdc1_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK; wm8350_reg_write(wm8350, WM8350_DCDC1_LOW_POWER, - WM8350_DCDC_HIB_MODE_DIS); + val | WM8350_DCDC_HIB_MODE_DIS); break; case WM8350_DCDC_3: val = wm8350_reg_read(wm8350, WM8350_DCDC3_LOW_POWER); wm8350->pmic.dcdc3_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK; wm8350_reg_write(wm8350, WM8350_DCDC3_LOW_POWER, - WM8350_DCDC_HIB_MODE_DIS); + val | WM8350_DCDC_HIB_MODE_DIS); break; case WM8350_DCDC_4: val = wm8350_reg_read(wm8350, WM8350_DCDC4_LOW_POWER); wm8350->pmic.dcdc4_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK; wm8350_reg_write(wm8350, WM8350_DCDC4_LOW_POWER, - WM8350_DCDC_HIB_MODE_DIS); + val | WM8350_DCDC_HIB_MODE_DIS); break; case WM8350_DCDC_6: val = wm8350_reg_read(wm8350, WM8350_DCDC6_LOW_POWER); wm8350->pmic.dcdc6_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK; wm8350_reg_write(wm8350, WM8350_DCDC6_LOW_POWER, - WM8350_DCDC_HIB_MODE_DIS); + val | WM8350_DCDC_HIB_MODE_DIS); break; case WM8350_DCDC_2: case WM8350_DCDC_5: @@ -749,7 +749,7 @@ static int wm8350_ldo_set_suspend_disable(struct regulator_dev *rdev) /* all LDOs have same mV bits */ val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_HIB_MODE_MASK; - wm8350_reg_write(wm8350, volt_reg, WM8350_LDO1_HIB_MODE_DIS); + wm8350_reg_write(wm8350, volt_reg, val | WM8350_LDO1_HIB_MODE_DIS); return 0; } -- cgit v1.2.3 From fa1b42b45a9c96da77f3ddabf715f49525a87209 Mon Sep 17 00:00:00 2001 From: Dave Liu Date: Tue, 12 Jan 2010 00:04:03 +0000 Subject: powerpc/qe: Update the SNUM table for MPC8569 Rev2.0 The MPC8569 Rev2.0 has the correct SNUM table as QE Reference Manual, we must follow it. However the Rev1.0 silicon need the old SNUM table as workaround due to Rev1.0 silicon SNUM erratum. So, we support both snum table, and choose the one FDT tell us. And u-boot will fixup FDT according to SPRN_SVR. Signed-off-by: Liu Yu Signed-off-by: Dave Liu Signed-off-by: Kumar Gala --- arch/powerpc/sysdev/qe_lib/qe.c | 22 ++++++++++++++++++++-- drivers/net/ethernet/freescale/ucc_geth.c | 6 ++++-- 2 files changed, 24 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/arch/powerpc/sysdev/qe_lib/qe.c b/arch/powerpc/sysdev/qe_lib/qe.c index ceb09cbd2329..818e763f8265 100644 --- a/arch/powerpc/sysdev/qe_lib/qe.c +++ b/arch/powerpc/sysdev/qe_lib/qe.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved. + * Copyright (C) 2006-2010 Freescale Semicondutor, Inc. All rights reserved. * * Authors: Shlomi Gridish * Li Yang @@ -266,7 +266,19 @@ EXPORT_SYMBOL(qe_clock_source); static void qe_snums_init(void) { int i; - static const u8 snum_init[] = { + static const u8 snum_init_76[] = { + 0x04, 0x05, 0x0C, 0x0D, 0x14, 0x15, 0x1C, 0x1D, + 0x24, 0x25, 0x2C, 0x2D, 0x34, 0x35, 0x88, 0x89, + 0x98, 0x99, 0xA8, 0xA9, 0xB8, 0xB9, 0xC8, 0xC9, + 0xD8, 0xD9, 0xE8, 0xE9, 0x44, 0x45, 0x4C, 0x4D, + 0x54, 0x55, 0x5C, 0x5D, 0x64, 0x65, 0x6C, 0x6D, + 0x74, 0x75, 0x7C, 0x7D, 0x84, 0x85, 0x8C, 0x8D, + 0x94, 0x95, 0x9C, 0x9D, 0xA4, 0xA5, 0xAC, 0xAD, + 0xB4, 0xB5, 0xBC, 0xBD, 0xC4, 0xC5, 0xCC, 0xCD, + 0xD4, 0xD5, 0xDC, 0xDD, 0xE4, 0xE5, 0xEC, 0xED, + 0xF4, 0xF5, 0xFC, 0xFD, + }; + static const u8 snum_init_46[] = { 0x04, 0x05, 0x0C, 0x0D, 0x14, 0x15, 0x1C, 0x1D, 0x24, 0x25, 0x2C, 0x2D, 0x34, 0x35, 0x88, 0x89, 0x98, 0x99, 0xA8, 0xA9, 0xB8, 0xB9, 0xC8, 0xC9, @@ -274,9 +286,15 @@ static void qe_snums_init(void) 0x28, 0x29, 0x38, 0x39, 0x48, 0x49, 0x58, 0x59, 0x68, 0x69, 0x78, 0x79, 0x80, 0x81, }; + static const u8 *snum_init; qe_num_of_snum = qe_get_num_of_snums(); + if (qe_num_of_snum == 76) + snum_init = snum_init_76; + else + snum_init = snum_init_46; + for (i = 0; i < qe_num_of_snum; i++) { snums[i].num = snum_init[i]; snums[i].state = QE_SNUM_STATE_FREE; diff --git a/drivers/net/ethernet/freescale/ucc_geth.c b/drivers/net/ethernet/freescale/ucc_geth.c index 4e3cd2f8debb..17a46e76123f 100644 --- a/drivers/net/ethernet/freescale/ucc_geth.c +++ b/drivers/net/ethernet/freescale/ucc_geth.c @@ -3945,6 +3945,8 @@ static int ucc_geth_probe(struct platform_device* ofdev) } if (max_speed == SPEED_1000) { + unsigned int snums = qe_get_num_of_snums(); + /* configure muram FIFOs for gigabit operation */ ug_info->uf_info.urfs = UCC_GETH_URFS_GIGA_INIT; ug_info->uf_info.urfet = UCC_GETH_URFET_GIGA_INIT; @@ -3954,11 +3956,11 @@ static int ucc_geth_probe(struct platform_device* ofdev) ug_info->uf_info.utftt = UCC_GETH_UTFTT_GIGA_INIT; ug_info->numThreadsTx = UCC_GETH_NUM_OF_THREADS_4; - /* If QE's snum number is 46 which means we need to support + /* If QE's snum number is 46/76 which means we need to support * 4 UECs at 1000Base-T simultaneously, we need to allocate * more Threads to Rx. */ - if (qe_get_num_of_snums() == 46) + if ((snums == 76) || (snums == 46)) ug_info->numThreadsRx = UCC_GETH_NUM_OF_THREADS_6; else ug_info->numThreadsRx = UCC_GETH_NUM_OF_THREADS_4; -- cgit v1.2.3 From 4a206ffc0bfe8e8c3fc0468a052f5b0bb625a57b Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 27 Mar 2012 14:41:04 +1000 Subject: drm/nouveau: oops, create m2mf for nvd9 too Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_state.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index a4886b36d0fa..c2a8511e855a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -642,7 +642,7 @@ nouveau_card_channel_init(struct drm_device *dev) OUT_RING (chan, chan->vram_handle); OUT_RING (chan, chan->gart_handle); } else - if (dev_priv->card_type <= NV_C0) { + if (dev_priv->card_type <= NV_D0) { ret = nouveau_gpuobj_gr_new(chan, 0x9039, 0x9039); if (ret) goto error; -- cgit v1.2.3 From acde2d8037f4502669af251e44b05579681e0dc1 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 29 Mar 2012 20:21:32 +1000 Subject: Revert "drm/nouveau: inform userspace of new kernel subchannel requirements" This reverts commit a81f15499887d3f9f24ec70bb9b7e778942a6b7b. Gah, we have a released userspace component using fixed subc assignment that conflicts with this. To avoid breaking ABI this needs to be reverted. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_channel.c | 15 +++++++++++---- drivers/gpu/drm/nouveau/nouveau_dma.h | 4 ++-- 2 files changed, 13 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index 44e6416d4a33..337e228629ed 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -436,11 +436,18 @@ nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data, } if (dev_priv->card_type < NV_C0) { - init->subchan[0].handle = NvSw; - init->subchan[0].grclass = NV_SW; - init->nr_subchan = 1; + init->subchan[0].handle = NvM2MF; + if (dev_priv->card_type < NV_50) + init->subchan[0].grclass = 0x0039; + else + init->subchan[0].grclass = 0x5039; + init->subchan[1].handle = NvSw; + init->subchan[1].grclass = NV_SW; + init->nr_subchan = 2; } else { - init->nr_subchan = 0; + init->subchan[0].handle = 0x9039; + init->subchan[0].grclass = 0x9039; + init->nr_subchan = 1; } /* Named memory object area */ diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.h b/drivers/gpu/drm/nouveau/nouveau_dma.h index bcf0fd9e313e..23d4edf992b7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dma.h +++ b/drivers/gpu/drm/nouveau/nouveau_dma.h @@ -48,8 +48,8 @@ void nv50_dma_push(struct nouveau_channel *, struct nouveau_bo *, /* Hardcoded object assignments to subchannels (subchannel id). */ enum { - NvSubSw = 0, - NvSubM2MF = 1, + NvSubM2MF = 0, + NvSubSw = 1, NvSub2D = 2, NvSubCtxSurf2D = 2, NvSubGdiRect = 3, -- cgit v1.2.3 From 02bfc2881e0d5b23147211bb6420798d946a7b5c Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 29 Mar 2012 20:24:34 +1000 Subject: drm/nouveau: inform userspace of relaxed kernel subchannel requirements Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_channel.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index 337e228629ed..846afb0bfef4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -436,18 +436,11 @@ nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data, } if (dev_priv->card_type < NV_C0) { - init->subchan[0].handle = NvM2MF; - if (dev_priv->card_type < NV_50) - init->subchan[0].grclass = 0x0039; - else - init->subchan[0].grclass = 0x5039; + init->subchan[0].handle = 0x00000000; + init->subchan[0].grclass = 0x0000; init->subchan[1].handle = NvSw; init->subchan[1].grclass = NV_SW; init->nr_subchan = 2; - } else { - init->subchan[0].handle = 0x9039; - init->subchan[0].grclass = 0x9039; - init->nr_subchan = 1; } /* Named memory object area */ -- cgit v1.2.3 From e032b376551a61662b20a2c8544fbbc568ab2e7f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 28 Mar 2012 21:17:55 +0100 Subject: regulator: Fix deadlock on removal of regulators with supplies If a regulator with a supply is being unregistered we will call regulator_put() to release the supply with the regulator_list_mutex held but this deadlocks as regulator_put() takes the same lock. Fix this by releasing the supply before we take the mutex in regulator_unregister(). Signed-off-by: Mark Brown --- drivers/regulator/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index e2f3afa71efb..4a5054ef9421 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2992,14 +2992,14 @@ void regulator_unregister(struct regulator_dev *rdev) if (rdev == NULL) return; + if (rdev->supply) + regulator_put(rdev->supply); mutex_lock(®ulator_list_mutex); debugfs_remove_recursive(rdev->debugfs); flush_work_sync(&rdev->disable_work.work); WARN_ON(rdev->open_count); unset_regulator_supplies(rdev); list_del(&rdev->list); - if (rdev->supply) - regulator_put(rdev->supply); kfree(rdev->constraints); device_unregister(&rdev->dev); mutex_unlock(®ulator_list_mutex); -- cgit v1.2.3 From 7d26bb103c4162003bfdf1d63aaa32b548ad0e9a Mon Sep 17 00:00:00 2001 From: Weiping Pan Date: Tue, 27 Mar 2012 19:18:24 +0000 Subject: bonding: emit event when bonding changes MAC When a bonding device is configured with fail_over_mac=active, we expect to see the MAC address of the new active slave as the source MAC address after failover. But we see that the source MAC address is the MAC address of previous active slave. Emit NETDEV_CHANGEADDR event when bonding changes its MAC address, in order to let arp_netdev_event flush neighbour cache and route cache. How to reproduce this bug ? -----------hostB---------------- hostA ----- switch ---|-- eth0--bond0(192.168.100.2/24)| (192.168.100.1/24 \--|-- eth1-/ | -------------------------------- 1 on hostB, modprobe bonding mode=1 miimon=500 fail_over_mac=active downdelay=1000 num_grat_arp=1 ifconfig bond0 192.168.100.2/24 up ifenslave bond0 eth0 ifenslave bond0 eth1 then eth0 is the active slave, and MAC of bond0 is MAC of eth0. 2 on hostA, ping 192.168.100.2 3 on hostB, tcpdump -i bond0 -p icmp -XXX you will see bond0 uses MAC of eth0 as source MAC in icmp reply. 4 on hostB, ifconfig eth0 down tcpdump -i bond0 -p icmp -XXX (just keep it running in step 3) you will see first bond0 uses MAC of eth1 as source MAC in icmp reply, then it will use MAC of eth0 as source MAC. Signed-off-by: Weiping Pan Signed-off-by: Jay Vosburgh Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index b920d829692a..a20b5850e7ce 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -892,9 +892,15 @@ static void bond_do_fail_over_mac(struct bonding *bond, switch (bond->params.fail_over_mac) { case BOND_FOM_ACTIVE: - if (new_active) + if (new_active) { memcpy(bond->dev->dev_addr, new_active->dev->dev_addr, new_active->dev->addr_len); + write_unlock_bh(&bond->curr_slave_lock); + read_unlock(&bond->lock); + call_netdevice_notifiers(NETDEV_CHANGEADDR, bond->dev); + read_lock(&bond->lock); + write_lock_bh(&bond->curr_slave_lock); + } break; case BOND_FOM_FOLLOW: /* -- cgit v1.2.3 From 456ca7ff24841bf2d2a2dfd690fe7d42ef70d932 Mon Sep 17 00:00:00 2001 From: Jason Wessel Date: Thu, 29 Mar 2012 06:55:44 -0500 Subject: kgdbts: Fix kernel oops with CONFIG_DEBUG_RODATA On x86 the kgdb test suite will oops when the kernel is compiled with CONFIG_DEBUG_RODATA and you run the tests after boot time. This is regression has existed since 2.6.26 by commit: b33cb815 (kgdbts: Use HW breakpoints with CONFIG_DEBUG_RODATA). The test suite can use hw breakpoints for all the tests, but it has to execute the hardware breakpoint specific tests first in order to determine that the hw breakpoints actually work. Specifically the very first test causes an oops: # echo V1I1 > /sys/module/kgdbts/parameters/kgdbts kgdb: Registered I/O driver kgdbts. kgdbts:RUN plant and detach test Entering kdb (current=0xffff880017aa9320, pid 1078) on processor 0 due to Keyboard Entry [0]kdb> kgdbts: ERROR PUT: end of test buffer on 'plant_and_detach_test' line 1 expected OK got $E14#aa WARNING: at drivers/misc/kgdbts.c:730 run_simple_test+0x151/0x2c0() [...oops clipped...] This commit re-orders the running of the tests and puts the RODATA check into its own function so as to correctly avoid the kernel oops by detecting and using the hw breakpoints. Cc: # >= 2.6.26 Signed-off-by: Jason Wessel --- drivers/misc/kgdbts.c | 52 +++++++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c index 3f7ad83ed740..997e94d618ba 100644 --- a/drivers/misc/kgdbts.c +++ b/drivers/misc/kgdbts.c @@ -885,6 +885,22 @@ static void run_singlestep_break_test(void) kgdbts_break_test(); } +static void test_debug_rodata(void) +{ +#ifdef CONFIG_DEBUG_RODATA + /* Until there is an api to write to read-only text segments, use + * HW breakpoints for the remainder of any tests, else print a + * failure message if hw breakpoints do not work. + */ + if (!(arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT && hwbreaks_ok)) { + eprintk("kgdbts: HW breakpoints BROKEN, ending tests\n"); + return; + } + force_hwbrks = 1; + v1printk("kgdbts:Using HW breakpoints for SW breakpoint tests\n"); +#endif /* CONFIG_DEBUG_RODATA */ +} + static void kgdbts_run_tests(void) { char *ptr; @@ -907,6 +923,18 @@ static void kgdbts_run_tests(void) if (ptr) sstep_test = simple_strtol(ptr+1, NULL, 10); + /* All HW break point tests */ + if (arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT) { + hwbreaks_ok = 1; + v1printk("kgdbts:RUN hw breakpoint test\n"); + run_breakpoint_test(1); + v1printk("kgdbts:RUN hw write breakpoint test\n"); + run_hw_break_test(1); + v1printk("kgdbts:RUN access write breakpoint test\n"); + run_hw_break_test(0); + } + test_debug_rodata(); + /* required internal KGDB tests */ v1printk("kgdbts:RUN plant and detach test\n"); run_plant_and_detach_test(0); @@ -924,35 +952,11 @@ static void kgdbts_run_tests(void) /* ===Optional tests=== */ - /* All HW break point tests */ - if (arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT) { - hwbreaks_ok = 1; - v1printk("kgdbts:RUN hw breakpoint test\n"); - run_breakpoint_test(1); - v1printk("kgdbts:RUN hw write breakpoint test\n"); - run_hw_break_test(1); - v1printk("kgdbts:RUN access write breakpoint test\n"); - run_hw_break_test(0); - } - if (nmi_sleep) { v1printk("kgdbts:RUN NMI sleep %i seconds test\n", nmi_sleep); run_nmi_sleep_test(nmi_sleep); } -#ifdef CONFIG_DEBUG_RODATA - /* Until there is an api to write to read-only text segments, use - * HW breakpoints for the remainder of any tests, else print a - * failure message if hw breakpoints do not work. - */ - if (!(arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT && hwbreaks_ok)) { - eprintk("kgdbts: HW breakpoints do not work," - "skipping remaining tests\n"); - return; - } - force_hwbrks = 1; -#endif /* CONFIG_DEBUG_RODATA */ - /* If the do_fork test is run it will be the last test that is * executed because a kernel thread will be spawned at the very * end to unregister the debug hooks. -- cgit v1.2.3 From 486c5987a00a89d56c2c04c506417ef8f823ca2e Mon Sep 17 00:00:00 2001 From: Jason Wessel Date: Thu, 29 Mar 2012 17:41:24 -0500 Subject: kgdbts: (1 of 2) fix single step awareness to work correctly with SMP The do_fork and sys_open tests have never worked properly on anything other than a UP configuration with the kgdb test suite. This is because the test suite did not fully implement the behavior of a real debugger. A real debugger tracks the state of what thread it asked to single step and can correctly continue other threads of execution or conditionally stop while waiting for the original thread single step request to return. Below is a simple method to cause a fatal kernel oops with the kgdb test suite on a 4 processor x86 system: while [ 1 ] ; do ls > /dev/null 2> /dev/null; done& while [ 1 ] ; do ls > /dev/null 2> /dev/null; done& while [ 1 ] ; do ls > /dev/null 2> /dev/null; done& while [ 1 ] ; do ls > /dev/null 2> /dev/null; done& echo V1I1F1000 > /sys/module/kgdbts/parameters/kgdbts Very soon after starting the test the kernel will oops with a message like: kgdbts: BP mismatch 3b7da66480 expected ffffffff8106a590 WARNING: at drivers/misc/kgdbts.c:303 check_and_rewind_pc+0xe0/0x100() Call Trace: [] check_and_rewind_pc+0xe0/0x100 [] validate_simple_test+0x25/0xc0 [] run_simple_test+0x107/0x2c0 [] kgdbts_put_char+0x18/0x20 The warn will turn to a hard kernel crash shortly after that because the pc will not get properly rewound to the right value after hitting a breakpoint leading to a hard lockup. This change is broken up into 2 pieces because archs that have hw single stepping (2.6.26 and up) need different changes than archs that do not have hw single stepping (3.0 and up). This change implements the correct behavior for an arch that supports hw single stepping. A minor defect was fixed where sys_open should be do_sys_open for the sys_open break point test. This solves the problem of running a 64 bit with a 32 bit user space. The sys_open() never gets called when using the 32 bit file system for the kgdb testsuite because the 32 bit binaries invoke the compat_sys_open() call leading to the test never completing. In order to mimic a real debugger, the kgdb test suite now tracks the most recent thread that was continued (cont_thread_id), with the intent to single step just this thread. When the response to the single step request stops in a different thread that hit the original break point that thread will now get continued, while the debugger waits for the thread with the single step pending. Here is a high level description of the sequence of events. cont_instead_of_sstep = 0; 1) set breakpoint at do_fork 2) continue 3) Save the thread id where we stop to cont_thread_id 4) Remove breakpoint at do_fork 5) Reset the PC if needed depending on kernel exception type 6) if (cont_instead_of_sstep) { continue } else { single step } 7) Check where we stopped if current thread != cont_thread_id { cont_instead_of_sstep = 1; goto step 5 } else { cont_instead_of_sstep = 0; } 8) clean up and run test again if needed Cc: stable@vger.kernel.org # >= 2.6.26 Signed-off-by: Jason Wessel --- drivers/misc/kgdbts.c | 54 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c index 997e94d618ba..3cad9fce8054 100644 --- a/drivers/misc/kgdbts.c +++ b/drivers/misc/kgdbts.c @@ -134,6 +134,9 @@ static int force_hwbrks; static int hwbreaks_ok; static int hw_break_val; static int hw_break_val2; +static int cont_instead_of_sstep; +static unsigned long cont_thread_id; +static unsigned long sstep_thread_id; #if defined(CONFIG_ARM) || defined(CONFIG_MIPS) || defined(CONFIG_SPARC) static int arch_needs_sstep_emulation = 1; #else @@ -211,7 +214,7 @@ static unsigned long lookup_addr(char *arg) if (!strcmp(arg, "kgdbts_break_test")) addr = (unsigned long)kgdbts_break_test; else if (!strcmp(arg, "sys_open")) - addr = (unsigned long)sys_open; + addr = (unsigned long)do_sys_open; else if (!strcmp(arg, "do_fork")) addr = (unsigned long)do_fork; else if (!strcmp(arg, "hw_break_val")) @@ -283,6 +286,16 @@ static void hw_break_val_write(void) hw_break_val++; } +static int get_thread_id_continue(char *put_str, char *arg) +{ + char *ptr = &put_str[11]; + + if (put_str[1] != 'T' || put_str[2] != '0') + return 1; + kgdb_hex2long(&ptr, &cont_thread_id); + return 0; +} + static int check_and_rewind_pc(char *put_str, char *arg) { unsigned long addr = lookup_addr(arg); @@ -324,6 +337,18 @@ static int check_single_step(char *put_str, char *arg) gdb_regs_to_pt_regs(kgdbts_gdb_regs, &kgdbts_regs); v2printk("Singlestep stopped at IP: %lx\n", instruction_pointer(&kgdbts_regs)); + + if (sstep_thread_id != cont_thread_id && !arch_needs_sstep_emulation) { + /* + * Ensure we stopped in the same thread id as before, else the + * debugger should continue until the original thread that was + * single stepped is scheduled again, emulating gdb's behavior. + */ + v2printk("ThrID does not match: %lx\n", cont_thread_id); + cont_instead_of_sstep = 1; + ts.idx -= 4; + return 0; + } if (instruction_pointer(&kgdbts_regs) == addr) { eprintk("kgdbts: SingleStep failed at %lx\n", instruction_pointer(&kgdbts_regs)); @@ -368,7 +393,12 @@ static int got_break(char *put_str, char *arg) static void emul_sstep_get(char *arg) { if (!arch_needs_sstep_emulation) { - fill_get_buf(arg); + if (cont_instead_of_sstep) { + cont_instead_of_sstep = 0; + fill_get_buf("c"); + } else { + fill_get_buf(arg); + } return; } switch (sstep_state) { @@ -398,9 +428,11 @@ static void emul_sstep_get(char *arg) static int emul_sstep_put(char *put_str, char *arg) { if (!arch_needs_sstep_emulation) { - if (!strncmp(put_str+1, arg, 2)) - return 0; - return 1; + char *ptr = &put_str[11]; + if (put_str[1] != 'T' || put_str[2] != '0') + return 1; + kgdb_hex2long(&ptr, &sstep_thread_id); + return 0; } switch (sstep_state) { case 1: @@ -502,10 +534,10 @@ static struct test_struct bad_read_test[] = { static struct test_struct singlestep_break_test[] = { { "?", "S0*" }, /* Clear break points */ { "kgdbts_break_test", "OK", sw_break, }, /* set sw breakpoint */ - { "c", "T0*", }, /* Continue */ + { "c", "T0*", NULL, get_thread_id_continue }, /* Continue */ + { "kgdbts_break_test", "OK", sw_rem_break }, /*remove breakpoint */ { "g", "kgdbts_break_test", NULL, check_and_rewind_pc }, { "write", "OK", write_regs }, /* Write registers */ - { "kgdbts_break_test", "OK", sw_rem_break }, /*remove breakpoint */ { "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */ { "g", "kgdbts_break_test", NULL, check_single_step }, { "kgdbts_break_test", "OK", sw_break, }, /* set sw breakpoint */ @@ -523,10 +555,10 @@ static struct test_struct singlestep_break_test[] = { static struct test_struct do_fork_test[] = { { "?", "S0*" }, /* Clear break points */ { "do_fork", "OK", sw_break, }, /* set sw breakpoint */ - { "c", "T0*", }, /* Continue */ + { "c", "T0*", NULL, get_thread_id_continue }, /* Continue */ + { "do_fork", "OK", sw_rem_break }, /*remove breakpoint */ { "g", "do_fork", NULL, check_and_rewind_pc }, /* check location */ { "write", "OK", write_regs }, /* Write registers */ - { "do_fork", "OK", sw_rem_break }, /*remove breakpoint */ { "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */ { "g", "do_fork", NULL, check_single_step }, { "do_fork", "OK", sw_break, }, /* set sw breakpoint */ @@ -541,10 +573,10 @@ static struct test_struct do_fork_test[] = { static struct test_struct sys_open_test[] = { { "?", "S0*" }, /* Clear break points */ { "sys_open", "OK", sw_break, }, /* set sw breakpoint */ - { "c", "T0*", }, /* Continue */ + { "c", "T0*", NULL, get_thread_id_continue }, /* Continue */ + { "sys_open", "OK", sw_rem_break }, /*remove breakpoint */ { "g", "sys_open", NULL, check_and_rewind_pc }, /* check location */ { "write", "OK", write_regs }, /* Write registers */ - { "sys_open", "OK", sw_rem_break }, /*remove breakpoint */ { "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */ { "g", "sys_open", NULL, check_single_step }, { "sys_open", "OK", sw_break, }, /* set sw breakpoint */ -- cgit v1.2.3 From 23bbd8e346f1ef3fc1219c79cea53d8d52b207d8 Mon Sep 17 00:00:00 2001 From: Jason Wessel Date: Thu, 29 Mar 2012 17:41:24 -0500 Subject: kgdbts: (2 of 2) fix single step awareness to work correctly with SMP The do_fork and sys_open tests have never worked properly on anything other than a UP configuration with the kgdb test suite. This is because the test suite did not fully implement the behavior of a real debugger. A real debugger tracks the state of what thread it asked to single step and can correctly continue other threads of execution or conditionally stop while waiting for the original thread single step request to return. Below is a simple method to cause a fatal kernel oops with the kgdb test suite on a 2 processor ARM system: while [ 1 ] ; do ls > /dev/null 2> /dev/null; done& while [ 1 ] ; do ls > /dev/null 2> /dev/null; done& echo V1I1F100 > /sys/module/kgdbts/parameters/kgdbts Very soon after starting the test the kernel will start warning with messages like: kgdbts: BP mismatch c002487c expected c0024878 ------------[ cut here ]------------ WARNING: at drivers/misc/kgdbts.c:317 check_and_rewind_pc+0x9c/0xc4() [] (check_and_rewind_pc+0x9c/0xc4) [] (validate_simple_test+0x3c/0xc4) [] (run_simple_test+0x1e8/0x274) The kernel will eventually recovers, but the test suite has completely failed to test anything useful. This patch implements behavior similar to a real debugger that does not rely on hardware single stepping by using only software planted breakpoints. In order to mimic a real debugger, the kgdb test suite now tracks the most recent thread that was continued (cont_thread_id), with the intent to single step just this thread. When the response to the single step request stops in a different thread that hit the original break point that thread will now get continued, while the debugger waits for the thread with the single step pending. Here is a high level description of the sequence of events. cont_instead_of_sstep = 0; 1) set breakpoint at do_fork 2) continue 3) Save the thread id where we stop to cont_thread_id 4) Remove breakpoint at do_fork 5) Reset the PC if needed depending on kernel exception type 6) soft single step 7) Check where we stopped if current thread != cont_thread_id { if (here for more than 2 times for the same thead) { ### must be a really busy system, start test again ### goto step 1 } goto step 5 } else { cont_instead_of_sstep = 0; } 8) clean up and run test again if needed 9) Clear out any threads that were waiting on a break point at the point in time the test is ended with get_cont_catch(). This happens sometimes because breakpoints are used in place of single stepping and some threads could have been in the debugger exception handling queue because breakpoints were hit concurrently on different CPUs. This also means we wait at least one second before unplumbing the debugger connection at the very end, so as respond to any debug threads waiting to be serviced. Cc: stable@vger.kernel.org # >= 3.0 Signed-off-by: Jason Wessel --- drivers/misc/kgdbts.c | 73 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 62 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c index 3cad9fce8054..d087456ba089 100644 --- a/drivers/misc/kgdbts.c +++ b/drivers/misc/kgdbts.c @@ -142,7 +142,9 @@ static int arch_needs_sstep_emulation = 1; #else static int arch_needs_sstep_emulation; #endif +static unsigned long cont_addr; static unsigned long sstep_addr; +static int restart_from_top_after_write; static int sstep_state; /* Storage for the registers, in GDB format. */ @@ -190,7 +192,8 @@ static int kgdbts_unreg_thread(void *ptr) */ while (!final_ack) msleep_interruptible(1500); - + /* Pause for any other threads to exit after final ack. */ + msleep_interruptible(1000); if (configured) kgdb_unregister_io_module(&kgdbts_io_ops); configured = 0; @@ -312,13 +315,21 @@ static int check_and_rewind_pc(char *put_str, char *arg) if (addr + BREAK_INSTR_SIZE == ip) offset = -BREAK_INSTR_SIZE; #endif - if (strcmp(arg, "silent") && ip + offset != addr) { + + if (arch_needs_sstep_emulation && sstep_addr && + ip + offset == sstep_addr && + ((!strcmp(arg, "sys_open") || !strcmp(arg, "do_fork")))) { + /* This is special case for emulated single step */ + v2printk("Emul: rewind hit single step bp\n"); + restart_from_top_after_write = 1; + } else if (strcmp(arg, "silent") && ip + offset != addr) { eprintk("kgdbts: BP mismatch %lx expected %lx\n", ip + offset, addr); return 1; } /* Readjust the instruction pointer if needed */ ip += offset; + cont_addr = ip; #ifdef GDB_ADJUSTS_BREAK_OFFSET instruction_pointer_set(&kgdbts_regs, ip); #endif @@ -328,6 +339,8 @@ static int check_and_rewind_pc(char *put_str, char *arg) static int check_single_step(char *put_str, char *arg) { unsigned long addr = lookup_addr(arg); + static int matched_id; + /* * From an arch indepent point of view the instruction pointer * should be on a different instruction @@ -338,17 +351,28 @@ static int check_single_step(char *put_str, char *arg) v2printk("Singlestep stopped at IP: %lx\n", instruction_pointer(&kgdbts_regs)); - if (sstep_thread_id != cont_thread_id && !arch_needs_sstep_emulation) { + if (sstep_thread_id != cont_thread_id) { /* * Ensure we stopped in the same thread id as before, else the * debugger should continue until the original thread that was * single stepped is scheduled again, emulating gdb's behavior. */ v2printk("ThrID does not match: %lx\n", cont_thread_id); + if (arch_needs_sstep_emulation) { + if (matched_id && + instruction_pointer(&kgdbts_regs) != addr) + goto continue_test; + matched_id++; + ts.idx -= 2; + sstep_state = 0; + return 0; + } cont_instead_of_sstep = 1; ts.idx -= 4; return 0; } +continue_test: + matched_id = 0; if (instruction_pointer(&kgdbts_regs) == addr) { eprintk("kgdbts: SingleStep failed at %lx\n", instruction_pointer(&kgdbts_regs)); @@ -390,6 +414,31 @@ static int got_break(char *put_str, char *arg) return 1; } +static void get_cont_catch(char *arg) +{ + /* Always send detach because the test is completed at this point */ + fill_get_buf("D"); +} + +static int put_cont_catch(char *put_str, char *arg) +{ + /* This is at the end of the test and we catch any and all input */ + v2printk("kgdbts: cleanup task: %lx\n", sstep_thread_id); + ts.idx--; + return 0; +} + +static int emul_reset(char *put_str, char *arg) +{ + if (strncmp(put_str, "$OK", 3)) + return 1; + if (restart_from_top_after_write) { + restart_from_top_after_write = 0; + ts.idx = -1; + } + return 0; +} + static void emul_sstep_get(char *arg) { if (!arch_needs_sstep_emulation) { @@ -443,8 +492,7 @@ static int emul_sstep_put(char *put_str, char *arg) v2printk("Stopped at IP: %lx\n", instruction_pointer(&kgdbts_regs)); /* Want to stop at IP + break instruction size by default */ - sstep_addr = instruction_pointer(&kgdbts_regs) + - BREAK_INSTR_SIZE; + sstep_addr = cont_addr + BREAK_INSTR_SIZE; break; case 2: if (strncmp(put_str, "$OK", 3)) { @@ -456,6 +504,9 @@ static int emul_sstep_put(char *put_str, char *arg) if (strncmp(put_str, "$T0", 3)) { eprintk("kgdbts: failed continue sstep\n"); return 1; + } else { + char *ptr = &put_str[11]; + kgdb_hex2long(&ptr, &sstep_thread_id); } break; case 4: @@ -558,13 +609,13 @@ static struct test_struct do_fork_test[] = { { "c", "T0*", NULL, get_thread_id_continue }, /* Continue */ { "do_fork", "OK", sw_rem_break }, /*remove breakpoint */ { "g", "do_fork", NULL, check_and_rewind_pc }, /* check location */ - { "write", "OK", write_regs }, /* Write registers */ + { "write", "OK", write_regs, emul_reset }, /* Write registers */ { "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */ { "g", "do_fork", NULL, check_single_step }, { "do_fork", "OK", sw_break, }, /* set sw breakpoint */ { "7", "T0*", skip_back_repeat_test }, /* Loop based on repeat_test */ { "D", "OK", NULL, final_ack_set }, /* detach and unregister I/O */ - { "", "" }, + { "", "", get_cont_catch, put_cont_catch }, }; /* Test for hitting a breakpoint at sys_open for what ever the number @@ -576,13 +627,13 @@ static struct test_struct sys_open_test[] = { { "c", "T0*", NULL, get_thread_id_continue }, /* Continue */ { "sys_open", "OK", sw_rem_break }, /*remove breakpoint */ { "g", "sys_open", NULL, check_and_rewind_pc }, /* check location */ - { "write", "OK", write_regs }, /* Write registers */ + { "write", "OK", write_regs, emul_reset }, /* Write registers */ { "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */ { "g", "sys_open", NULL, check_single_step }, { "sys_open", "OK", sw_break, }, /* set sw breakpoint */ { "7", "T0*", skip_back_repeat_test }, /* Loop based on repeat_test */ { "D", "OK", NULL, final_ack_set }, /* detach and unregister I/O */ - { "", "" }, + { "", "", get_cont_catch, put_cont_catch }, }; /* @@ -725,8 +776,8 @@ static int run_simple_test(int is_get_char, int chr) /* This callback is a put char which is when kgdb sends data to * this I/O module. */ - if (ts.tst[ts.idx].get[0] == '\0' && - ts.tst[ts.idx].put[0] == '\0') { + if (ts.tst[ts.idx].get[0] == '\0' && ts.tst[ts.idx].put[0] == '\0' && + !ts.tst[ts.idx].get_handler) { eprintk("kgdbts: ERROR: beyond end of test on" " '%s' line %i\n", ts.name, ts.idx); return 0; -- cgit v1.2.3 From 3751d3e85cf693e10e2c47c03c8caa65e171099b Mon Sep 17 00:00:00 2001 From: Jason Wessel Date: Fri, 23 Mar 2012 09:35:05 -0500 Subject: x86,kgdb: Fix DEBUG_RODATA limitation using text_poke() There has long been a limitation using software breakpoints with a kernel compiled with CONFIG_DEBUG_RODATA going back to 2.6.26. For this particular patch, it will apply cleanly and has been tested all the way back to 2.6.36. The kprobes code uses the text_poke() function which accommodates writing a breakpoint into a read-only page. The x86 kgdb code can solve the problem similarly by overriding the default breakpoint set/remove routines and using text_poke() directly. The x86 kgdb code will first attempt to use the traditional probe_kernel_write(), and next try using a the text_poke() function. The break point install method is tracked such that the correct break point removal routine will get called later on. Cc: x86@kernel.org Cc: Thomas Gleixner Cc: Ingo Molnar Cc: H. Peter Anvin Cc: stable@vger.kernel.org # >= 2.6.36 Inspried-by: Masami Hiramatsu Signed-off-by: Jason Wessel --- arch/x86/kernel/kgdb.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/misc/kgdbts.c | 17 -------------- include/linux/kgdb.h | 3 ++- 3 files changed, 62 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c index fdc37b3d0ce3..b9bd9d8de665 100644 --- a/arch/x86/kernel/kgdb.c +++ b/arch/x86/kernel/kgdb.c @@ -43,6 +43,8 @@ #include #include #include +#include +#include #include #include @@ -742,6 +744,64 @@ void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long ip) regs->ip = ip; } +int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt) +{ + int err; + char opc[BREAK_INSTR_SIZE]; + + bpt->type = BP_BREAKPOINT; + err = probe_kernel_read(bpt->saved_instr, (char *)bpt->bpt_addr, + BREAK_INSTR_SIZE); + if (err) + return err; + err = probe_kernel_write((char *)bpt->bpt_addr, + arch_kgdb_ops.gdb_bpt_instr, BREAK_INSTR_SIZE); +#ifdef CONFIG_DEBUG_RODATA + if (!err) + return err; + /* + * It is safe to call text_poke() because normal kernel execution + * is stopped on all cores, so long as the text_mutex is not locked. + */ + if (mutex_is_locked(&text_mutex)) + return -EBUSY; + text_poke((void *)bpt->bpt_addr, arch_kgdb_ops.gdb_bpt_instr, + BREAK_INSTR_SIZE); + err = probe_kernel_read(opc, (char *)bpt->bpt_addr, BREAK_INSTR_SIZE); + if (err) + return err; + if (memcmp(opc, arch_kgdb_ops.gdb_bpt_instr, BREAK_INSTR_SIZE)) + return -EINVAL; + bpt->type = BP_POKE_BREAKPOINT; +#endif /* CONFIG_DEBUG_RODATA */ + return err; +} + +int kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt) +{ +#ifdef CONFIG_DEBUG_RODATA + int err; + char opc[BREAK_INSTR_SIZE]; + + if (bpt->type != BP_POKE_BREAKPOINT) + goto knl_write; + /* + * It is safe to call text_poke() because normal kernel execution + * is stopped on all cores, so long as the text_mutex is not locked. + */ + if (mutex_is_locked(&text_mutex)) + goto knl_write; + text_poke((void *)bpt->bpt_addr, bpt->saved_instr, BREAK_INSTR_SIZE); + err = probe_kernel_read(opc, (char *)bpt->bpt_addr, BREAK_INSTR_SIZE); + if (err || memcmp(opc, bpt->saved_instr, BREAK_INSTR_SIZE)) + goto knl_write; + return err; +knl_write: +#endif /* CONFIG_DEBUG_RODATA */ + return probe_kernel_write((char *)bpt->bpt_addr, + (char *)bpt->saved_instr, BREAK_INSTR_SIZE); +} + struct kgdb_arch arch_kgdb_ops = { /* Breakpoint instruction: */ .gdb_bpt_instr = { 0xcc }, diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c index d087456ba089..3aa9a969b373 100644 --- a/drivers/misc/kgdbts.c +++ b/drivers/misc/kgdbts.c @@ -968,22 +968,6 @@ static void run_singlestep_break_test(void) kgdbts_break_test(); } -static void test_debug_rodata(void) -{ -#ifdef CONFIG_DEBUG_RODATA - /* Until there is an api to write to read-only text segments, use - * HW breakpoints for the remainder of any tests, else print a - * failure message if hw breakpoints do not work. - */ - if (!(arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT && hwbreaks_ok)) { - eprintk("kgdbts: HW breakpoints BROKEN, ending tests\n"); - return; - } - force_hwbrks = 1; - v1printk("kgdbts:Using HW breakpoints for SW breakpoint tests\n"); -#endif /* CONFIG_DEBUG_RODATA */ -} - static void kgdbts_run_tests(void) { char *ptr; @@ -1016,7 +1000,6 @@ static void kgdbts_run_tests(void) v1printk("kgdbts:RUN access write breakpoint test\n"); run_hw_break_test(0); } - test_debug_rodata(); /* required internal KGDB tests */ v1printk("kgdbts:RUN plant and detach test\n"); diff --git a/include/linux/kgdb.h b/include/linux/kgdb.h index e5d689c1d774..c4d2fc194ede 100644 --- a/include/linux/kgdb.h +++ b/include/linux/kgdb.h @@ -63,7 +63,8 @@ enum kgdb_bptype { BP_HARDWARE_BREAKPOINT, BP_WRITE_WATCHPOINT, BP_READ_WATCHPOINT, - BP_ACCESS_WATCHPOINT + BP_ACCESS_WATCHPOINT, + BP_POKE_BREAKPOINT, }; enum kgdb_bpstate { -- cgit v1.2.3 From f6365201d8a21fb347260f89d6e9b3e718d63c70 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Thu, 29 Mar 2012 14:49:17 -0700 Subject: x86: Remove the ancient and deprecated disable_hlt() and enable_hlt() facility The X86_32-only disable_hlt/enable_hlt mechanism was used by the 32-bit floppy driver. Its effect was to replace the use of the HLT instruction inside default_idle() with cpu_relax() - essentially it turned off the use of HLT. This workaround was commented in the code as: "disable hlt during certain critical i/o operations" "This halt magic was a workaround for ancient floppy DMA wreckage. It should be safe to remove." H. Peter Anvin additionally adds: "To the best of my knowledge, no-hlt only existed because of flaky power distributions on 386/486 systems which were sold to run DOS. Since DOS did no power management of any kind, including HLT, the power draw was fairly uniform; when exposed to the much hhigher noise levels you got when Linux used HLT caused some of these systems to fail. They were by far in the minority even back then." Alan Cox further says: "Also for the Cyrix 5510 which tended to go castors up if a HLT occurred during a DMA cycle and on a few other boxes HLT during DMA tended to go astray. Do we care ? I doubt it. The 5510 was pretty obscure, the 5520 fixed it, the 5530 is probably the oldest still in any kind of use." So, let's finally drop this. Signed-off-by: Len Brown Signed-off-by: Josh Boyer Signed-off-by: Andrew Morton Acked-by: "H. Peter Anvin" Acked-by: Alan Cox Cc: Stephen Hemminger Cc: Link: http://lkml.kernel.org/n/tip-3rhk9bzf0x9rljkv488tloib@git.kernel.org [ If anyone cares then alternative instruction patching could be used to replace HLT with a one-byte NOP instruction. Much simpler. ] Signed-off-by: Ingo Molnar --- Documentation/feature-removal-schedule.txt | 8 ------- arch/x86/include/asm/processor.h | 10 --------- arch/x86/kernel/process.c | 24 -------------------- drivers/block/floppy.c | 36 ------------------------------ 4 files changed, 78 deletions(-) (limited to 'drivers') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 0cad4803ffac..7c950d48d76e 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -6,14 +6,6 @@ be removed from this file. --------------------------- -What: x86 floppy disable_hlt -When: 2012 -Why: ancient workaround of dubious utility clutters the - code used by everybody else. -Who: Len Brown - ---------------------------- - What: CONFIG_APM_CPU_IDLE, and its ability to call APM BIOS in idle When: 2012 Why: This optional sub-feature of APM is of dubious reliability, diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 7284c9a6a0b5..4fa7dcceb6c0 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -974,16 +974,6 @@ extern bool cpu_has_amd_erratum(const int *); #define cpu_has_amd_erratum(x) (false) #endif /* CONFIG_CPU_SUP_AMD */ -#ifdef CONFIG_X86_32 -/* - * disable hlt during certain critical i/o operations - */ -#define HAVE_DISABLE_HLT -#endif - -void disable_hlt(void); -void enable_hlt(void); - void cpu_idle_wait(void); extern unsigned long arch_align_stack(unsigned long sp); diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index a33afaa5ddb7..1d92a5ab6e8b 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -362,34 +362,10 @@ void (*pm_idle)(void); EXPORT_SYMBOL(pm_idle); #endif -#ifdef CONFIG_X86_32 -/* - * This halt magic was a workaround for ancient floppy DMA - * wreckage. It should be safe to remove. - */ -static int hlt_counter; -void disable_hlt(void) -{ - hlt_counter++; -} -EXPORT_SYMBOL(disable_hlt); - -void enable_hlt(void) -{ - hlt_counter--; -} -EXPORT_SYMBOL(enable_hlt); - -static inline int hlt_use_halt(void) -{ - return (!hlt_counter && boot_cpu_data.hlt_works_ok); -} -#else static inline int hlt_use_halt(void) { return 1; } -#endif #ifndef CONFIG_SMP static inline void play_dead(void) diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 76a08236430a..b0b00d70c166 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -1030,37 +1030,6 @@ static int fd_wait_for_completion(unsigned long delay, timeout_fn function) return 0; } -static DEFINE_SPINLOCK(floppy_hlt_lock); -static int hlt_disabled; -static void floppy_disable_hlt(void) -{ - unsigned long flags; - - WARN_ONCE(1, "floppy_disable_hlt() scheduled for removal in 2012"); - spin_lock_irqsave(&floppy_hlt_lock, flags); - if (!hlt_disabled) { - hlt_disabled = 1; -#ifdef HAVE_DISABLE_HLT - disable_hlt(); -#endif - } - spin_unlock_irqrestore(&floppy_hlt_lock, flags); -} - -static void floppy_enable_hlt(void) -{ - unsigned long flags; - - spin_lock_irqsave(&floppy_hlt_lock, flags); - if (hlt_disabled) { - hlt_disabled = 0; -#ifdef HAVE_DISABLE_HLT - enable_hlt(); -#endif - } - spin_unlock_irqrestore(&floppy_hlt_lock, flags); -} - static void setup_DMA(void) { unsigned long f; @@ -1105,7 +1074,6 @@ static void setup_DMA(void) fd_enable_dma(); release_dma_lock(f); #endif - floppy_disable_hlt(); } static void show_floppy(void); @@ -1707,7 +1675,6 @@ irqreturn_t floppy_interrupt(int irq, void *dev_id) fd_disable_dma(); release_dma_lock(f); - floppy_enable_hlt(); do_floppy = NULL; if (fdc >= N_FDC || FDCS->address == -1) { /* we don't even know which FDC is the culprit */ @@ -1856,8 +1823,6 @@ static void floppy_shutdown(unsigned long data) show_floppy(); cancel_activity(); - floppy_enable_hlt(); - flags = claim_dma_lock(); fd_disable_dma(); release_dma_lock(flags); @@ -4508,7 +4473,6 @@ static void floppy_release_irq_and_dma(void) #if N_FDC > 1 set_dor(1, ~8, 0); #endif - floppy_enable_hlt(); if (floppy_track_buffer && max_buffer_sectors) { tmpsize = max_buffer_sectors * 1024; -- cgit v1.2.3 From d9d54540147336c75f81c36c342b3bfec0d4d60d Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 30 Mar 2012 11:44:15 +0100 Subject: ARM: sa11x0: fix build errors from DMA engine API updates The recent merge of the sa11x0 code into mainline had silent conflicts with further development of the DMA engine API, leading to build errors and warnings: drivers/net/irda/sa1100_ir.c: In function 'sa1100_irda_dma_start': drivers/net/irda/sa1100_ir.c:151: error: too few arguments to function 'chan->device->device_prep_slave_sg' drivers/dma/sa11x0-dma.c: In function 'sa11x0_dma_probe': drivers/dma/sa11x0-dma.c:950: warning: assignment from incompatible pointer type Fix these. Signed-off-by: Russell King --- drivers/dma/sa11x0-dma.c | 2 +- drivers/net/irda/sa1100_ir.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/sa11x0-dma.c b/drivers/dma/sa11x0-dma.c index 16a6b48883cf..ec78ccef9132 100644 --- a/drivers/dma/sa11x0-dma.c +++ b/drivers/dma/sa11x0-dma.c @@ -585,7 +585,7 @@ static dma_cookie_t sa11x0_dma_tx_submit(struct dma_async_tx_descriptor *tx) static struct dma_async_tx_descriptor *sa11x0_dma_prep_slave_sg( struct dma_chan *chan, struct scatterlist *sg, unsigned int sglen, - enum dma_transfer_direction dir, unsigned long flags) + enum dma_transfer_direction dir, unsigned long flags, void *context) { struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan); struct sa11x0_dma_desc *txd; diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index a0d1913a58d3..e25067552b20 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c @@ -147,7 +147,7 @@ static void sa1100_irda_dma_start(struct sa1100_buf *buf, struct dma_async_tx_descriptor *desc; struct dma_chan *chan = buf->chan; - desc = chan->device->device_prep_slave_sg(chan, &buf->sg, 1, dir, + desc = dmaengine_prep_slave_sg(chan, &buf->sg, 1, dir, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (desc) { desc->callback = cb; -- cgit v1.2.3 From b12bb29f847050b8e75e445c839a2d42989213df Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Fri, 30 Mar 2012 19:50:15 +0900 Subject: serial: sh-sci: use serial_port_in/out vs sci_in/out. Follows the 8250 change for pretty much the same rationale. See commit "serial: use serial_port_in/out vs serial_in/out in 8250". Signed-off-by: Paul Mundt --- drivers/tty/serial/sh-sci.c | 167 ++++++++++++++++++++++---------------------- drivers/tty/serial/sh-sci.h | 8 +-- 2 files changed, 86 insertions(+), 89 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index bf461cf99616..3158e17b665c 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -355,9 +355,6 @@ static void sci_serial_out(struct uart_port *p, int offset, int value) WARN(1, "Invalid register access\n"); } -#define sci_in(up, offset) (up->serial_in(up, offset)) -#define sci_out(up, offset, value) (up->serial_out(up, offset, value)) - static int sci_probe_regmap(struct plat_sci_port *cfg) { switch (cfg->type) { @@ -422,9 +419,9 @@ static int sci_poll_get_char(struct uart_port *port) int c; do { - status = sci_in(port, SCxSR); + status = serial_port_in(port, SCxSR); if (status & SCxSR_ERRORS(port)) { - sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); + serial_port_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); continue; } break; @@ -433,11 +430,11 @@ static int sci_poll_get_char(struct uart_port *port) if (!(status & SCxSR_RDxF(port))) return NO_POLL_CHAR; - c = sci_in(port, SCxRDR); + c = serial_port_in(port, SCxRDR); /* Dummy read */ - sci_in(port, SCxSR); - sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); + serial_port_in(port, SCxSR); + serial_port_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); return c; } @@ -448,11 +445,11 @@ static void sci_poll_put_char(struct uart_port *port, unsigned char c) unsigned short status; do { - status = sci_in(port, SCxSR); + status = serial_port_in(port, SCxSR); } while (!(status & SCxSR_TDxE(port))); - sci_out(port, SCxTDR, c); - sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port)); + serial_port_out(port, SCxTDR, c); + serial_port_out(port, SCxSR, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port)); } #endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE */ @@ -480,10 +477,10 @@ static void sci_init_pins(struct uart_port *port, unsigned int cflag) ((!(cflag & CRTSCTS)))) { unsigned short status; - status = sci_in(port, SCSPTR); + status = serial_port_in(port, SCSPTR); status &= ~SCSPTR_CTSIO; status |= SCSPTR_RTSIO; - sci_out(port, SCSPTR, status); /* Set RTS = 1 */ + serial_port_out(port, SCSPTR, status); /* Set RTS = 1 */ } } @@ -493,13 +490,13 @@ static int sci_txfill(struct uart_port *port) reg = sci_getreg(port, SCTFDR); if (reg->size) - return sci_in(port, SCTFDR) & 0xff; + return serial_port_in(port, SCTFDR) & 0xff; reg = sci_getreg(port, SCFDR); if (reg->size) - return sci_in(port, SCFDR) >> 8; + return serial_port_in(port, SCFDR) >> 8; - return !(sci_in(port, SCxSR) & SCI_TDRE); + return !(serial_port_in(port, SCxSR) & SCI_TDRE); } static int sci_txroom(struct uart_port *port) @@ -513,13 +510,13 @@ static int sci_rxfill(struct uart_port *port) reg = sci_getreg(port, SCRFDR); if (reg->size) - return sci_in(port, SCRFDR) & 0xff; + return serial_port_in(port, SCRFDR) & 0xff; reg = sci_getreg(port, SCFDR); if (reg->size) - return sci_in(port, SCFDR) & ((port->fifosize << 1) - 1); + return serial_port_in(port, SCFDR) & ((port->fifosize << 1) - 1); - return (sci_in(port, SCxSR) & SCxSR_RDxF(port)) != 0; + return (serial_port_in(port, SCxSR) & SCxSR_RDxF(port)) != 0; } /* @@ -547,14 +544,14 @@ static void sci_transmit_chars(struct uart_port *port) unsigned short ctrl; int count; - status = sci_in(port, SCxSR); + status = serial_port_in(port, SCxSR); if (!(status & SCxSR_TDxE(port))) { - ctrl = sci_in(port, SCSCR); + ctrl = serial_port_in(port, SCSCR); if (uart_circ_empty(xmit)) ctrl &= ~SCSCR_TIE; else ctrl |= SCSCR_TIE; - sci_out(port, SCSCR, ctrl); + serial_port_out(port, SCSCR, ctrl); return; } @@ -573,27 +570,27 @@ static void sci_transmit_chars(struct uart_port *port) break; } - sci_out(port, SCxTDR, c); + serial_port_out(port, SCxTDR, c); port->icount.tx++; } while (--count > 0); - sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port)); + serial_port_out(port, SCxSR, SCxSR_TDxE_CLEAR(port)); if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(port); if (uart_circ_empty(xmit)) { sci_stop_tx(port); } else { - ctrl = sci_in(port, SCSCR); + ctrl = serial_port_in(port, SCSCR); if (port->type != PORT_SCI) { - sci_in(port, SCxSR); /* Dummy read */ - sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port)); + serial_port_in(port, SCxSR); /* Dummy read */ + serial_port_out(port, SCxSR, SCxSR_TDxE_CLEAR(port)); } ctrl |= SCSCR_TIE; - sci_out(port, SCSCR, ctrl); + serial_port_out(port, SCSCR, ctrl); } } @@ -608,7 +605,7 @@ static void sci_receive_chars(struct uart_port *port) unsigned short status; unsigned char flag; - status = sci_in(port, SCxSR); + status = serial_port_in(port, SCxSR); if (!(status & SCxSR_RDxF(port))) return; @@ -621,7 +618,7 @@ static void sci_receive_chars(struct uart_port *port) break; if (port->type == PORT_SCI) { - char c = sci_in(port, SCxRDR); + char c = serial_port_in(port, SCxRDR); if (uart_handle_sysrq_char(port, c) || sci_port->break_flag) count = 0; @@ -629,9 +626,9 @@ static void sci_receive_chars(struct uart_port *port) tty_insert_flip_char(tty, c, TTY_NORMAL); } else { for (i = 0; i < count; i++) { - char c = sci_in(port, SCxRDR); + char c = serial_port_in(port, SCxRDR); - status = sci_in(port, SCxSR); + status = serial_port_in(port, SCxSR); #if defined(CONFIG_CPU_SH3) /* Skip "chars" during break */ if (sci_port->break_flag) { @@ -672,8 +669,8 @@ static void sci_receive_chars(struct uart_port *port) } } - sci_in(port, SCxSR); /* dummy read */ - sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); + serial_port_in(port, SCxSR); /* dummy read */ + serial_port_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); copied += count; port->icount.rx += count; @@ -683,8 +680,8 @@ static void sci_receive_chars(struct uart_port *port) /* Tell the rest of the system the news. New characters! */ tty_flip_buffer_push(tty); } else { - sci_in(port, SCxSR); /* dummy read */ - sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); + serial_port_in(port, SCxSR); /* dummy read */ + serial_port_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); } } @@ -726,7 +723,7 @@ static void sci_break_timer(unsigned long data) static int sci_handle_errors(struct uart_port *port) { int copied = 0; - unsigned short status = sci_in(port, SCxSR); + unsigned short status = serial_port_in(port, SCxSR); struct tty_struct *tty = port->state->port.tty; struct sci_port *s = to_sci_port(port); @@ -804,8 +801,8 @@ static int sci_handle_fifo_overrun(struct uart_port *port) if (!reg->size) return 0; - if ((sci_in(port, SCLSR) & (1 << s->cfg->overrun_bit))) { - sci_out(port, SCLSR, 0); + if ((serial_port_in(port, SCLSR) & (1 << s->cfg->overrun_bit))) { + serial_port_out(port, SCLSR, 0); port->icount.overrun++; @@ -822,7 +819,7 @@ static int sci_handle_fifo_overrun(struct uart_port *port) static int sci_handle_breaks(struct uart_port *port) { int copied = 0; - unsigned short status = sci_in(port, SCxSR); + unsigned short status = serial_port_in(port, SCxSR); struct tty_struct *tty = port->state->port.tty; struct sci_port *s = to_sci_port(port); @@ -859,8 +856,8 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr) struct sci_port *s = to_sci_port(port); if (s->chan_rx) { - u16 scr = sci_in(port, SCSCR); - u16 ssr = sci_in(port, SCxSR); + u16 scr = serial_port_in(port, SCSCR); + u16 ssr = serial_port_in(port, SCxSR); /* Disable future Rx interrupts */ if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { @@ -869,9 +866,9 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr) } else { scr &= ~SCSCR_RIE; } - sci_out(port, SCSCR, scr); + serial_port_out(port, SCSCR, scr); /* Clear current interrupt */ - sci_out(port, SCxSR, ssr & ~(1 | SCxSR_RDxF(port))); + serial_port_out(port, SCxSR, ssr & ~(1 | SCxSR_RDxF(port))); dev_dbg(port->dev, "Rx IRQ %lu: setup t-out in %u jiffies\n", jiffies, s->rx_timeout); mod_timer(&s->rx_timer, jiffies + s->rx_timeout); @@ -909,15 +906,15 @@ static irqreturn_t sci_er_interrupt(int irq, void *ptr) if (port->type == PORT_SCI) { if (sci_handle_errors(port)) { /* discard character in rx buffer */ - sci_in(port, SCxSR); - sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); + serial_port_in(port, SCxSR); + serial_port_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); } } else { sci_handle_fifo_overrun(port); sci_rx_interrupt(irq, ptr); } - sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); + serial_port_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); /* Kick the transmission */ sci_tx_interrupt(irq, ptr); @@ -931,7 +928,7 @@ static irqreturn_t sci_br_interrupt(int irq, void *ptr) /* Handle BREAKs */ sci_handle_breaks(port); - sci_out(port, SCxSR, SCxSR_BREAK_CLEAR(port)); + serial_port_out(port, SCxSR, SCxSR_BREAK_CLEAR(port)); return IRQ_HANDLED; } @@ -955,8 +952,8 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) struct sci_port *s = to_sci_port(port); irqreturn_t ret = IRQ_NONE; - ssr_status = sci_in(port, SCxSR); - scr_status = sci_in(port, SCSCR); + ssr_status = serial_port_in(port, SCxSR); + scr_status = serial_port_in(port, SCSCR); err_enabled = scr_status & port_rx_irq_mask(port); /* Tx Interrupt */ @@ -1170,7 +1167,7 @@ static void sci_free_gpios(struct sci_port *port) static unsigned int sci_tx_empty(struct uart_port *port) { - unsigned short status = sci_in(port, SCxSR); + unsigned short status = serial_port_in(port, SCxSR); unsigned short in_tx_fifo = sci_txfill(port); return (status & SCxSR_TEND(port)) && !in_tx_fifo ? TIOCSER_TEMT : 0; @@ -1198,7 +1195,7 @@ static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl) */ reg = sci_getreg(port, SCFCR); if (reg->size) - sci_out(port, SCFCR, sci_in(port, SCFCR) | 1); + serial_port_out(port, SCFCR, serial_port_in(port, SCFCR) | 1); } } @@ -1240,8 +1237,8 @@ static void sci_dma_tx_complete(void *arg) } else { s->cookie_tx = -EINVAL; if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { - u16 ctrl = sci_in(port, SCSCR); - sci_out(port, SCSCR, ctrl & ~SCSCR_TIE); + u16 ctrl = serial_port_in(port, SCSCR); + serial_port_out(port, SCSCR, ctrl & ~SCSCR_TIE); } } @@ -1494,13 +1491,13 @@ static void sci_start_tx(struct uart_port *port) #ifdef CONFIG_SERIAL_SH_SCI_DMA if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { - u16 new, scr = sci_in(port, SCSCR); + u16 new, scr = serial_port_in(port, SCSCR); if (s->chan_tx) new = scr | 0x8000; else new = scr & ~0x8000; if (new != scr) - sci_out(port, SCSCR, new); + serial_port_out(port, SCSCR, new); } if (s->chan_tx && !uart_circ_empty(&s->port.state->xmit) && @@ -1512,8 +1509,8 @@ static void sci_start_tx(struct uart_port *port) if (!s->chan_tx || port->type == PORT_SCIFA || port->type == PORT_SCIFB) { /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */ - ctrl = sci_in(port, SCSCR); - sci_out(port, SCSCR, ctrl | SCSCR_TIE); + ctrl = serial_port_in(port, SCSCR); + serial_port_out(port, SCSCR, ctrl | SCSCR_TIE); } } @@ -1522,40 +1519,40 @@ static void sci_stop_tx(struct uart_port *port) unsigned short ctrl; /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */ - ctrl = sci_in(port, SCSCR); + ctrl = serial_port_in(port, SCSCR); if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) ctrl &= ~0x8000; ctrl &= ~SCSCR_TIE; - sci_out(port, SCSCR, ctrl); + serial_port_out(port, SCSCR, ctrl); } static void sci_start_rx(struct uart_port *port) { unsigned short ctrl; - ctrl = sci_in(port, SCSCR) | port_rx_irq_mask(port); + ctrl = serial_port_in(port, SCSCR) | port_rx_irq_mask(port); if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) ctrl &= ~0x4000; - sci_out(port, SCSCR, ctrl); + serial_port_out(port, SCSCR, ctrl); } static void sci_stop_rx(struct uart_port *port) { unsigned short ctrl; - ctrl = sci_in(port, SCSCR); + ctrl = serial_port_in(port, SCSCR); if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) ctrl &= ~0x4000; ctrl &= ~port_rx_irq_mask(port); - sci_out(port, SCSCR, ctrl); + serial_port_out(port, SCSCR, ctrl); } static void sci_enable_ms(struct uart_port *port) @@ -1589,13 +1586,13 @@ static void rx_timer_fn(unsigned long arg) { struct sci_port *s = (struct sci_port *)arg; struct uart_port *port = &s->port; - u16 scr = sci_in(port, SCSCR); + u16 scr = serial_port_in(port, SCSCR); if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { scr &= ~0x4000; enable_irq(s->cfg->irqs[1]); } - sci_out(port, SCSCR, scr | SCSCR_RIE); + serial_port_out(port, SCSCR, scr | SCSCR_RIE); dev_dbg(port->dev, "DMA Rx timed out\n"); schedule_work(&s->work_rx); } @@ -1776,14 +1773,14 @@ static void sci_reset(struct uart_port *port) unsigned int status; do { - status = sci_in(port, SCxSR); + status = serial_port_in(port, SCxSR); } while (!(status & SCxSR_TEND(port))); - sci_out(port, SCSCR, 0x00); /* TE=0, RE=0, CKE1=0 */ + serial_port_out(port, SCSCR, 0x00); /* TE=0, RE=0, CKE1=0 */ reg = sci_getreg(port, SCFCR); if (reg->size) - sci_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST); + serial_port_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST); } static void sci_set_termios(struct uart_port *port, struct ktermios *termios, @@ -1812,7 +1809,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, sci_reset(port); - smr_val = sci_in(port, SCSMR) & 3; + smr_val = serial_port_in(port, SCSMR) & 3; if ((termios->c_cflag & CSIZE) == CS7) smr_val |= 0x40; @@ -1825,19 +1822,19 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, uart_update_timeout(port, termios->c_cflag, baud); - sci_out(port, SCSMR, smr_val); + serial_port_out(port, SCSMR, smr_val); dev_dbg(port->dev, "%s: SMR %x, t %x, SCSCR %x\n", __func__, smr_val, t, s->cfg->scscr); if (t > 0) { if (t >= 256) { - sci_out(port, SCSMR, (sci_in(port, SCSMR) & ~3) | 1); + serial_port_out(port, SCSMR, (serial_port_in(port, SCSMR) & ~3) | 1); t >>= 2; } else - sci_out(port, SCSMR, sci_in(port, SCSMR) & ~3); + serial_port_out(port, SCSMR, serial_port_in(port, SCSMR) & ~3); - sci_out(port, SCBRR, t); + serial_port_out(port, SCBRR, t); udelay((1000000+(baud-1)) / baud); /* Wait one bit interval */ } @@ -1845,7 +1842,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, reg = sci_getreg(port, SCFCR); if (reg->size) { - unsigned short ctrl = sci_in(port, SCFCR); + unsigned short ctrl = serial_port_in(port, SCFCR); if (s->cfg->capabilities & SCIx_HAVE_RTSCTS) { if (termios->c_cflag & CRTSCTS) @@ -1861,10 +1858,10 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, */ ctrl &= ~(SCFCR_RFRST | SCFCR_TFRST); - sci_out(port, SCFCR, ctrl); + serial_port_out(port, SCFCR, ctrl); } - sci_out(port, SCSCR, s->cfg->scscr); + serial_port_out(port, SCSCR, s->cfg->scscr); #ifdef CONFIG_SERIAL_SH_SCI_DMA /* @@ -2166,7 +2163,7 @@ static void serial_console_write(struct console *co, const char *s, /* wait until fifo is empty and last bit has been transmitted */ bits = SCxSR_TDxE(port) | SCxSR_TEND(port); - while ((sci_in(port, SCxSR) & bits) != bits) + while ((serial_port_in(port, SCxSR) & bits) != bits) cpu_relax(); sci_port_disable(sci_port); @@ -2260,12 +2257,12 @@ static int sci_runtime_suspend(struct device *dev) if (uart_console(port)) { struct plat_sci_reg *reg; - sci_port->saved_smr = sci_in(port, SCSMR); - sci_port->saved_brr = sci_in(port, SCBRR); + sci_port->saved_smr = serial_port_in(port, SCSMR); + sci_port->saved_brr = serial_port_in(port, SCBRR); reg = sci_getreg(port, SCFCR); if (reg->size) - sci_port->saved_fcr = sci_in(port, SCFCR); + sci_port->saved_fcr = serial_port_in(port, SCFCR); else sci_port->saved_fcr = 0; } @@ -2279,13 +2276,13 @@ static int sci_runtime_resume(struct device *dev) if (uart_console(port)) { sci_reset(port); - sci_out(port, SCSMR, sci_port->saved_smr); - sci_out(port, SCBRR, sci_port->saved_brr); + serial_port_out(port, SCSMR, sci_port->saved_smr); + serial_port_out(port, SCBRR, sci_port->saved_brr); if (sci_port->saved_fcr) - sci_out(port, SCFCR, sci_port->saved_fcr); + serial_port_out(port, SCFCR, sci_port->saved_fcr); - sci_out(port, SCSCR, sci_port->cfg->scscr); + serial_port_out(port, SCSCR, sci_port->cfg->scscr); } return 0; } diff --git a/drivers/tty/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h index a1a2d364f92b..4c22a1529aac 100644 --- a/drivers/tty/serial/sh-sci.h +++ b/drivers/tty/serial/sh-sci.h @@ -20,10 +20,10 @@ defined(CONFIG_ARCH_SH7372) || \ defined(CONFIG_ARCH_R8A7740) -# define SCxSR_RDxF_CLEAR(port) (sci_in(port, SCxSR) & 0xfffc) -# define SCxSR_ERROR_CLEAR(port) (sci_in(port, SCxSR) & 0xfd73) -# define SCxSR_TDxE_CLEAR(port) (sci_in(port, SCxSR) & 0xffdf) -# define SCxSR_BREAK_CLEAR(port) (sci_in(port, SCxSR) & 0xffe3) +# define SCxSR_RDxF_CLEAR(port) (serial_port_in(port, SCxSR) & 0xfffc) +# define SCxSR_ERROR_CLEAR(port) (serial_port_in(port, SCxSR) & 0xfd73) +# define SCxSR_TDxE_CLEAR(port) (serial_port_in(port, SCxSR) & 0xffdf) +# define SCxSR_BREAK_CLEAR(port) (serial_port_in(port, SCxSR) & 0xffe3) #else # define SCxSR_RDxF_CLEAR(port) (((port)->type == PORT_SCI) ? 0xbc : 0x00fc) # define SCxSR_ERROR_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x0073) -- cgit v1.2.3 From 3248877ea1796915419fba7c89315fdbf00cb56a Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 25 Nov 2011 15:21:02 +0000 Subject: drm: base prime/dma-buf support (v5) This adds the basic drm dma-buf interface layer, called PRIME. This commit doesn't add any driver support, it is simply and agreed upon starting point so we can work towards merging driver support for the next merge window. Current drivers with work done are nouveau, i915, udl, exynos and omap. The main APIs exposed to userspace allow translating a 32-bit object handle to a file descriptor, and a file descriptor to a 32-bit object handle. The flags value is currently limited to O_CLOEXEC. Acknowledgements: Daniel Vetter: lots of review Rob Clark: cleaned up lots of the internals and did lifetime review. v2: rename some functions after Chris preferred a green shed fix IS_ERR_OR_NULL -> IS_ERR v3: Fix Ville pointed out using buffer + kmalloc v4: add locking as per ickle review v5: allow re-exporting the original dma-buf (Daniel) Reviewed-by: Daniel Vetter Reviewed-by: Rob Clark Reviewed-by: Sumit Semwal Reviewed-by: Inki Dae Acked-by: Ben Widawsky Signed-off-by: Dave Airlie --- drivers/gpu/drm/Kconfig | 1 + drivers/gpu/drm/Makefile | 2 +- drivers/gpu/drm/drm_drv.c | 4 + drivers/gpu/drm/drm_fops.c | 7 + drivers/gpu/drm/drm_gem.c | 9 ++ drivers/gpu/drm/drm_prime.c | 304 ++++++++++++++++++++++++++++++++++++++++++++ include/drm/drm.h | 14 +- include/drm/drmP.h | 62 +++++++++ 8 files changed, 401 insertions(+), 2 deletions(-) create mode 100644 drivers/gpu/drm/drm_prime.c (limited to 'drivers') diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index cc1148837e24..e354bc0b052a 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -9,6 +9,7 @@ menuconfig DRM depends on (AGP || AGP=n) && !EMULATED_CMPXCHG && MMU select I2C select I2C_ALGOBIT + select DMA_SHARED_BUFFER help Kernel-level support for the Direct Rendering Infrastructure (DRI) introduced in XFree86 4.0. If you say Y here, you need to select diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index a858532806ae..c20da5bda355 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -12,7 +12,7 @@ drm-y := drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \ drm_platform.o drm_sysfs.o drm_hashtab.o drm_mm.o \ drm_crtc.o drm_modes.o drm_edid.o \ drm_info.o drm_debugfs.o drm_encoder_slave.o \ - drm_trace_points.o drm_global.o + drm_trace_points.o drm_global.o drm_prime.o drm-$(CONFIG_COMPAT) += drm_ioc32.o diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 0b65fbc8a630..6116e3b75393 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -136,6 +136,10 @@ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, DRM_CONTROL_ALLOW|DRM_UNLOCKED), + + DRM_IOCTL_DEF(DRM_IOCTL_PRIME_HANDLE_TO_FD, drm_prime_handle_to_fd_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_PRIME_FD_TO_HANDLE, drm_prime_fd_to_handle_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANERESOURCES, drm_mode_getplane_res, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index 7348a3dab250..cdfbf27b2b3c 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c @@ -271,6 +271,9 @@ static int drm_open_helper(struct inode *inode, struct file *filp, if (dev->driver->driver_features & DRIVER_GEM) drm_gem_open(dev, priv); + if (drm_core_check_feature(dev, DRIVER_PRIME)) + drm_prime_init_file_private(&priv->prime); + if (dev->driver->open) { ret = dev->driver->open(dev, priv); if (ret < 0) @@ -571,6 +574,10 @@ int drm_release(struct inode *inode, struct file *filp) if (dev->driver->postclose) dev->driver->postclose(dev, file_priv); + + if (drm_core_check_feature(dev, DRIVER_PRIME)) + drm_prime_destroy_file_private(&file_priv->prime); + kfree(file_priv); /* ======================================================== diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 0ef358e53245..83114b5e3cee 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "drmP.h" /** @file drm_gem.c @@ -232,6 +233,10 @@ drm_gem_handle_delete(struct drm_file *filp, u32 handle) idr_remove(&filp->object_idr, handle); spin_unlock(&filp->table_lock); + if (obj->import_attach) + drm_prime_remove_imported_buf_handle(&filp->prime, + obj->import_attach->dmabuf); + if (dev->driver->gem_close_object) dev->driver->gem_close_object(obj, filp); drm_gem_object_handle_unreference_unlocked(obj); @@ -527,6 +532,10 @@ drm_gem_object_release_handle(int id, void *ptr, void *data) struct drm_gem_object *obj = ptr; struct drm_device *dev = obj->dev; + if (obj->import_attach) + drm_prime_remove_imported_buf_handle(&file_priv->prime, + obj->import_attach->dmabuf); + if (dev->driver->gem_close_object) dev->driver->gem_close_object(obj, file_priv); diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c new file mode 100644 index 000000000000..1bdf2b54eaf6 --- /dev/null +++ b/drivers/gpu/drm/drm_prime.c @@ -0,0 +1,304 @@ +/* + * Copyright © 2012 Red Hat + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Dave Airlie + * Rob Clark + * + */ + +#include +#include +#include "drmP.h" + +/* + * DMA-BUF/GEM Object references and lifetime overview: + * + * On the export the dma_buf holds a reference to the exporting GEM + * object. It takes this reference in handle_to_fd_ioctl, when it + * first calls .prime_export and stores the exporting GEM object in + * the dma_buf priv. This reference is released when the dma_buf + * object goes away in the driver .release function. + * + * On the import the importing GEM object holds a reference to the + * dma_buf (which in turn holds a ref to the exporting GEM object). + * It takes that reference in the fd_to_handle ioctl. + * It calls dma_buf_get, creates an attachment to it and stores the + * attachment in the GEM object. When this attachment is destroyed + * when the imported object is destroyed, we remove the attachment + * and drop the reference to the dma_buf. + * + * Thus the chain of references always flows in one direction + * (avoiding loops): importing_gem -> dmabuf -> exporting_gem + * + * Self-importing: if userspace is using PRIME as a replacement for flink + * then it will get a fd->handle request for a GEM object that it created. + * Drivers should detect this situation and return back the gem object + * from the dma-buf private. + */ + +struct drm_prime_member { + struct list_head entry; + struct dma_buf *dma_buf; + uint32_t handle; +}; + +int drm_gem_prime_handle_to_fd(struct drm_device *dev, + struct drm_file *file_priv, uint32_t handle, uint32_t flags, + int *prime_fd) +{ + struct drm_gem_object *obj; + void *buf; + + obj = drm_gem_object_lookup(dev, file_priv, handle); + if (!obj) + return -ENOENT; + + mutex_lock(&file_priv->prime.lock); + /* re-export the original imported object */ + if (obj->import_attach) { + get_dma_buf(obj->import_attach->dmabuf); + *prime_fd = dma_buf_fd(obj->import_attach->dmabuf, flags); + drm_gem_object_unreference_unlocked(obj); + mutex_unlock(&file_priv->prime.lock); + return 0; + } + + if (obj->export_dma_buf) { + get_dma_buf(obj->export_dma_buf); + *prime_fd = dma_buf_fd(obj->export_dma_buf, flags); + drm_gem_object_unreference_unlocked(obj); + } else { + buf = dev->driver->gem_prime_export(dev, obj, flags); + if (IS_ERR(buf)) { + /* normally the created dma-buf takes ownership of the ref, + * but if that fails then drop the ref + */ + drm_gem_object_unreference_unlocked(obj); + mutex_unlock(&file_priv->prime.lock); + return PTR_ERR(buf); + } + obj->export_dma_buf = buf; + *prime_fd = dma_buf_fd(buf, flags); + } + mutex_unlock(&file_priv->prime.lock); + return 0; +} +EXPORT_SYMBOL(drm_gem_prime_handle_to_fd); + +int drm_gem_prime_fd_to_handle(struct drm_device *dev, + struct drm_file *file_priv, int prime_fd, uint32_t *handle) +{ + struct dma_buf *dma_buf; + struct drm_gem_object *obj; + int ret; + + dma_buf = dma_buf_get(prime_fd); + if (IS_ERR(dma_buf)) + return PTR_ERR(dma_buf); + + mutex_lock(&file_priv->prime.lock); + + ret = drm_prime_lookup_imported_buf_handle(&file_priv->prime, + dma_buf, handle); + if (!ret) { + ret = 0; + goto out_put; + } + + /* never seen this one, need to import */ + obj = dev->driver->gem_prime_import(dev, dma_buf); + if (IS_ERR(obj)) { + ret = PTR_ERR(obj); + goto out_put; + } + + ret = drm_gem_handle_create(file_priv, obj, handle); + drm_gem_object_unreference_unlocked(obj); + if (ret) + goto out_put; + + ret = drm_prime_add_imported_buf_handle(&file_priv->prime, + dma_buf, *handle); + if (ret) + goto fail; + + mutex_unlock(&file_priv->prime.lock); + return 0; + +fail: + /* hmm, if driver attached, we are relying on the free-object path + * to detach.. which seems ok.. + */ + drm_gem_object_handle_unreference_unlocked(obj); +out_put: + dma_buf_put(dma_buf); + mutex_unlock(&file_priv->prime.lock); + return ret; +} +EXPORT_SYMBOL(drm_gem_prime_fd_to_handle); + +int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_prime_handle *args = data; + uint32_t flags; + + if (!drm_core_check_feature(dev, DRIVER_PRIME)) + return -EINVAL; + + if (!dev->driver->prime_handle_to_fd) + return -ENOSYS; + + /* check flags are valid */ + if (args->flags & ~DRM_CLOEXEC) + return -EINVAL; + + /* we only want to pass DRM_CLOEXEC which is == O_CLOEXEC */ + flags = args->flags & DRM_CLOEXEC; + + return dev->driver->prime_handle_to_fd(dev, file_priv, + args->handle, flags, &args->fd); +} + +int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_prime_handle *args = data; + + if (!drm_core_check_feature(dev, DRIVER_PRIME)) + return -EINVAL; + + if (!dev->driver->prime_fd_to_handle) + return -ENOSYS; + + return dev->driver->prime_fd_to_handle(dev, file_priv, + args->fd, &args->handle); +} + +/* + * drm_prime_pages_to_sg + * + * this helper creates an sg table object from a set of pages + * the driver is responsible for mapping the pages into the + * importers address space + */ +struct sg_table *drm_prime_pages_to_sg(struct page **pages, int nr_pages) +{ + struct sg_table *sg = NULL; + struct scatterlist *iter; + int i; + int ret; + + sg = kmalloc(sizeof(struct sg_table), GFP_KERNEL); + if (!sg) + goto out; + + ret = sg_alloc_table(sg, nr_pages, GFP_KERNEL); + if (ret) + goto out; + + for_each_sg(sg->sgl, iter, nr_pages, i) + sg_set_page(iter, pages[i], PAGE_SIZE, 0); + + return sg; +out: + kfree(sg); + return NULL; +} +EXPORT_SYMBOL(drm_prime_pages_to_sg); + +/* helper function to cleanup a GEM/prime object */ +void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *sg) +{ + struct dma_buf_attachment *attach; + struct dma_buf *dma_buf; + attach = obj->import_attach; + if (sg) + dma_buf_unmap_attachment(attach, sg, DMA_BIDIRECTIONAL); + dma_buf = attach->dmabuf; + dma_buf_detach(attach->dmabuf, attach); + /* remove the reference */ + dma_buf_put(dma_buf); +} +EXPORT_SYMBOL(drm_prime_gem_destroy); + +void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv) +{ + INIT_LIST_HEAD(&prime_fpriv->head); + mutex_init(&prime_fpriv->lock); +} +EXPORT_SYMBOL(drm_prime_init_file_private); + +void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv) +{ + struct drm_prime_member *member, *safe; + list_for_each_entry_safe(member, safe, &prime_fpriv->head, entry) { + list_del(&member->entry); + kfree(member); + } +} +EXPORT_SYMBOL(drm_prime_destroy_file_private); + +int drm_prime_add_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle) +{ + struct drm_prime_member *member; + + member = kmalloc(sizeof(*member), GFP_KERNEL); + if (!member) + return -ENOMEM; + + member->dma_buf = dma_buf; + member->handle = handle; + list_add(&member->entry, &prime_fpriv->head); + return 0; +} +EXPORT_SYMBOL(drm_prime_add_imported_buf_handle); + +int drm_prime_lookup_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t *handle) +{ + struct drm_prime_member *member; + + list_for_each_entry(member, &prime_fpriv->head, entry) { + if (member->dma_buf == dma_buf) { + *handle = member->handle; + return 0; + } + } + return -ENOENT; +} +EXPORT_SYMBOL(drm_prime_lookup_imported_buf_handle); + +void drm_prime_remove_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf) +{ + struct drm_prime_member *member, *safe; + + mutex_lock(&prime_fpriv->lock); + list_for_each_entry_safe(member, safe, &prime_fpriv->head, entry) { + if (member->dma_buf == dma_buf) { + list_del(&member->entry); + kfree(member); + } + } + mutex_unlock(&prime_fpriv->lock); +} +EXPORT_SYMBOL(drm_prime_remove_imported_buf_handle); diff --git a/include/drm/drm.h b/include/drm/drm.h index 34a7b89fd006..64ff02d5b730 100644 --- a/include/drm/drm.h +++ b/include/drm/drm.h @@ -617,6 +617,17 @@ struct drm_get_cap { __u64 value; }; +#define DRM_CLOEXEC O_CLOEXEC +struct drm_prime_handle { + __u32 handle; + + /** Flags.. only applicable for handle->fd */ + __u32 flags; + + /** Returned dmabuf file descriptor */ + __s32 fd; +}; + #include "drm_mode.h" #define DRM_IOCTL_BASE 'd' @@ -673,7 +684,8 @@ struct drm_get_cap { #define DRM_IOCTL_UNLOCK DRM_IOW( 0x2b, struct drm_lock) #define DRM_IOCTL_FINISH DRM_IOW( 0x2c, struct drm_lock) -#define DRM_IOCTL_GEM_PRIME_OPEN DRM_IOWR(0x2e, struct drm_gem_open) +#define DRM_IOCTL_PRIME_HANDLE_TO_FD DRM_IOWR(0x2d, struct drm_prime_handle) +#define DRM_IOCTL_PRIME_FD_TO_HANDLE DRM_IOWR(0x2e, struct drm_prime_handle) #define DRM_IOCTL_AGP_ACQUIRE DRM_IO( 0x30) #define DRM_IOCTL_AGP_RELEASE DRM_IO( 0x31) diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 574bd1c81ebd..dd731043fecd 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -91,6 +91,7 @@ struct drm_device; #define DRM_UT_CORE 0x01 #define DRM_UT_DRIVER 0x02 #define DRM_UT_KMS 0x04 +#define DRM_UT_PRIME 0x08 /* * Three debug levels are defined. * drm_core, drm_driver, drm_kms @@ -150,6 +151,7 @@ int drm_err(const char *func, const char *format, ...); #define DRIVER_IRQ_VBL2 0x800 #define DRIVER_GEM 0x1000 #define DRIVER_MODESET 0x2000 +#define DRIVER_PRIME 0x4000 #define DRIVER_BUS_PCI 0x1 #define DRIVER_BUS_PLATFORM 0x2 @@ -215,6 +217,11 @@ int drm_err(const char *func, const char *format, ...); drm_ut_debug_printk(DRM_UT_KMS, DRM_NAME, \ __func__, fmt, ##args); \ } while (0) +#define DRM_DEBUG_PRIME(fmt, args...) \ + do { \ + drm_ut_debug_printk(DRM_UT_PRIME, DRM_NAME, \ + __func__, fmt, ##args); \ + } while (0) #define DRM_LOG(fmt, args...) \ do { \ drm_ut_debug_printk(DRM_UT_CORE, NULL, \ @@ -238,6 +245,7 @@ int drm_err(const char *func, const char *format, ...); #else #define DRM_DEBUG_DRIVER(fmt, args...) do { } while (0) #define DRM_DEBUG_KMS(fmt, args...) do { } while (0) +#define DRM_DEBUG_PRIME(fmt, args...) do { } while (0) #define DRM_DEBUG(fmt, arg...) do { } while (0) #define DRM_LOG(fmt, arg...) do { } while (0) #define DRM_LOG_KMS(fmt, args...) do { } while (0) @@ -410,6 +418,12 @@ struct drm_pending_event { void (*destroy)(struct drm_pending_event *event); }; +/* initial implementaton using a linked list - todo hashtab */ +struct drm_prime_file_private { + struct list_head head; + struct mutex lock; +}; + /** File private data */ struct drm_file { int authenticated; @@ -437,6 +451,8 @@ struct drm_file { wait_queue_head_t event_wait; struct list_head event_list; int event_space; + + struct drm_prime_file_private prime; }; /** Wait queue */ @@ -652,6 +668,12 @@ struct drm_gem_object { uint32_t pending_write_domain; void *driver_private; + + /* dma buf exported from this GEM object */ + struct dma_buf *export_dma_buf; + + /* dma buf attachment backing this object */ + struct dma_buf_attachment *import_attach; }; #include "drm_crtc.h" @@ -890,6 +912,20 @@ struct drm_driver { int (*gem_open_object) (struct drm_gem_object *, struct drm_file *); void (*gem_close_object) (struct drm_gem_object *, struct drm_file *); + /* prime: */ + /* export handle -> fd (see drm_gem_prime_handle_to_fd() helper) */ + int (*prime_handle_to_fd)(struct drm_device *dev, struct drm_file *file_priv, + uint32_t handle, uint32_t flags, int *prime_fd); + /* import fd -> handle (see drm_gem_prime_fd_to_handle() helper) */ + int (*prime_fd_to_handle)(struct drm_device *dev, struct drm_file *file_priv, + int prime_fd, uint32_t *handle); + /* export GEM -> dmabuf */ + struct dma_buf * (*gem_prime_export)(struct drm_device *dev, + struct drm_gem_object *obj, int flags); + /* import dmabuf -> GEM */ + struct drm_gem_object * (*gem_prime_import)(struct drm_device *dev, + struct dma_buf *dma_buf); + /* vga arb irq handler */ void (*vgaarb_irq)(struct drm_device *dev, bool state); @@ -1509,6 +1545,32 @@ extern int drm_vblank_info(struct seq_file *m, void *data); extern int drm_clients_info(struct seq_file *m, void* data); extern int drm_gem_name_info(struct seq_file *m, void *data); + +extern int drm_gem_prime_handle_to_fd(struct drm_device *dev, + struct drm_file *file_priv, uint32_t handle, uint32_t flags, + int *prime_fd); +extern int drm_gem_prime_fd_to_handle(struct drm_device *dev, + struct drm_file *file_priv, int prime_fd, uint32_t *handle); + +extern int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); + +extern struct sg_table *drm_prime_pages_to_sg(struct page **pages, int nr_pages); +extern void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *sg); + + +void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv); +void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv); +int drm_prime_add_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle); +int drm_prime_lookup_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t *handle); +void drm_prime_remove_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf); + +int drm_prime_add_dma_buf(struct drm_device *dev, struct drm_gem_object *obj); +int drm_prime_lookup_obj(struct drm_device *dev, struct dma_buf *buf, + struct drm_gem_object **obj); + #if DRM_DEBUG_CODE extern int drm_vma_info(struct seq_file *m, void *data); #endif -- cgit v1.2.3 From 5f12760d289fd2da685cb54eebb08c107b146872 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sat, 31 Mar 2012 16:33:31 +0800 Subject: regulator: fix sysfs name collision between dummy and fixed dummy regulator When regulator_register_fixed() is being used to register fixed dummy regulator, the following line will be seen in the boot log. And the sysfs entry for fixed dummy regulator is not shown. dummy: Failed to create debugfs directory The patch renames the fixed dummy supply to "fixed-dummy" to avoid the name collision with dummy regulator. Signed-off-by: Shawn Guo Signed-off-by: Mark Brown --- drivers/regulator/fixed-helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/fixed-helper.c b/drivers/regulator/fixed-helper.c index 30d0a15b8949..efb52dcefd35 100644 --- a/drivers/regulator/fixed-helper.c +++ b/drivers/regulator/fixed-helper.c @@ -32,7 +32,7 @@ struct platform_device *regulator_register_fixed(int id, if (!data) return NULL; - data->cfg.supply_name = "dummy"; + data->cfg.supply_name = "fixed-dummy"; data->cfg.microvolts = 0; data->cfg.gpio = -EINVAL; data->cfg.enabled_at_boot = 1; -- cgit v1.2.3 From 546e78452a3f81eb45ae5c671c71db05389d42c8 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 19 Mar 2012 12:22:10 +0800 Subject: regulator: Fix setting new voltage in s5m8767_set_voltage Current code does not really update the register with new value, fix it. I rename the variable i to sel for better readability. Signed-off-by: Axel Lin Acked-by: Sangbeom Kim Signed-off-by: Mark Brown --- drivers/regulator/s5m8767.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c index 58447db15de1..4ca2db059004 100644 --- a/drivers/regulator/s5m8767.c +++ b/drivers/regulator/s5m8767.c @@ -311,8 +311,7 @@ static int s5m8767_set_voltage(struct regulator_dev *rdev, struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); const struct s5m_voltage_desc *desc; int reg_id = rdev_get_id(rdev); - int reg, mask, ret; - int i; + int sel, reg, mask, ret; u8 val; switch (reg_id) { @@ -333,19 +332,20 @@ static int s5m8767_set_voltage(struct regulator_dev *rdev, desc = reg_voltage_map[reg_id]; - i = s5m8767_convert_voltage_to_sel(desc, min_uV, max_uV); - if (i < 0) - return i; + sel = s5m8767_convert_voltage_to_sel(desc, min_uV, max_uV); + if (sel < 0) + return sel; ret = s5m8767_get_voltage_register(rdev, ®); if (ret) return ret; s5m_reg_read(s5m8767->iodev, reg, &val); - val = val & mask; + val &= ~mask; + val |= sel; ret = s5m_reg_write(s5m8767->iodev, reg, val); - *selector = i; + *selector = sel; return ret; } -- cgit v1.2.3 From d49fe3c4cd22965de7422dd81d46110fc3d4deef Mon Sep 17 00:00:00 2001 From: Russ Dill Date: Wed, 21 Mar 2012 22:19:45 -0700 Subject: regulator: Remove non-existent parameter from fixed-helper.c kernel doc Signed-off-by: Russ Dill Signed-off-by: Mark Brown --- drivers/regulator/fixed-helper.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/fixed-helper.c b/drivers/regulator/fixed-helper.c index efb52dcefd35..cacd33c9d042 100644 --- a/drivers/regulator/fixed-helper.c +++ b/drivers/regulator/fixed-helper.c @@ -18,7 +18,6 @@ static void regulator_fixed_release(struct device *dev) /** * regulator_register_fixed - register a no-op fixed regulator - * @name: supply name * @id: platform device id * @supplies: consumers for this regulator * @num_supplies: number of consumers -- cgit v1.2.3 From f47166d2b0001fcb752b40c5a2d4db986dfbea68 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 22 Mar 2012 15:00:50 +0000 Subject: drm/i915: Sanitize BIOS debugging bits from PIPECONF Quoting the BSpec from time immemorial: PIPEACONF, bits 28:27: Frame Start Delay (Debug) Used to delay the frame start signal that is sent to the display planes. Care must be taken to insure that there are enough lines during VBLANK to support this setting. An instance of the BIOS leaving these bits set was found in the wild, where it caused our modesetting to go all squiffy and skewiff. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=47271 Reported-and-tested-by: Eva Wang Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=43012 Reported-and-tested-by: Carl Richell Cc: stable@kernel.org Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_display.c | 6 ++++++ 2 files changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 3886cf051bac..2abf4eb94039 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2385,6 +2385,7 @@ #define PIPECONF_DISABLE 0 #define PIPECONF_DOUBLE_WIDE (1<<30) #define I965_PIPECONF_ACTIVE (1<<30) +#define PIPECONF_FRAME_START_DELAY_MASK (3<<27) #define PIPECONF_SINGLE_WIDE 0 #define PIPECONF_PIPE_UNLOCKED 0 #define PIPECONF_PIPE_LOCKED (1<<25) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d514719f65e2..078477306975 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7580,6 +7580,12 @@ static void intel_sanitize_modesetting(struct drm_device *dev, struct drm_i915_private *dev_priv = dev->dev_private; u32 reg, val; + /* Clear any frame start delays used for debugging left by the BIOS */ + for_each_pipe(pipe) { + reg = PIPECONF(pipe); + I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK); + } + if (HAS_PCH_SPLIT(dev)) return; -- cgit v1.2.3 From 55a254ac63a3ac1867d1501030e7fba69c7d4aeb Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 22 Mar 2012 00:14:43 +0100 Subject: drm/i915: properly restore the ppgtt page directory on resume The ppgtt page directory lives in a snatched part of the gtt pte range. Which naturally gets cleared on hibernate when we pull the power. Suspend to ram (which is what I've tested) works because despite the fact that this is a mmio region, it is actually back by system ram. Fix this by moving the page directory setup code to the ppgtt init code (which gets called on resume). This fixes hibernate on my ivb and snb. Reviewed-by: Ben Widawsky Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 22 +++++++++++++++++++++- drivers/gpu/drm/i915/i915_gem_gtt.c | 9 --------- 2 files changed, 21 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 1f441f5c2405..97e659985223 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3754,12 +3754,32 @@ void i915_gem_init_ppgtt(struct drm_device *dev) drm_i915_private_t *dev_priv = dev->dev_private; uint32_t pd_offset; struct intel_ring_buffer *ring; + struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt; + uint32_t __iomem *pd_addr; + uint32_t pd_entry; int i; if (!dev_priv->mm.aliasing_ppgtt) return; - pd_offset = dev_priv->mm.aliasing_ppgtt->pd_offset; + + pd_addr = dev_priv->mm.gtt->gtt + ppgtt->pd_offset/sizeof(uint32_t); + for (i = 0; i < ppgtt->num_pd_entries; i++) { + dma_addr_t pt_addr; + + if (dev_priv->mm.gtt->needs_dmar) + pt_addr = ppgtt->pt_dma_addr[i]; + else + pt_addr = page_to_phys(ppgtt->pt_pages[i]); + + pd_entry = GEN6_PDE_ADDR_ENCODE(pt_addr); + pd_entry |= GEN6_PDE_VALID; + + writel(pd_entry, pd_addr + i); + } + readl(pd_addr); + + pd_offset = ppgtt->pd_offset; pd_offset /= 64; /* in cachelines, */ pd_offset <<= 16; diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 2eacd78bb93b..a135c61f4119 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -65,9 +65,7 @@ int i915_gem_init_aliasing_ppgtt(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct i915_hw_ppgtt *ppgtt; - uint32_t pd_entry; unsigned first_pd_entry_in_global_pt; - uint32_t __iomem *pd_addr; int i; int ret = -ENOMEM; @@ -100,7 +98,6 @@ int i915_gem_init_aliasing_ppgtt(struct drm_device *dev) goto err_pt_alloc; } - pd_addr = dev_priv->mm.gtt->gtt + first_pd_entry_in_global_pt; for (i = 0; i < ppgtt->num_pd_entries; i++) { dma_addr_t pt_addr; if (dev_priv->mm.gtt->needs_dmar) { @@ -117,13 +114,7 @@ int i915_gem_init_aliasing_ppgtt(struct drm_device *dev) ppgtt->pt_dma_addr[i] = pt_addr; } else pt_addr = page_to_phys(ppgtt->pt_pages[i]); - - pd_entry = GEN6_PDE_ADDR_ENCODE(pt_addr); - pd_entry |= GEN6_PDE_VALID; - - writel(pd_entry, pd_addr + i); } - readl(pd_addr); ppgtt->scratch_page_dma_addr = dev_priv->mm.gtt->scratch_page_dma; -- cgit v1.2.3 From 7dd4906586274f3945f2aeaaa5a33b451c3b4bba Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 21 Mar 2012 10:48:18 +0000 Subject: drm/i915: Mark untiled BLT commands as fenced on gen2/3 The BLT commands on gen2/3 utilize the fence registers and so we cannot modify any fences for the object whilst those commands are in flight. Currently we marked tiled commands as occupying a fence, but forgot to restrict the untiled commands from preventing a fence being assigned before they were completed. One side-effect is that we ten have to double check that a fence was allocated for a fenced buffer during move-to-active. Reported-by: Jiri Slaby Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=43427 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=47990 Reviewed-by: Daniel Vetter Testcase: i-g-t/tests/gem_tiled_after_untiled_blt Tested-by: Daniel Vetter Signed-off-by: Chris Wilson Cc: stable@kernel.org Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 15 +++++++++------ drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 97e659985223..4c65c639f772 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1472,16 +1472,19 @@ i915_gem_object_move_to_active(struct drm_i915_gem_object *obj, list_move_tail(&obj->ring_list, &ring->active_list); obj->last_rendering_seqno = seqno; - if (obj->fenced_gpu_access) { - struct drm_i915_fence_reg *reg; - - BUG_ON(obj->fence_reg == I915_FENCE_REG_NONE); + if (obj->fenced_gpu_access) { obj->last_fenced_seqno = seqno; obj->last_fenced_ring = ring; - reg = &dev_priv->fence_regs[obj->fence_reg]; - list_move_tail(®->lru_list, &dev_priv->mm.fence_list); + /* Bump MRU to take account of the delayed flush */ + if (obj->fence_reg != I915_FENCE_REG_NONE) { + struct drm_i915_fence_reg *reg; + + reg = &dev_priv->fence_regs[obj->fence_reg]; + list_move_tail(®->lru_list, + &dev_priv->mm.fence_list); + } } } diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 81687af00893..f51a696486cb 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -498,8 +498,8 @@ pin_and_fence_object(struct drm_i915_gem_object *obj, if (ret) goto err_unpin; } + obj->pending_fenced_gpu_access = true; } - obj->pending_fenced_gpu_access = need_fence; } entry->offset = obj->gtt_offset; -- cgit v1.2.3 From 83b7f9ac9126f0532ca34c14e4f0582c565c6b0d Mon Sep 17 00:00:00 2001 From: Eugeni Dodonov Date: Fri, 23 Mar 2012 11:57:18 -0300 Subject: drm/i915: allow to select rc6 modes via kernel parameter This allows to select which rc6 modes are to be used via kernel parameter, via a bitmask parameter. E.g.: - to enable rc6, i915_enable_rc6=1 - to enable rc6 and deep rc6, i915_enable_rc6=3 - to enable rc6 and deepest rc6, use i915_enable_rc6=5 - to enable rc6, deep and deepest rc6, use i915_enable_rc6=7 Please keep in mind that the deepest RC6 state really should NOT be used by default, as it could potentially worsen the issues with deep RC6. So do enable it only when you know what you are doing. However, having it around could help solving possible future rc6-related issues and their debugging on user machines. Note that this changes behavior - previously, value of 1 would enable both RC6 and deep RC6. Now it should only enable RC6 and deep/deepest RC6 stages must be enabled manually. v2: address Chris Wilson comments and clean up the code. References: https://bugs.freedesktop.org/show_bug.cgi?id=42579 Reviewed-by: Chris Wilson Reviewed-by: Ben Widawsky Signed-off-by: Eugeni Dodonov Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 6 +++++- drivers/gpu/drm/i915/i915_drv.h | 21 +++++++++++++++++++++ drivers/gpu/drm/i915/intel_display.c | 20 ++++++++++++++++---- 3 files changed, 42 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 1a7559b59997..c7d689e4247c 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -66,7 +66,11 @@ MODULE_PARM_DESC(semaphores, int i915_enable_rc6 __read_mostly = -1; module_param_named(i915_enable_rc6, i915_enable_rc6, int, 0600); MODULE_PARM_DESC(i915_enable_rc6, - "Enable power-saving render C-state 6 (default: -1 (use per-chip default)"); + "Enable power-saving render C-state 6. " + "Different stages can be selected via bitmask values " + "(0 = disable; 1 = enable rc6; 2 = enable deep rc6; 4 = enable deepest rc6). " + "For example, 3 would enable rc6 and deep rc6, and 7 would enable everything. " + "default: -1 (use per-chip default)"); int i915_enable_fbc __read_mostly = -1; module_param_named(i915_enable_fbc, i915_enable_fbc, int, 0600); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c0f19f572004..2c192270cb0d 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1053,6 +1053,27 @@ struct drm_i915_file_private { #include "i915_trace.h" +/** + * RC6 is a special power stage which allows the GPU to enter an very + * low-voltage mode when idle, using down to 0V while at this stage. This + * stage is entered automatically when the GPU is idle when RC6 support is + * enabled, and as soon as new workload arises GPU wakes up automatically as well. + * + * There are different RC6 modes available in Intel GPU, which differentiate + * among each other with the latency required to enter and leave RC6 and + * voltage consumed by the GPU in different states. + * + * The combination of the following flags define which states GPU is allowed + * to enter, while RC6 is the normal RC6 state, RC6p is the deep RC6, and + * RC6pp is deepest RC6. Their support by hardware varies according to the + * GPU, BIOS, chipset and platform. RC6 is usually the safest one and the one + * which brings the most power savings; deeper states save more power, but + * require higher latency to switch to and wake up. + */ +#define INTEL_RC6_ENABLE (1<<0) +#define INTEL_RC6p_ENABLE (1<<1) +#define INTEL_RC6pp_ENABLE (1<<2) + extern struct drm_ioctl_desc i915_ioctls[]; extern int i915_max_ioctl; extern unsigned int i915_fbpercrtc __always_unused; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 078477306975..a0a4e3bcbcf6 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8221,7 +8221,7 @@ void intel_init_emon(struct drm_device *dev) dev_priv->corr = (lcfuse & LCFUSE_HIV_MASK); } -static bool intel_enable_rc6(struct drm_device *dev) +static int intel_enable_rc6(struct drm_device *dev) { /* * Respect the kernel parameter if it is set @@ -8253,6 +8253,7 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv) u32 pcu_mbox, rc6_mask = 0; u32 gtfifodbg; int cur_freq, min_freq, max_freq; + int rc6_mode; int i; /* Here begins a magic sequence of register writes to enable @@ -8290,9 +8291,20 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv) I915_WRITE(GEN6_RC6p_THRESHOLD, 100000); I915_WRITE(GEN6_RC6pp_THRESHOLD, 64000); /* unused */ - if (intel_enable_rc6(dev_priv->dev)) - rc6_mask = GEN6_RC_CTL_RC6_ENABLE | - ((IS_GEN7(dev_priv->dev)) ? GEN6_RC_CTL_RC6p_ENABLE : 0); + rc6_mode = intel_enable_rc6(dev_priv->dev); + if (rc6_mode & INTEL_RC6_ENABLE) + rc6_mask |= GEN6_RC_CTL_RC6_ENABLE; + + if (rc6_mode & INTEL_RC6p_ENABLE) + rc6_mask |= GEN6_RC_CTL_RC6p_ENABLE; + + if (rc6_mode & INTEL_RC6pp_ENABLE) + rc6_mask |= GEN6_RC_CTL_RC6pp_ENABLE; + + DRM_INFO("Enabling RC6 states: RC6 %s, RC6p %s, RC6pp %s\n", + (rc6_mode & INTEL_RC6_ENABLE) ? "on" : "off", + (rc6_mode & INTEL_RC6p_ENABLE) ? "on" : "off", + (rc6_mode & INTEL_RC6pp_ENABLE) ? "on" : "off"); I915_WRITE(GEN6_RC_CONTROL, rc6_mask | -- cgit v1.2.3 From aa46419186992e6b8b8010319f0ca7f40a0d13f5 Mon Sep 17 00:00:00 2001 From: Eugeni Dodonov Date: Fri, 23 Mar 2012 11:57:19 -0300 Subject: drm/i915: enable plain RC6 on Sandy Bridge by default This is yet another chapter in the ongoing saga of bringing RC6 to Sandy Bridge machines by default. Now that we have discovered that RC6 issues are triggered by RC6+ state, let's try to disable it by default. Plain RC6 is the one responsible for most energy savings, and so far it haven't given any problems - at least, none we are aware of. So with this, when i915_enable_rc6=-1 (e.g., the default value), we'll attempt to enable plain RC6 only on SNB. For Ivy Bridge, the behavior stays the same as always - we enable both RC6 and deep RC6. Note that while this exact patch does not has explicit tested-by's, the equivalent settings were fixed in 3.3 kernel by a smaller patch. And it has also received considerable testing through Canonical RC6 task-force testing at https://wiki.ubuntu.com/Kernel/PowerManagementRC6. Up to date, it looks like all the known issues are gone. v2: improve description and reference a couple of open bugs related to RC6 which seem to be fixed with this change. References: https://bugs.freedesktop.org/show_bug.cgi?id=41682 References: https://bugs.freedesktop.org/show_bug.cgi?id=38567 References: https://bugs.freedesktop.org/show_bug.cgi?id=44867 Acked-by: Chris Wilson Signed-off-by: Eugeni Dodonov Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a0a4e3bcbcf6..ec6ea92da538 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8239,11 +8239,11 @@ static int intel_enable_rc6(struct drm_device *dev) * Disable rc6 on Sandybridge */ if (INTEL_INFO(dev)->gen == 6) { - DRM_DEBUG_DRIVER("Sandybridge: RC6 disabled\n"); - return 0; + DRM_DEBUG_DRIVER("Sandybridge: deep RC6 disabled\n"); + return INTEL_RC6_ENABLE; } - DRM_DEBUG_DRIVER("RC6 enabled\n"); - return 1; + DRM_DEBUG_DRIVER("RC6 and deep RC6 enabled\n"); + return (INTEL_RC6_ENABLE | INTEL_RC6p_ENABLE); } void gen6_enable_rps(struct drm_i915_private *dev_priv) -- cgit v1.2.3 From 25e341cfc33d94435472983825163e97fe370a6c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sat, 24 Mar 2012 23:51:30 +0100 Subject: drm/i915: quirk away broken OpRegion VBT Somehow the BIOS manages to screw things up when copying the VBT around, because the one we scrap from the VBIOS rom actually works. Cc: stable@kernel.org Tested-by: Markus Heinz Acked-by: Chris Wilson Reviewed-by: Rodrigo Vivi Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=28812 Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_bios.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 8168d8f8a634..b48fc2a8410c 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -24,6 +24,7 @@ * Eric Anholt * */ +#include #include #include "drmP.h" #include "drm.h" @@ -621,6 +622,26 @@ init_vbt_defaults(struct drm_i915_private *dev_priv) dev_priv->edp.bpp = 18; } +static int __init intel_no_opregion_vbt_callback(const struct dmi_system_id *id) +{ + DRM_DEBUG_KMS("Falling back to manually reading VBT from " + "VBIOS ROM for %s\n", + id->ident); + return 1; +} + +static const struct dmi_system_id intel_no_opregion_vbt[] = { + { + .callback = intel_no_opregion_vbt_callback, + .ident = "ThinkCentre A57", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "97027RG"), + }, + }, + { } +}; + /** * intel_parse_bios - find VBT and initialize settings from the BIOS * @dev: DRM device @@ -641,7 +662,7 @@ intel_parse_bios(struct drm_device *dev) init_vbt_defaults(dev_priv); /* XXX Should this validation be moved to intel_opregion.c? */ - if (dev_priv->opregion.vbt) { + if (!dmi_check_system(intel_no_opregion_vbt) && dev_priv->opregion.vbt) { struct vbt_header *vbt = dev_priv->opregion.vbt; if (memcmp(vbt->signature, "$VBT", 4) == 0) { DRM_DEBUG_KMS("Using VBT from OpRegion: %20s\n", -- cgit v1.2.3 From 1c7eaac737e4cca24703531ebcb566afc3ed285f Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 27 Mar 2012 09:31:24 +0200 Subject: drm/i915: apply CS reg readback trick against missed IRQ on snb Ben Widawsky reported missed IRQ issues and this patch here helps. We have one other missed IRQ report still left on snb, reported by QA: https://bugs.freedesktop.org/show_bug.cgi?id=46145 This is _not_ a regression due to the forcewake voodoo though, it started showing up before that was applied and has been on-and-off for the past few weeks. According to QA this patch does not help. But the missed IRQ is always from the blt ring (despite running piglit, so also render activity expected), so I'm hopefully that this is an issue with the blt ring itself. Tested-by: Ben Widawsky Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index fc66af6a9448..e25581a9f60f 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -626,7 +626,7 @@ gen6_ring_get_seqno(struct intel_ring_buffer *ring) /* Workaround to force correct ordering between irq and seqno writes on * ivb (and maybe also on snb) by reading from a CS register (like * ACTHD) before reading the status page. */ - if (IS_GEN7(dev)) + if (IS_GEN6(dev) || IS_GEN7(dev)) intel_ring_get_active_head(ring); return intel_read_status_page(ring, I915_GEM_HWS_INDEX); } -- cgit v1.2.3 From e77166b5a653728f312d07e60a80819d1c54fca4 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 30 Mar 2012 22:14:05 +0200 Subject: drm/i915: properly clear SSC1 bit in the pch refclock init code Noticed by staring at intel_reg_dumper diffs. Unfortunately it does not seem to completely fix the bug. Still, it's good to get this right, and maybe it helps someplace else. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=47117 Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ec6ea92da538..91b35fd1db8c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5539,7 +5539,8 @@ void ironlake_init_pch_refclk(struct drm_device *dev) if (intel_panel_use_ssc(dev_priv) && can_ssc) { DRM_DEBUG_KMS("Using SSC on panel\n"); temp |= DREF_SSC1_ENABLE; - } + } else + temp &= ~DREF_SSC1_ENABLE; /* Get SSC going before enabling the outputs */ I915_WRITE(PCH_DREF_CONTROL, temp); -- cgit v1.2.3 From 4b4e9e43fd210e0cd2a5d29357e7c000e13e08ae Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 23 Mar 2012 11:04:57 +0100 Subject: regmap: rbtree: Fix register default look-up in sync The code currently passes the register offset in the current block to regcache_lookup_reg. This works fine as long as there is only one block and with base register of 0, but in all other cases it will look-up the default for a wrong register, which can cause unnecessary register writes. This patch fixes it by passing the actual register number to regcache_lookup_reg. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown Cc: --- drivers/base/regmap/regcache-rbtree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c index 5157fa04c2f0..fb14a6343d4f 100644 --- a/drivers/base/regmap/regcache-rbtree.c +++ b/drivers/base/regmap/regcache-rbtree.c @@ -396,7 +396,7 @@ static int regcache_rbtree_sync(struct regmap *map, unsigned int min, map->cache_word_size); /* Is this the hardware default? If so skip. */ - ret = regcache_lookup_reg(map, i); + ret = regcache_lookup_reg(map, regtmp); if (ret >= 0 && val == map->reg_defaults[ret].def) continue; -- cgit v1.2.3 From c1a1260244d8ffe017fbb3199f65c842e4d42fe6 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 20 Mar 2012 23:06:34 -0400 Subject: hwmon: (gpio-fan) Fix Kconfig dependencies gpio-fan depends on GPIOLIB, not on GENERIC_GPIO. This fixes the following build error, seen if GPIOLIB is not defined: src/drivers/hwmon/gpio-fan.c: error: implicit declaration of function 'gpio_direction_output': => 372:3 src/drivers/hwmon/gpio-fan.c: error: implicit declaration of function 'gpio_free': => 130:2 src/drivers/hwmon/gpio-fan.c: error: implicit declaration of function 'gpio_get_value': => 79:2 src/drivers/hwmon/gpio-fan.c: error: implicit declaration of function 'gpio_request': => 98:2 src/drivers/hwmon/gpio-fan.c: error: implicit declaration of function 'gpio_set_value': => 156:3 src/drivers/hwmon/gpio-fan.c: error: implicit declaration of function 'gpio_to_irq': => 114:2 Signed-off-by: Guenter Roeck Acked-by: Jean Delvare Acked-by: Simon Guinot --- drivers/hwmon/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 5b32d56dbb4d..496f80dcc80c 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -425,7 +425,7 @@ config SENSORS_GL520SM config SENSORS_GPIO_FAN tristate "GPIO fan" - depends on GENERIC_GPIO + depends on GPIOLIB help If you say yes here you get support for fans connected to GPIO lines. -- cgit v1.2.3 From be45d422d96ba22ecd0e34690644099d172e9c6d Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 20 Mar 2012 23:06:35 -0400 Subject: hwmon: (sht15) Fix Kconfig dependencies sht15 depends on GPIOLIB, not on GENERIC_GPIO. This fixes the following build error, seen if GPIOLIB is not defined: src/drivers/hwmon/sht15.c: error: implicit declaration of function 'gpio_direction_input': => 293:2 src/drivers/hwmon/sht15.c: error: implicit declaration of function 'gpio_direction_output': => 216:2 src/drivers/hwmon/sht15.c: error: implicit declaration of function 'gpio_free': => 1000:2 src/drivers/hwmon/sht15.c: error: implicit declaration of function 'gpio_get_value': => 296:2 src/drivers/hwmon/sht15.c: error: implicit declaration of function 'gpio_request': => 946:2 src/drivers/hwmon/sht15.c: error: implicit declaration of function 'gpio_set_value': => 218:2 src/drivers/hwmon/sht15.c: error: implicit declaration of function 'gpio_to_irq': => 514:2 Signed-off-by: Guenter Roeck Acked-by: Jean Delvare --- drivers/hwmon/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 496f80dcc80c..670f274a18e6 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -883,7 +883,7 @@ source drivers/hwmon/pmbus/Kconfig config SENSORS_SHT15 tristate "Sensiron humidity and temperature sensors. SHT15 and compat." - depends on GENERIC_GPIO + depends on GPIOLIB help If you say yes here you get support for the Sensiron SHT10, SHT11, SHT15, SHT71, SHT75 humidity and temperature sensors. -- cgit v1.2.3 From 52f30f77171f934cb9562908cb279178b890a048 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 22 Mar 2012 16:23:58 -0400 Subject: hwmon: (max6639) Convert to dev_pm_ops The I2C specific PM operations have been deprecated and printing a warning on boot for over a year now. Signed-off-by: Mark Brown [guenter.roeck@ericsson.com: Added missing #ifdef around pm functions] Cc: stable@vger.kernel.org # 3.0+ Signed-off-by: Guenter Roeck --- drivers/hwmon/max6639.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/max6639.c b/drivers/hwmon/max6639.c index 193067e27b6f..de8f7adaccbd 100644 --- a/drivers/hwmon/max6639.c +++ b/drivers/hwmon/max6639.c @@ -596,8 +596,10 @@ static int max6639_remove(struct i2c_client *client) return 0; } -static int max6639_suspend(struct i2c_client *client, pm_message_t mesg) +#ifdef CONFIG_PM_SLEEP +static int max6639_suspend(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); int data = i2c_smbus_read_byte_data(client, MAX6639_REG_GCONFIG); if (data < 0) return data; @@ -606,8 +608,9 @@ static int max6639_suspend(struct i2c_client *client, pm_message_t mesg) MAX6639_REG_GCONFIG, data | MAX6639_GCONFIG_STANDBY); } -static int max6639_resume(struct i2c_client *client) +static int max6639_resume(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); int data = i2c_smbus_read_byte_data(client, MAX6639_REG_GCONFIG); if (data < 0) return data; @@ -615,6 +618,7 @@ static int max6639_resume(struct i2c_client *client) return i2c_smbus_write_byte_data(client, MAX6639_REG_GCONFIG, data & ~MAX6639_GCONFIG_STANDBY); } +#endif /* CONFIG_PM_SLEEP */ static const struct i2c_device_id max6639_id[] = { {"max6639", 0}, @@ -623,15 +627,18 @@ static const struct i2c_device_id max6639_id[] = { MODULE_DEVICE_TABLE(i2c, max6639_id); +static const struct dev_pm_ops max6639_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(max6639_suspend, max6639_resume) +}; + static struct i2c_driver max6639_driver = { .class = I2C_CLASS_HWMON, .driver = { .name = "max6639", + .pm = &max6639_pm_ops, }, .probe = max6639_probe, .remove = max6639_remove, - .suspend = max6639_suspend, - .resume = max6639_resume, .id_table = max6639_id, .detect = max6639_detect, .address_list = normal_i2c, -- cgit v1.2.3 From 6394011d65b7e74666f07cca98747601cf8298fa Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 24 Mar 2012 08:38:21 -0700 Subject: hwmon: (f75375s) Fix warning message seen in some configurations In some configurations, BUG() does not result in an endless loop but returns to the caller. This results in the following compiler warning: drivers/hwmon/f75375s.c: In function 'duty_mode_enabled': drivers/hwmon/f75375s.c:280: warning: control reaches end of non-void function drivers/hwmon/f75375s.c: In function 'auto_mode_enabled': drivers/hwmon/f75375s.c:295: warning: control reaches end of non-void function Fix the warning by returning something sensible after BUG(). Cc: Nikolaus Schulz Cc: Riku Voipio Signed-off-by: Guenter Roeck Acked-by: Jean Delvare Signed-off-by: Guenter Roeck --- drivers/hwmon/f75375s.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c index 729499e75210..ece4159bd453 100644 --- a/drivers/hwmon/f75375s.c +++ b/drivers/hwmon/f75375s.c @@ -276,6 +276,7 @@ static bool duty_mode_enabled(u8 pwm_enable) return false; default: BUG(); + return true; } } @@ -291,6 +292,7 @@ static bool auto_mode_enabled(u8 pwm_enable) return true; default: BUG(); + return false; } } -- cgit v1.2.3 From ce15a81da33b961852f6e6a55305ccc60856de25 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 24 Mar 2012 08:51:05 -0700 Subject: hwmon: (adm1031) Fix compiler warning Some configurations produce the following compile warning: drivers/hwmon/adm1031.c: In function 'set_fan_auto_channel': drivers/hwmon/adm1031.c:292: warning: 'reg' may be used uninitialized in this function While this is a false positive, it can easily be fixed by overloading the return value from get_fan_auto_nearest with both register value and error return code (the register value is never negative). Coincidentially, that also reduces module size by a few bytes. Signed-off-by: Guenter Roeck Acked-by: Jean Delvare --- drivers/hwmon/adm1031.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c index ff37363ea5bc..44e1fd7f3d81 100644 --- a/drivers/hwmon/adm1031.c +++ b/drivers/hwmon/adm1031.c @@ -233,18 +233,15 @@ static const auto_chan_table_t auto_channel_select_table_adm1030 = { * nearest match if no exact match where found. */ static int -get_fan_auto_nearest(struct adm1031_data *data, - int chan, u8 val, u8 reg, u8 *new_reg) +get_fan_auto_nearest(struct adm1031_data *data, int chan, u8 val, u8 reg) { int i; int first_match = -1, exact_match = -1; u8 other_reg_val = (*data->chan_select_table)[FAN_CHAN_FROM_REG(reg)][chan ? 0 : 1]; - if (val == 0) { - *new_reg = 0; + if (val == 0) return 0; - } for (i = 0; i < 8; i++) { if ((val == (*data->chan_select_table)[i][chan]) && @@ -264,13 +261,11 @@ get_fan_auto_nearest(struct adm1031_data *data, } if (exact_match >= 0) - *new_reg = exact_match; + return exact_match; else if (first_match >= 0) - *new_reg = first_match; - else - return -EINVAL; + return first_match; - return 0; + return -EINVAL; } static ssize_t show_fan_auto_channel(struct device *dev, @@ -301,11 +296,12 @@ set_fan_auto_channel(struct device *dev, struct device_attribute *attr, mutex_lock(&data->update_lock); - ret = get_fan_auto_nearest(data, nr, val, data->conf1, ®); - if (ret) { + ret = get_fan_auto_nearest(data, nr, val, data->conf1); + if (ret < 0) { mutex_unlock(&data->update_lock); return ret; } + reg = ret; data->conf1 = FAN_CHAN_TO_REG(reg, data->conf1); if ((data->conf1 & ADM1031_CONF1_AUTO_MODE) ^ (old_fan_mode & ADM1031_CONF1_AUTO_MODE)) { -- cgit v1.2.3 From 31e354ee653c3d85e802a372f27224130fc95011 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Wed, 28 Mar 2012 15:11:47 -0400 Subject: hwmon: (acpi_power_meter) fix lockdep spew due to non-static lock class Similar to a30dcb4f which fixed asus_atk0110.ko, I recently received a bug report from someone hitting the same issue in acpi_power_meter. [ 13.963168] power_meter ACPI000D:00: Found ACPI power meter. [ 13.963900] BUG: key ffff8802161f3920 not in .data! [ 13.963904] ------------[ cut here ]------------ [ 13.963915] WARNING: at kernel/lockdep.c:2986 lockdep_init_map+0x52f/0x560() So let's fix that up for them by statically declaring the lockdep_class_key. Signed-off-by: Kyle McMartin Cc: stable@vger.kernel.org # 3.0+ Signed-off-by: Guenter Roeck --- drivers/hwmon/acpi_power_meter.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c index 554f046bcf20..145f13580ff0 100644 --- a/drivers/hwmon/acpi_power_meter.c +++ b/drivers/hwmon/acpi_power_meter.c @@ -632,6 +632,7 @@ static int register_ro_attrs(struct acpi_power_meter_resource *resource, sensors->dev_attr.show = ro->show; sensors->index = ro->index; + sysfs_attr_init(&sensors->dev_attr.attr); res = device_create_file(dev, &sensors->dev_attr); if (res) { sensors->dev_attr.attr.name = NULL; @@ -661,6 +662,7 @@ static int register_rw_attrs(struct acpi_power_meter_resource *resource, sensors->dev_attr.store = rw->set; sensors->index = rw->index; + sysfs_attr_init(&sensors->dev_attr.attr); res = device_create_file(dev, &sensors->dev_attr); if (res) { sensors->dev_attr.attr.name = NULL; -- cgit v1.2.3 From 6f7805a8d9dc6fa8af999f8603188157505558d9 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 30 Mar 2012 16:04:55 -0400 Subject: hwmon: (w83627ehf) mark const init data with __initconst instead of __initdata MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As long as there is no other non-const variable marked __initdata in the same compilation unit it doesn't hurt. If there were one however compilation would fail with error: $variablename causes a section type conflict because a section containing const variables is marked read only and so cannot contain non-const variables. Signed-off-by: Uwe Kleine-König Cc: Jean Delvare Cc: Guenter Roeck Cc: lm-sensors@lm-sensors.org Signed-off-by: Guenter Roeck --- drivers/hwmon/w83627ehf.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index a25350cf9554..54922ed12978 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -2619,15 +2619,15 @@ static struct platform_driver w83627ehf_driver = { static int __init w83627ehf_find(int sioaddr, unsigned short *addr, struct w83627ehf_sio_data *sio_data) { - static const char __initdata sio_name_W83627EHF[] = "W83627EHF"; - static const char __initdata sio_name_W83627EHG[] = "W83627EHG"; - static const char __initdata sio_name_W83627DHG[] = "W83627DHG"; - static const char __initdata sio_name_W83627DHG_P[] = "W83627DHG-P"; - static const char __initdata sio_name_W83627UHG[] = "W83627UHG"; - static const char __initdata sio_name_W83667HG[] = "W83667HG"; - static const char __initdata sio_name_W83667HG_B[] = "W83667HG-B"; - static const char __initdata sio_name_NCT6775[] = "NCT6775F"; - static const char __initdata sio_name_NCT6776[] = "NCT6776F"; + static const char sio_name_W83627EHF[] __initconst = "W83627EHF"; + static const char sio_name_W83627EHG[] __initconst = "W83627EHG"; + static const char sio_name_W83627DHG[] __initconst = "W83627DHG"; + static const char sio_name_W83627DHG_P[] __initconst = "W83627DHG-P"; + static const char sio_name_W83627UHG[] __initconst = "W83627UHG"; + static const char sio_name_W83667HG[] __initconst = "W83667HG"; + static const char sio_name_W83667HG_B[] __initconst = "W83667HG-B"; + static const char sio_name_NCT6775[] __initconst = "NCT6775F"; + static const char sio_name_NCT6776[] __initconst = "NCT6776F"; u16 val; const char *sio_name; -- cgit v1.2.3 From fbc729a446f7d80ec8b73fe90d8c0cc3e95ad277 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Fri, 30 Mar 2012 16:48:20 -0400 Subject: hwmon: (k10temp) Add support for AMD Trinity CPUs The on-chip northbridge's temperature sensor of the upcoming AMD Trinity CPUs works the same as for the previous CPUs. Since it has a different PCI-ID, we just add the new one to the list supported by k10temp. This allows to use the k10temp driver on those CPUs. Signed-off-by: Andre Przywara Cc: stable@vger.kernel.org # 3.0+ Signed-off-by: Guenter Roeck --- Documentation/hwmon/k10temp | 2 +- drivers/hwmon/Kconfig | 3 ++- drivers/hwmon/k10temp.c | 4 ++++ 3 files changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/Documentation/hwmon/k10temp b/Documentation/hwmon/k10temp index a10f73624ad3..90956b618025 100644 --- a/Documentation/hwmon/k10temp +++ b/Documentation/hwmon/k10temp @@ -11,7 +11,7 @@ Supported chips: Socket S1G2: Athlon (X2), Sempron (X2), Turion X2 (Ultra) * AMD Family 12h processors: "Llano" (E2/A4/A6/A8-Series) * AMD Family 14h processors: "Brazos" (C/E/G/Z-Series) -* AMD Family 15h processors: "Bulldozer" +* AMD Family 15h processors: "Bulldozer" (FX-Series), "Trinity" Prefix: 'k10temp' Addresses scanned: PCI space diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 670f274a18e6..8deedc1b9840 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -253,7 +253,8 @@ config SENSORS_K10TEMP If you say yes here you get support for the temperature sensor(s) inside your CPU. Supported are later revisions of the AMD Family 10h and all revisions of the AMD Family 11h, - 12h (Llano), 14h (Brazos) and 15h (Bulldozer) microarchitectures. + 12h (Llano), 14h (Brazos) and 15h (Bulldozer/Trinity) + microarchitectures. This driver can also be built as a module. If so, the module will be called k10temp. diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c index aba29d63f195..307bb325dde9 100644 --- a/drivers/hwmon/k10temp.c +++ b/drivers/hwmon/k10temp.c @@ -33,6 +33,9 @@ static bool force; module_param(force, bool, 0444); MODULE_PARM_DESC(force, "force loading on processors with erratum 319"); +/* PCI-IDs for Northbridge devices not used anywhere else */ +#define PCI_DEVICE_ID_AMD_15H_M10H_NB_F3 0x1403 + /* CPUID function 0x80000001, ebx */ #define CPUID_PKGTYPE_MASK 0xf0000000 #define CPUID_PKGTYPE_F 0x00000000 @@ -210,6 +213,7 @@ static DEFINE_PCI_DEVICE_TABLE(k10temp_id_table) = { { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_11H_NB_MISC) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CNB17H_F3) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F3) }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M10H_NB_F3) }, {} }; MODULE_DEVICE_TABLE(pci, k10temp_id_table); -- cgit v1.2.3 From 464b57da56910c8737ede75ad820b9a7afc46b3e Mon Sep 17 00:00:00 2001 From: Kenth Eriksson Date: Tue, 27 Mar 2012 22:05:54 +0000 Subject: Fix non TBI PHY access; a bad merge undid bug fix in a previous commit. The merge done in commit b26e478f undid bug fix in commit c3e072f8 ("net: fsl_pq_mdio: fix non tbi phy access"), with the result that non TBI (e.g. MDIO) PHYs cannot be accessed. Signed-off-by: Kenth Eriksson Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fsl_pq_mdio.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/freescale/fsl_pq_mdio.c b/drivers/net/ethernet/freescale/fsl_pq_mdio.c index 9eb815941df5..f7f0bf5d037b 100644 --- a/drivers/net/ethernet/freescale/fsl_pq_mdio.c +++ b/drivers/net/ethernet/freescale/fsl_pq_mdio.c @@ -356,13 +356,13 @@ static int fsl_pq_mdio_probe(struct platform_device *ofdev) if (prop) tbiaddr = *prop; - } - if (tbiaddr == -1) { - err = -EBUSY; - goto err_free_irqs; - } else { - out_be32(tbipa, tbiaddr); + if (tbiaddr == -1) { + err = -EBUSY; + goto err_free_irqs; + } else { + out_be32(tbipa, tbiaddr); + } } err = of_mdiobus_register(new_bus, np); -- cgit v1.2.3 From cdaf0b835df04177397b90214f8b457fd23b67e0 Mon Sep 17 00:00:00 2001 From: "stigge@antcom.de" Date: Wed, 28 Mar 2012 12:36:26 +0000 Subject: net: lpc_eth: Fix rename of dev_hw_addr_random In parallel to the integration of lpc_eth.c, dev_hw_addr_random() has been renamed to eth_hw_addr_random(). This patch fixes it also in the new driver lpc_eth.c. Signed-off-by: Roland Stigge Signed-off-by: David S. Miller --- drivers/net/ethernet/nxp/lpc_eth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/nxp/lpc_eth.c b/drivers/net/ethernet/nxp/lpc_eth.c index 69444247c20b..6dfc26d85e47 100644 --- a/drivers/net/ethernet/nxp/lpc_eth.c +++ b/drivers/net/ethernet/nxp/lpc_eth.c @@ -1441,7 +1441,7 @@ static int lpc_eth_drv_probe(struct platform_device *pdev) } #endif if (!is_valid_ether_addr(ndev->dev_addr)) - dev_hw_addr_random(ndev, ndev->dev_addr); + eth_hw_addr_random(ndev); /* Reset the ethernet controller */ __lpc_eth_reset(pldat); -- cgit v1.2.3 From 98d5561bfbc3c7a53d6abc1812a2bd5344d36fa3 Mon Sep 17 00:00:00 2001 From: majianpeng Date: Mon, 2 Apr 2012 09:48:37 +1000 Subject: md/linear: If md_integrity_register() fails, linear_run() must free the mem. Signed-off-by: majianpeng Signed-off-by: NeilBrown --- drivers/md/linear.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/md/linear.c b/drivers/md/linear.c index b0fcc7d02adb..fa211d80fc0a 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c @@ -198,6 +198,7 @@ out: static int linear_run (struct mddev *mddev) { struct linear_conf *conf; + int ret; if (md_check_no_bitmap(mddev)) return -EINVAL; @@ -211,7 +212,13 @@ static int linear_run (struct mddev *mddev) blk_queue_merge_bvec(mddev->queue, linear_mergeable_bvec); mddev->queue->backing_dev_info.congested_fn = linear_congested; mddev->queue->backing_dev_info.congested_data = mddev; - return md_integrity_register(mddev); + + ret = md_integrity_register(mddev); + if (ret) { + kfree(conf); + mddev->private = NULL; + } + return ret; } static int linear_add(struct mddev *mddev, struct md_rdev *rdev) -- cgit v1.2.3 From 0366ef847581d692e197b88825867ca9ee00e358 Mon Sep 17 00:00:00 2001 From: majianpeng Date: Mon, 2 Apr 2012 09:48:37 +1000 Subject: md/raid0: If md_integrity_register() fails, raid0_run() must free the mem. Signed-off-by: majianpeng Signed-off-by: NeilBrown --- drivers/md/raid0.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index 6f31f5596e01..c9809453a346 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -407,6 +407,8 @@ static sector_t raid0_size(struct mddev *mddev, sector_t sectors, int raid_disks return array_sectors; } +static int raid0_stop(struct mddev *mddev); + static int raid0_run(struct mddev *mddev) { struct r0conf *conf; @@ -454,7 +456,12 @@ static int raid0_run(struct mddev *mddev) blk_queue_merge_bvec(mddev->queue, raid0_mergeable_bvec); dump_zones(mddev); - return md_integrity_register(mddev); + + ret = md_integrity_register(mddev); + if (ret) + raid0_stop(mddev); + + return ret; } static int raid0_stop(struct mddev *mddev) -- cgit v1.2.3 From 5220ea1e640869e70f894837678315c878c651fd Mon Sep 17 00:00:00 2001 From: majianpeng Date: Mon, 2 Apr 2012 09:48:38 +1000 Subject: md/raid1: If md_integrity_register() failed,run() must free the mem Signed-off-by: majianpeng Signed-off-by: NeilBrown --- drivers/md/raid1.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 4a40a200d769..242440831b23 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -2636,11 +2636,13 @@ static struct r1conf *setup_conf(struct mddev *mddev) return ERR_PTR(err); } +static int stop(struct mddev *mddev); static int run(struct mddev *mddev) { struct r1conf *conf; int i; struct md_rdev *rdev; + int ret; if (mddev->level != 1) { printk(KERN_ERR "md/raid1:%s: raid level not set to mirroring (%d)\n", @@ -2705,7 +2707,11 @@ static int run(struct mddev *mddev) mddev->queue->backing_dev_info.congested_data = mddev; blk_queue_merge_bvec(mddev->queue, raid1_mergeable_bvec); } - return md_integrity_register(mddev); + + ret = md_integrity_register(mddev); + if (ret) + stop(mddev); + return ret; } static int stop(struct mddev *mddev) -- cgit v1.2.3 From 3f8c91a7398b9266fbe7abcbe4bd5dffef907643 Mon Sep 17 00:00:00 2001 From: Andreas Mohr Date: Sun, 1 Apr 2012 12:35:00 +0000 Subject: via-rhine: fix wait-bit inversion. Bug appeared in a384a33bb1c9ec2d99db2046b41f57023fa7d77b ("via-rhine: RHINE_WAIT_FOR macro removal). It can be noticed during suspend/resume. Signed-off-by: Andreas Mohr Acked-by: Francois Romieu Cc: David Lv Signed-off-by: David S. Miller --- drivers/net/ethernet/via/via-rhine.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/via/via-rhine.c b/drivers/net/ethernet/via/via-rhine.c index 39b8cf3dafcd..fcfa01f7ceb6 100644 --- a/drivers/net/ethernet/via/via-rhine.c +++ b/drivers/net/ethernet/via/via-rhine.c @@ -503,30 +503,32 @@ static int rhine_vlan_rx_add_vid(struct net_device *dev, unsigned short vid); static int rhine_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid); static void rhine_restart_tx(struct net_device *dev); -static void rhine_wait_bit(struct rhine_private *rp, u8 reg, u8 mask, bool high) +static void rhine_wait_bit(struct rhine_private *rp, u8 reg, u8 mask, bool low) { void __iomem *ioaddr = rp->base; int i; for (i = 0; i < 1024; i++) { - if (high ^ !!(ioread8(ioaddr + reg) & mask)) + bool has_mask_bits = !!(ioread8(ioaddr + reg) & mask); + + if (low ^ has_mask_bits) break; udelay(10); } if (i > 64) { netif_dbg(rp, hw, rp->dev, "%s bit wait (%02x/%02x) cycle " - "count: %04d\n", high ? "high" : "low", reg, mask, i); + "count: %04d\n", low ? "low" : "high", reg, mask, i); } } static void rhine_wait_bit_high(struct rhine_private *rp, u8 reg, u8 mask) { - rhine_wait_bit(rp, reg, mask, true); + rhine_wait_bit(rp, reg, mask, false); } static void rhine_wait_bit_low(struct rhine_private *rp, u8 reg, u8 mask) { - rhine_wait_bit(rp, reg, mask, false); + rhine_wait_bit(rp, reg, mask, true); } static u32 rhine_get_events(struct rhine_private *rp) -- cgit v1.2.3 From acc656323ab904803393acefdc8e1b78cde752e5 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Fri, 30 Mar 2012 01:01:46 +0000 Subject: rionet: fix page allocation order of rionet_active rionet_active is allocated from the page allocator and the allocation order is calculated on the assumption that the page size is 4KB, so it wastes memory on more than 4K page systems. Signed-off-by: Akinobu Mita Cc: Matt Porter Cc: Alexandre Bounine Cc: netdev@vger.kernel.org Signed-off-by: David S. Miller --- drivers/net/rionet.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c index a57f05726b57..91d25888a1b9 100644 --- a/drivers/net/rionet.c +++ b/drivers/net/rionet.c @@ -375,8 +375,8 @@ static void rionet_remove(struct rio_dev *rdev) struct net_device *ndev = rio_get_drvdata(rdev); struct rionet_peer *peer, *tmp; - free_pages((unsigned long)rionet_active, rdev->net->hport->sys_size ? - __fls(sizeof(void *)) + 4 : 0); + free_pages((unsigned long)rionet_active, get_order(sizeof(void *) * + RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size))); unregister_netdev(ndev); free_netdev(ndev); @@ -432,15 +432,16 @@ static int rionet_setup_netdev(struct rio_mport *mport, struct net_device *ndev) int rc = 0; struct rionet_private *rnet; u16 device_id; + const size_t rionet_active_bytes = sizeof(void *) * + RIO_MAX_ROUTE_ENTRIES(mport->sys_size); rionet_active = (struct rio_dev **)__get_free_pages(GFP_KERNEL, - mport->sys_size ? __fls(sizeof(void *)) + 4 : 0); + get_order(rionet_active_bytes)); if (!rionet_active) { rc = -ENOMEM; goto out; } - memset((void *)rionet_active, 0, sizeof(void *) * - RIO_MAX_ROUTE_ENTRIES(mport->sys_size)); + memset((void *)rionet_active, 0, rionet_active_bytes); /* Set up private area */ rnet = netdev_priv(ndev); -- cgit v1.2.3 From 6bafd6436e99d08e8def37ae9f790e1aff871bae Mon Sep 17 00:00:00 2001 From: huajun li Date: Fri, 30 Mar 2012 00:11:05 +0000 Subject: usb/rtl8150 : Remove duplicated definitions There exist duplicated macro definitions in rtl8150.c, remove them. Signed-off-by: Huajun Li Signed-off-by: David S. Miller --- drivers/net/usb/rtl8150.c | 26 -------------------------- 1 file changed, 26 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c index 6dda2fe5b15b..d363b31053da 100644 --- a/drivers/net/usb/rtl8150.c +++ b/drivers/net/usb/rtl8150.c @@ -59,32 +59,6 @@ #define RTL8150_REQ_SET_REGS 0x05 -/* Transmit status register errors */ -#define TSR_ECOL (1<<5) -#define TSR_LCOL (1<<4) -#define TSR_LOSS_CRS (1<<3) -#define TSR_JBR (1<<2) -#define TSR_ERRORS (TSR_ECOL | TSR_LCOL | TSR_LOSS_CRS | TSR_JBR) -/* Receive status register errors */ -#define RSR_CRC (1<<2) -#define RSR_FAE (1<<1) -#define RSR_ERRORS (RSR_CRC | RSR_FAE) - -/* Media status register definitions */ -#define MSR_DUPLEX (1<<4) -#define MSR_SPEED (1<<3) -#define MSR_LINK (1<<2) - -/* Interrupt pipe data */ -#define INT_TSR 0x00 -#define INT_RSR 0x01 -#define INT_MSR 0x02 -#define INT_WAKSR 0x03 -#define INT_TXOK_CNT 0x04 -#define INT_RXLOST_CNT 0x05 -#define INT_CRERR_CNT 0x06 -#define INT_COL_CNT 0x07 - /* Transmit status register errors */ #define TSR_ECOL (1<<5) #define TSR_LCOL (1<<4) -- cgit v1.2.3 From 10b9194f959608368ed89df1937f17cfe6bd6d84 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Thu, 29 Mar 2012 19:32:08 +0000 Subject: net: sh_eth: fix endian check for architecture independent SuperH has the "CONFIG_CPU_LITTLE_ENDIAN" and the "__LITTLE_ENDIAN__". But, other architecture doesn't have them. So, this patch fixes it. Signed-off-by: Yoshihiro Shimoda Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/sh_eth.c | 2 +- drivers/net/ethernet/renesas/sh_eth.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 8bdf070ace90..d63e09b29a96 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -804,7 +804,7 @@ static int sh_eth_dev_init(struct net_device *ndev) /* all sh_eth int mask */ sh_eth_write(ndev, 0, EESIPR); -#if defined(__LITTLE_ENDIAN__) +#if defined(__LITTLE_ENDIAN) if (mdp->cd->hw_swap) sh_eth_write(ndev, EDMR_EL, EDMR); else diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h index e66de1823532..0fa14afce23d 100644 --- a/drivers/net/ethernet/renesas/sh_eth.h +++ b/drivers/net/ethernet/renesas/sh_eth.h @@ -693,7 +693,7 @@ enum TSU_FWSLC_BIT { */ struct sh_eth_txdesc { u32 status; /* TD0 */ -#if defined(CONFIG_CPU_LITTLE_ENDIAN) +#if defined(__LITTLE_ENDIAN) u16 pad0; /* TD1 */ u16 buffer_length; /* TD1 */ #else @@ -710,7 +710,7 @@ struct sh_eth_txdesc { */ struct sh_eth_rxdesc { u32 status; /* RD0 */ -#if defined(CONFIG_CPU_LITTLE_ENDIAN) +#if defined(__LITTLE_ENDIAN) u16 frame_length; /* RD1 */ u16 buffer_length; /* RD1 */ #else -- cgit v1.2.3 From 78fb72f7936c01d5b426c03a691eca082b03f2b9 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Thu, 29 Mar 2012 07:15:15 +0000 Subject: net: usb: cdc_eem: fix mtu Make CDC EEM recalculate the hard_mtu after adjusting the hard_header_len. Without this, usbnet adjusts the MTU down to 1494 bytes, and the host is unable to receive standard 1500-byte frames from the device. Tested with the Linux USB Ethernet gadget. Cc: Oliver Neukum Signed-off-by: Rabin Vincent Signed-off-by: David S. Miller --- drivers/net/usb/cdc_eem.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/usb/cdc_eem.c b/drivers/net/usb/cdc_eem.c index 439690be519f..685a4e22c768 100644 --- a/drivers/net/usb/cdc_eem.c +++ b/drivers/net/usb/cdc_eem.c @@ -93,6 +93,7 @@ static int eem_bind(struct usbnet *dev, struct usb_interface *intf) /* no jumbogram (16K) support for now */ dev->net->hard_header_len += EEM_HEAD + ETH_FCS_LEN; + dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len; return 0; } -- cgit v1.2.3 From 40c61046ee3007d73f141e96aa2f3dd56ee321c6 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 2 Apr 2012 10:45:49 +0100 Subject: drm/nouveau: select POWER_SUPPLY Ben H. reported that building nouveau into the kernel and power supply as a module was broken. Just have nouveau select it, like radeon does. Reported-by: Benjamin Herrenschmidt Signed-off-by: Dave Airlie --- drivers/gpu/drm/nouveau/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig index ca1639918f57..97a81260485a 100644 --- a/drivers/gpu/drm/nouveau/Kconfig +++ b/drivers/gpu/drm/nouveau/Kconfig @@ -13,6 +13,7 @@ config DRM_NOUVEAU select ACPI_VIDEO if ACPI && X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL && INPUT select ACPI_WMI if ACPI select MXM_WMI if ACPI + select POWER_SUPPLY help Choose this option for open-source nVidia support. -- cgit v1.2.3 From ea71f98d680c9ac768a7849d26d7ce4744064510 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 2 Apr 2012 13:37:13 +1000 Subject: nouveau: Fix crash when pci_ram_rom() returns a size of 0 From b15b244d6e6e20964bd4b85306722cb60c3c0809 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 2 Apr 2012 13:28:18 +1000 Subject: Under some circumstances, pci_map_rom() can return a valid mapping but a size of 0 (if it cannot find an image in the header). This causes nouveau to try to kmalloc() a 0 sized pointer and dereference it, which crashes. Signed-off-by: Benjamin Herrenschmidt Acked-by: Ben Skeggs Signed-off-by: Dave Airlie --- drivers/gpu/drm/nouveau/nouveau_bios.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 637afe71de56..80963d05b54a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -177,14 +177,15 @@ bios_shadow_pci(struct nvbios *bios) if (!pci_enable_rom(pdev)) { void __iomem *rom = pci_map_rom(pdev, &length); - if (rom) { + if (rom && length) { bios->data = kmalloc(length, GFP_KERNEL); if (bios->data) { memcpy_fromio(bios->data, rom, length); bios->length = length; } - pci_unmap_rom(pdev, rom); } + if (rom) + pci_unmap_rom(pdev, rom); pci_disable_rom(pdev); } -- cgit v1.2.3 From d06221c0617ab6d0bc41c4980cefdd9c8cc9a1c1 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 2 Apr 2012 13:38:19 +1000 Subject: nouveau/bios: Fix tracking of BIOS image data The code tries various methods for retreiving the BIOS data. However it doesn't clear the bios->data pointer between the iterations. In some cases, the shadow() method will fail and not update bios->data at all, which will cause us to "score" the old data and incorrectly attribute that score to the new method. This can cause double frees later when disposing of the unused data. Additionally, we were not freeing the data for methods that fail the score test (we only freed when a "best" is superseeded, not when the new method has a lower score than the exising "best"). Fix that as well. Signed-off-by: Benjamin Herrenschmidt Acked-by: Ben Skeggs Signed-off-by: Dave Airlie --- drivers/gpu/drm/nouveau/nouveau_bios.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 80963d05b54a..1947d6139a38 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -273,6 +273,7 @@ bios_shadow(struct drm_device *dev) mthd->score = score_vbios(bios, mthd->rw); mthd->size = bios->length; mthd->data = bios->data; + bios->data = NULL; } while (mthd->score != 3 && (++mthd)->shadow); mthd = shadow_methods; @@ -281,7 +282,8 @@ bios_shadow(struct drm_device *dev) if (mthd->score > best->score) { kfree(best->data); best = mthd; - } + } else + kfree(mthd->data); } while ((++mthd)->shadow); if (best->score) { -- cgit v1.2.3 From 402976fe51b2d1a58a29ba06fa1ca5ace3a4cdcd Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 29 Mar 2012 19:04:08 -0400 Subject: drm/radeon/kms: fix fans after resume MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On pre-R600 asics, the SpeedFanControl table is not executed as part of ASIC_Init as it is on newer asics. Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=29412 Signed-off-by: Alex Deucher Reviewed-by: Michel Dänzer Cc: stable@vger.kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atom.c | 15 ++++++++++++++- drivers/gpu/drm/radeon/atom.h | 1 + 2 files changed, 15 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c index d1bd239cd9e9..5ce9bf51a8de 100644 --- a/drivers/gpu/drm/radeon/atom.c +++ b/drivers/gpu/drm/radeon/atom.c @@ -1306,8 +1306,11 @@ struct atom_context *atom_parse(struct card_info *card, void *bios) int atom_asic_init(struct atom_context *ctx) { + struct radeon_device *rdev = ctx->card->dev->dev_private; int hwi = CU16(ctx->data_table + ATOM_DATA_FWI_PTR); uint32_t ps[16]; + int ret; + memset(ps, 0, 64); ps[0] = cpu_to_le32(CU32(hwi + ATOM_FWI_DEFSCLK_PTR)); @@ -1317,7 +1320,17 @@ int atom_asic_init(struct atom_context *ctx) if (!CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_INIT)) return 1; - return atom_execute_table(ctx, ATOM_CMD_INIT, ps); + ret = atom_execute_table(ctx, ATOM_CMD_INIT, ps); + if (ret) + return ret; + + memset(ps, 0, 64); + + if (rdev->family < CHIP_R600) { + if (CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_SPDFANCNTL)) + atom_execute_table(ctx, ATOM_CMD_SPDFANCNTL, ps); + } + return ret; } void atom_destroy(struct atom_context *ctx) diff --git a/drivers/gpu/drm/radeon/atom.h b/drivers/gpu/drm/radeon/atom.h index 93cfe2086ba0..25fea631dad2 100644 --- a/drivers/gpu/drm/radeon/atom.h +++ b/drivers/gpu/drm/radeon/atom.h @@ -44,6 +44,7 @@ #define ATOM_CMD_SETSCLK 0x0A #define ATOM_CMD_SETMCLK 0x0B #define ATOM_CMD_SETPCLK 0x0C +#define ATOM_CMD_SPDFANCNTL 0x39 #define ATOM_DATA_FWI_PTR 0xC #define ATOM_DATA_IIO_PTR 0x32 -- cgit v1.2.3 From fa9e855025b19e96e493ee00de7d933a9794f742 Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Sat, 31 Mar 2012 13:29:25 +0400 Subject: mm, drm/udl: fixup vma flags on mmap There should be VM_MIXEDMAP, not VM_PFNMAP, because udl_gem_fault() inserts pages via vm_insert_page(). Other drm/gem drivers already do this. Signed-off-by: Konstantin Khlebnikov Cc: Dave Airlie Cc: dri-devel@lists.freedesktop.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/udl/udl_drv.c | 2 +- drivers/gpu/drm/udl/udl_drv.h | 1 + drivers/gpu/drm/udl/udl_gem.c | 14 ++++++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/udl/udl_drv.c b/drivers/gpu/drm/udl/udl_drv.c index 5340c5f3987b..53673907a6a0 100644 --- a/drivers/gpu/drm/udl/udl_drv.c +++ b/drivers/gpu/drm/udl/udl_drv.c @@ -47,7 +47,7 @@ static struct vm_operations_struct udl_gem_vm_ops = { static const struct file_operations udl_driver_fops = { .owner = THIS_MODULE, .open = drm_open, - .mmap = drm_gem_mmap, + .mmap = udl_drm_gem_mmap, .poll = drm_poll, .read = drm_read, .unlocked_ioctl = drm_ioctl, diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h index 1612954a5bc4..96820d03a303 100644 --- a/drivers/gpu/drm/udl/udl_drv.h +++ b/drivers/gpu/drm/udl/udl_drv.h @@ -121,6 +121,7 @@ struct udl_gem_object *udl_gem_alloc_object(struct drm_device *dev, int udl_gem_vmap(struct udl_gem_object *obj); void udl_gem_vunmap(struct udl_gem_object *obj); +int udl_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma); int udl_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf); int udl_handle_damage(struct udl_framebuffer *fb, int x, int y, diff --git a/drivers/gpu/drm/udl/udl_gem.c b/drivers/gpu/drm/udl/udl_gem.c index 852642dc1187..92f19ef329b0 100644 --- a/drivers/gpu/drm/udl/udl_gem.c +++ b/drivers/gpu/drm/udl/udl_gem.c @@ -71,6 +71,20 @@ int udl_dumb_destroy(struct drm_file *file, struct drm_device *dev, return drm_gem_handle_delete(file, handle); } +int udl_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) +{ + int ret; + + ret = drm_gem_mmap(filp, vma); + if (ret) + return ret; + + vma->vm_flags &= ~VM_PFNMAP; + vma->vm_flags |= VM_MIXEDMAP; + + return ret; +} + int udl_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct udl_gem_object *obj = to_udl_bo(vma->vm_private_data); -- cgit v1.2.3 From e199fd422420d1620cf64fd9bdd4ff8bc255cc76 Mon Sep 17 00:00:00 2001 From: Michel Dänzer Date: Thu, 29 Mar 2012 16:47:43 +0200 Subject: drm/radeon: Don't dereference possibly-NULL pointer. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reported-by: Dan Carpenter Signed-off-by: Michel Dänzer Reviewed-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_object.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 6f70158d34e4..df6a4dbd93f8 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -241,7 +241,8 @@ int radeon_bo_pin_restricted(struct radeon_bo *bo, u32 domain, u64 max_offset, domain_start = bo->rdev->mc.vram_start; else domain_start = bo->rdev->mc.gtt_start; - WARN_ON_ONCE((*gpu_addr - domain_start) > max_offset); + WARN_ON_ONCE(max_offset < + (radeon_bo_gpu_offset(bo) - domain_start)); } return 0; -- cgit v1.2.3 From cc22a938fc1db0c8ef5e693a69b159c4b851dab3 Mon Sep 17 00:00:00 2001 From: Eugeni Dodonov Date: Thu, 29 Mar 2012 20:55:48 -0300 Subject: drm/i915: add Ivy Bridge GT2 Server entries This adds PCI ID for IVB GT2 server variant which we were missing. Signed-off-by: Eugeni Dodonov [danvet: fix up conflict because the patch has been diffed against next. tsk.] Signed-Off-by: Daniel Vetter --- drivers/char/agp/intel-agp.h | 1 + drivers/char/agp/intel-gtt.c | 2 ++ drivers/gpu/drm/i915/i915_drv.c | 1 + 3 files changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/char/agp/intel-agp.h b/drivers/char/agp/intel-agp.h index 5da67f165afa..7ea18a5fe71c 100644 --- a/drivers/char/agp/intel-agp.h +++ b/drivers/char/agp/intel-agp.h @@ -234,6 +234,7 @@ #define PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_GT2_IG 0x0166 #define PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_HB 0x0158 /* Server */ #define PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_GT1_IG 0x015A +#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_GT2_IG 0x016A int intel_gmch_probe(struct pci_dev *pdev, struct agp_bridge_data *bridge); diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 5cf47ac2d401..f493546b2d45 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -1459,6 +1459,8 @@ static const struct intel_gtt_driver_description { "Ivybridge", &sandybridge_gtt_driver }, { PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_GT1_IG, "Ivybridge", &sandybridge_gtt_driver }, + { PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_GT2_IG, + "Ivybridge", &sandybridge_gtt_driver }, { 0, NULL, NULL } }; diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index c7d689e4247c..77afd3176dd0 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -296,6 +296,7 @@ static const struct pci_device_id pciidlist[] = { /* aka */ INTEL_VGA_DEVICE(0x0152, &intel_ivybridge_d_info), /* GT1 desktop */ INTEL_VGA_DEVICE(0x0162, &intel_ivybridge_d_info), /* GT2 desktop */ INTEL_VGA_DEVICE(0x015a, &intel_ivybridge_d_info), /* GT1 server */ + INTEL_VGA_DEVICE(0x016a, &intel_ivybridge_d_info), /* GT2 server */ {0, 0, 0} }; -- cgit v1.2.3 From 650dc07ec3b0eba8ff21da706d2b1876ada59fc3 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 2 Apr 2012 10:08:35 +0200 Subject: drm/i915: disable ppgtt on snb when dmar is enabled Totally unexpected that this regressed. Luckily it sounds like we just need to have dmar disable on the igfx, not the entire system. At least that's what a few days of testing between Tony Vroon and me indicates. Reported-by: Tony Vroon Cc: Tony Vroon Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=43024 Acked-by: Chris Wilson Signed-Off-by: Daniel Vetter --- drivers/char/agp/intel-gtt.c | 1 - drivers/gpu/drm/i915/i915_dma.c | 17 ++++++++++++++++- drivers/gpu/drm/i915/i915_drv.c | 4 ++-- drivers/gpu/drm/i915/i915_drv.h | 2 +- include/drm/intel-gtt.h | 4 ++++ 5 files changed, 23 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index f493546b2d45..7f025fb620de 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -1190,7 +1190,6 @@ static inline int needs_idle_maps(void) { #ifdef CONFIG_INTEL_IOMMU const unsigned short gpu_devid = intel_private.pcidev->device; - extern int intel_iommu_gfx_mapped; /* Query intel_iommu to see if we need the workaround. Presumably that * was loaded first. diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 9341eb8ce93b..8a62285ddbd0 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1183,6 +1183,21 @@ static bool i915_switcheroo_can_switch(struct pci_dev *pdev) return can_switch; } +static bool +intel_enable_ppgtt(struct drm_device *dev) +{ + if (i915_enable_ppgtt >= 0) + return i915_enable_ppgtt; + +#ifdef CONFIG_INTEL_IOMMU + /* Disable ppgtt on SNB if VT-d is on. */ + if (INTEL_INFO(dev)->gen == 6 && intel_iommu_gfx_mapped) + return false; +#endif + + return true; +} + static int i915_load_gem_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -1197,7 +1212,7 @@ static int i915_load_gem_init(struct drm_device *dev) drm_mm_init(&dev_priv->mm.stolen, 0, prealloc_size); mutex_lock(&dev->struct_mutex); - if (i915_enable_ppgtt && HAS_ALIASING_PPGTT(dev)) { + if (intel_enable_ppgtt(dev) && HAS_ALIASING_PPGTT(dev)) { /* PPGTT pdes are stolen from global gtt ptes, so shrink the * aperture accordingly when using aliasing ppgtt. */ gtt_size -= I915_PPGTT_PD_ENTRIES*PAGE_SIZE; diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 77afd3176dd0..19d55bc54873 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -107,8 +107,8 @@ MODULE_PARM_DESC(enable_hangcheck, "WARNING: Disabling this can cause system wide hangs. " "(default: true)"); -bool i915_enable_ppgtt __read_mostly = 1; -module_param_named(i915_enable_ppgtt, i915_enable_ppgtt, bool, 0600); +int i915_enable_ppgtt __read_mostly = -1; +module_param_named(i915_enable_ppgtt, i915_enable_ppgtt, int, 0600); MODULE_PARM_DESC(i915_enable_ppgtt, "Enable PPGTT (default: true)"); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 2c192270cb0d..5fabc6c31fec 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1086,7 +1086,7 @@ extern int i915_vbt_sdvo_panel_type __read_mostly; extern int i915_enable_rc6 __read_mostly; extern int i915_enable_fbc __read_mostly; extern bool i915_enable_hangcheck __read_mostly; -extern bool i915_enable_ppgtt __read_mostly; +extern int i915_enable_ppgtt __read_mostly; extern int i915_suspend(struct drm_device *dev, pm_message_t state); extern int i915_resume(struct drm_device *dev); diff --git a/include/drm/intel-gtt.h b/include/drm/intel-gtt.h index 0a0001b9dc78..923afb5dcf0c 100644 --- a/include/drm/intel-gtt.h +++ b/include/drm/intel-gtt.h @@ -44,4 +44,8 @@ void intel_gtt_insert_pages(unsigned int first_entry, unsigned int num_entries, /* flag for GFDT type */ #define AGP_USER_CACHED_MEMORY_GFDT (1 << 3) +#ifdef CONFIG_INTEL_IOMMU +extern int intel_iommu_gfx_mapped; +#endif + #endif -- cgit v1.2.3 From e2e110d7596656e2badd21c48713bd01e1b40f44 Mon Sep 17 00:00:00 2001 From: Chris Metcalf Date: Fri, 30 Mar 2012 18:58:37 -0400 Subject: edac: say "TILEGx" not "TILEPro" for the tilegx edac driver This is just an aesthetic change but it was silly to say TILEPro when booting up on the tilegx architecture. Signed-off-by: Chris Metcalf --- drivers/edac/tile_edac.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/edac/tile_edac.c b/drivers/edac/tile_edac.c index 1d5cf06f6c6b..e99d00976189 100644 --- a/drivers/edac/tile_edac.c +++ b/drivers/edac/tile_edac.c @@ -145,7 +145,11 @@ static int __devinit tile_edac_mc_probe(struct platform_device *pdev) mci->edac_ctl_cap = EDAC_FLAG_SECDED; mci->mod_name = DRV_NAME; +#ifdef __tilegx__ + mci->ctl_name = "TILEGx_Memory_Controller"; +#else mci->ctl_name = "TILEPro_Memory_Controller"; +#endif mci->dev_name = dev_name(&pdev->dev); mci->edac_check = tile_edac_check; -- cgit v1.2.3 From 16418bb1da8a685e639c6c4f2d3096f762e8b0fb Mon Sep 17 00:00:00 2001 From: Chris Metcalf Date: Fri, 30 Mar 2012 19:03:04 -0400 Subject: tile-srom.c driver: minor code cleanup Signed-off-by: Chris Metcalf --- drivers/char/tile-srom.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tile-srom.c b/drivers/char/tile-srom.c index 4dc019408fac..3b22a606f79d 100644 --- a/drivers/char/tile-srom.c +++ b/drivers/char/tile-srom.c @@ -194,17 +194,17 @@ static ssize_t srom_read(struct file *filp, char __user *buf, hv_retval = _srom_read(srom->hv_devhdl, kernbuf, *f_pos, bytes_this_pass); - if (hv_retval > 0) { - if (copy_to_user(buf, kernbuf, hv_retval) != 0) { - retval = -EFAULT; - break; - } - } else if (hv_retval <= 0) { + if (hv_retval <= 0) { if (retval == 0) retval = hv_retval; break; } + if (copy_to_user(buf, kernbuf, hv_retval) != 0) { + retval = -EFAULT; + break; + } + retval += hv_retval; *f_pos += hv_retval; buf += hv_retval; -- cgit v1.2.3 From 92795672898d5ee1faa557c498c078123d20e827 Mon Sep 17 00:00:00 2001 From: Chris Metcalf Date: Fri, 30 Mar 2012 19:23:35 -0400 Subject: tilepro ethernet driver: fix a few minor issues This commit fixes a number of issues seen with the driver: - Improve handling of return credits to the hardware shim - Use skb_frag_size() appropriately - Fix driver so it works properly with netpoll for console over UDP Signed-off-by: Chris Metcalf --- drivers/net/ethernet/tile/tilepro.c | 75 ++++++++++++++++++++++++------------- 1 file changed, 50 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/tile/tilepro.c b/drivers/net/ethernet/tile/tilepro.c index 261356c2dc99..75e590545179 100644 --- a/drivers/net/ethernet/tile/tilepro.c +++ b/drivers/net/ethernet/tile/tilepro.c @@ -342,6 +342,21 @@ inline int __netio_fastio1(u32 fastio_index, u32 arg0) } +static void tile_net_return_credit(struct tile_net_cpu *info) +{ + struct tile_netio_queue *queue = &info->queue; + netio_queue_user_impl_t *qup = &queue->__user_part; + + /* Return four credits after every fourth packet. */ + if (--qup->__receive_credit_remaining == 0) { + u32 interval = qup->__receive_credit_interval; + qup->__receive_credit_remaining = interval; + __netio_fastio_return_credits(qup->__fastio_index, interval); + } +} + + + /* * Provide a linux buffer to LIPP. */ @@ -864,19 +879,11 @@ static bool tile_net_poll_aux(struct tile_net_cpu *info, int index) stats->rx_packets++; stats->rx_bytes += len; - - if (small) - info->num_needed_small_buffers++; - else - info->num_needed_large_buffers++; } - /* Return four credits after every fourth packet. */ - if (--qup->__receive_credit_remaining == 0) { - u32 interval = qup->__receive_credit_interval; - qup->__receive_credit_remaining = interval; - __netio_fastio_return_credits(qup->__fastio_index, interval); - } + /* ISSUE: It would be nice to defer this until the packet has */ + /* actually been processed. */ + tile_net_return_credit(info); /* Consume this packet. */ qup->__packet_receive_read = index2; @@ -1543,7 +1550,7 @@ static int tile_net_drain_lipp_buffers(struct tile_net_priv *priv) /* Drain all the LIPP buffers. */ while (true) { - int buffer; + unsigned int buffer; /* NOTE: This should never fail. */ if (hv_dev_pread(priv->hv_devhdl, 0, (HV_VirtAddr)&buffer, @@ -1707,7 +1714,7 @@ static unsigned int tile_net_tx_frags(lepp_frag_t *frags, if (!hash_default) { void *va = pfn_to_kaddr(pfn) + f->page_offset; BUG_ON(PageHighMem(skb_frag_page(f))); - finv_buffer_remote(va, f->size, 0); + finv_buffer_remote(va, skb_frag_size(f), 0); } cpa = ((phys_addr_t)pfn << PAGE_SHIFT) + f->page_offset; @@ -1735,8 +1742,8 @@ static unsigned int tile_net_tx_frags(lepp_frag_t *frags, * Sometimes, if "sendfile()" requires copying, we will be called with * "data" containing the header and payload, with "frags" being empty. * - * In theory, "sh->nr_frags" could be 3, but in practice, it seems - * that this will never actually happen. + * Sometimes, for example when using NFS over TCP, a single segment can + * span 3 fragments, which must be handled carefully in LEPP. * * See "emulate_large_send_offload()" for some reference code, which * does not handle checksumming. @@ -1844,10 +1851,8 @@ static int tile_net_tx_tso(struct sk_buff *skb, struct net_device *dev) spin_lock_irqsave(&priv->eq_lock, irqflags); - /* - * Handle completions if needed to make room. - * HACK: Spin until there is sufficient room. - */ + /* Handle completions if needed to make room. */ + /* NOTE: Return NETDEV_TX_BUSY if there is still no room. */ if (lepp_num_free_comp_slots(eq) == 0) { nolds = tile_net_lepp_grab_comps(eq, olds, wanted, 0); if (nolds == 0) { @@ -1861,6 +1866,7 @@ busy: cmd_tail = eq->cmd_tail; /* Prepare to advance, detecting full queue. */ + /* NOTE: Return NETDEV_TX_BUSY if the queue is full. */ cmd_next = cmd_tail + cmd_size; if (cmd_tail < cmd_head && cmd_next >= cmd_head) goto busy; @@ -2023,10 +2029,8 @@ static int tile_net_tx(struct sk_buff *skb, struct net_device *dev) spin_lock_irqsave(&priv->eq_lock, irqflags); - /* - * Handle completions if needed to make room. - * HACK: Spin until there is sufficient room. - */ + /* Handle completions if needed to make room. */ + /* NOTE: Return NETDEV_TX_BUSY if there is still no room. */ if (lepp_num_free_comp_slots(eq) == 0) { nolds = tile_net_lepp_grab_comps(eq, olds, wanted, 0); if (nolds == 0) { @@ -2040,6 +2044,7 @@ busy: cmd_tail = eq->cmd_tail; /* Copy the commands, or fail. */ + /* NOTE: Return NETDEV_TX_BUSY if the queue is full. */ for (i = 0; i < num_frags; i++) { /* Prepare to advance, detecting full queue. */ @@ -2261,6 +2266,23 @@ static int tile_net_get_mac(struct net_device *dev) return 0; } + +#ifdef CONFIG_NET_POLL_CONTROLLER +/* + * Polling 'interrupt' - used by things like netconsole to send skbs + * without having to re-enable interrupts. It's not called while + * the interrupt routine is executing. + */ +static void tile_net_netpoll(struct net_device *dev) +{ + struct tile_net_priv *priv = netdev_priv(dev); + disable_percpu_irq(priv->intr_id); + tile_net_handle_ingress_interrupt(priv->intr_id, dev); + enable_percpu_irq(priv->intr_id, 0); +} +#endif + + static const struct net_device_ops tile_net_ops = { .ndo_open = tile_net_open, .ndo_stop = tile_net_stop, @@ -2269,7 +2291,10 @@ static const struct net_device_ops tile_net_ops = { .ndo_get_stats = tile_net_get_stats, .ndo_change_mtu = tile_net_change_mtu, .ndo_tx_timeout = tile_net_tx_timeout, - .ndo_set_mac_address = tile_net_set_mac_address + .ndo_set_mac_address = tile_net_set_mac_address, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = tile_net_netpoll, +#endif }; @@ -2409,7 +2434,7 @@ static void tile_net_cleanup(void) */ static int tile_net_init_module(void) { - pr_info("Tilera IPP Net Driver\n"); + pr_info("Tilera Network Driver\n"); tile_net_devs[0] = tile_net_dev_init("xgbe0"); tile_net_devs[1] = tile_net_dev_init("xgbe1"); -- cgit v1.2.3 From 00a62d4bc9b9a0388abee5c5ea946b9631b149d5 Mon Sep 17 00:00:00 2001 From: Chris Metcalf Date: Mon, 2 Apr 2012 13:17:37 -0400 Subject: drivers/net/ethernet/tile: fix netdev_alloc_skb() bombing Commit dae2e9f430c46c29e3f771110094bd3da3625aa4 changed dev_alloc_skb() to netdev_alloc_skb(), adding a dev pointer, but erroneously used "->" instead of "." for a struct member when accessing the dev pointer. This change fixes the build breakage. Signed-off-by: Chris Metcalf --- drivers/net/ethernet/tile/tilepro.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/tile/tilepro.c b/drivers/net/ethernet/tile/tilepro.c index 75e590545179..3d501ec7fad7 100644 --- a/drivers/net/ethernet/tile/tilepro.c +++ b/drivers/net/ethernet/tile/tilepro.c @@ -448,7 +448,7 @@ static bool tile_net_provide_needed_buffer(struct tile_net_cpu *info, struct sk_buff **skb_ptr; /* Request 96 extra bytes for alignment purposes. */ - skb = netdev_alloc_skb(info->napi->dev, len + padding); + skb = netdev_alloc_skb(info->napi.dev, len + padding); if (skb == NULL) return false; -- cgit v1.2.3 From 085f1afc56619bda424941412fdeaff1e32c21dc Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Mon, 2 Apr 2012 09:01:40 +0000 Subject: tg3: Fix 5717 serdes powerdown problem If port 0 of a 5717 serdes device powers down, it hides the phy from port 1. This patch works around the problem by keeping port 0's phy powered up. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/tg3.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 7b71387cf93c..d2ff8ee39e84 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -2779,7 +2779,9 @@ static void tg3_power_down_phy(struct tg3 *tp, bool do_low_power) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 || (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 && - (tp->phy_flags & TG3_PHYFLG_MII_SERDES))) + (tp->phy_flags & TG3_PHYFLG_MII_SERDES)) || + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 && + !tp->pci_fn)) return; if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5784_AX || -- cgit v1.2.3 From 2240eb4ae3dc4acff20d1a8947c441c451513e37 Mon Sep 17 00:00:00 2001 From: Lino Sanfilippo Date: Fri, 30 Mar 2012 07:28:59 +0000 Subject: sky2: dont overwrite settings for PHY Quick link This patch corrects a bug in function sky2_open() of the Marvell Yukon 2 driver in which the settings for PHY quick link are overwritten. Signed-off-by: Lino Sanfilippo Acked-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/sky2.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c index 423a1a2a702e..b806d9b4defb 100644 --- a/drivers/net/ethernet/marvell/sky2.c +++ b/drivers/net/ethernet/marvell/sky2.c @@ -1767,13 +1767,14 @@ static int sky2_open(struct net_device *dev) sky2_hw_up(sky2); + /* Enable interrupts from phy/mac for port */ + imask = sky2_read32(hw, B0_IMSK); + if (hw->chip_id == CHIP_ID_YUKON_OPT || hw->chip_id == CHIP_ID_YUKON_PRM || hw->chip_id == CHIP_ID_YUKON_OP_2) imask |= Y2_IS_PHY_QLNK; /* enable PHY Quick Link */ - /* Enable interrupts from phy/mac for port */ - imask = sky2_read32(hw, B0_IMSK); imask |= portirq_msk[port]; sky2_write32(hw, B0_IMSK, imask); sky2_read32(hw, B0_IMSK); -- cgit v1.2.3 From f283d22713b0bdc147097c92c9b45855339cf1c8 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Sun, 1 Apr 2012 20:19:30 +1000 Subject: APM: fix deadlock in APM_IOC_SUSPEND ioctl I found the Xorg server on my ARM device stuck in the 'msleep()' loop in apm_ioctl. I suspect it had attempted suspend immediately after resuming and lost a race. During that msleep(10);, a new suspend cycle must have started and changed ->suspend_state to SUSPEND_PENDING, so it was never seen to be SUSPEND_DONE and the loop could never exited. It would have moved on to SUSPEND_ACKTO but never been able to reach SUSPEND_DONE. So change the loop to only run while SUSPEND_ACKED rather than until SUSPEND_DONE. This is much safer. Signed-off-by: NeilBrown Signed-off-by: Jiri Kosina --- drivers/char/apm-emulation.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/apm-emulation.c b/drivers/char/apm-emulation.c index f4837a893dfa..6005c5c03f2a 100644 --- a/drivers/char/apm-emulation.c +++ b/drivers/char/apm-emulation.c @@ -302,7 +302,7 @@ apm_ioctl(struct file *filp, u_int cmd, u_long arg) * anything critical, chill a bit on each iteration. */ while (wait_event_freezable(apm_suspend_waitqueue, - as->suspend_state == SUSPEND_DONE)) + as->suspend_state != SUSPEND_ACKED)) msleep(10); break; case SUSPEND_ACKTO: -- cgit v1.2.3 From beca98c93dc8d838c3656bc62fd49b45622ef788 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Mon, 2 Apr 2012 18:17:17 -0400 Subject: ARM: fix lcd power build failure in collie_defconfig Commit 086ada54abaa4316e8603f02410fe8ebc9ba2de1 "FB: sa1100: remove global sa1100fb_.*_power function pointers" got rid of all instances but one in locomolcd.c -- which was conditional on CONFIG_SA1100_COLLIE. The associated .power field which replaces the global is populated in mach-sa1100/collie.c so move the assignment there, but make it conditional on the locomolcd support, so use CONFIG_BACKLIGHT_LOCOMO in that file. Cc: arm@kernel.org Acked-by: Russell King Signed-off-by: Paul Gortmaker Signed-off-by: Olof Johansson --- arch/arm/mach-sa1100/collie.c | 4 ++++ arch/arm/mach-sa1100/include/mach/collie.h | 3 ++- drivers/video/backlight/locomolcd.c | 9 +-------- 3 files changed, 7 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c index 48885b7efd6b..c7f418b0cde9 100644 --- a/arch/arm/mach-sa1100/collie.c +++ b/arch/arm/mach-sa1100/collie.c @@ -313,6 +313,10 @@ static struct sa1100fb_mach_info collie_lcd_info = { .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2), + +#ifdef CONFIG_BACKLIGHT_LOCOMO + .lcd_power = locomolcd_power +#endif }; static void __init collie_init(void) diff --git a/arch/arm/mach-sa1100/include/mach/collie.h b/arch/arm/mach-sa1100/include/mach/collie.h index 52acda7061b7..f33679d2d3ee 100644 --- a/arch/arm/mach-sa1100/include/mach/collie.h +++ b/arch/arm/mach-sa1100/include/mach/collie.h @@ -1,7 +1,7 @@ /* * arch/arm/mach-sa1100/include/mach/collie.h * - * This file contains the hardware specific definitions for Assabet + * This file contains the hardware specific definitions for Collie * Only include this file from SA1100-specific files. * * ChangeLog: @@ -13,6 +13,7 @@ #ifndef __ASM_ARCH_COLLIE_H #define __ASM_ARCH_COLLIE_H +extern void locomolcd_power(int on); #define COLLIE_SCOOP_GPIO_BASE (GPIO_MAX + 1) #define COLLIE_GPIO_CHARGE_ON (COLLIE_SCOOP_GPIO_BASE + 0) diff --git a/drivers/video/backlight/locomolcd.c b/drivers/video/backlight/locomolcd.c index be20b5cbe26c..3a6d5419e3e3 100644 --- a/drivers/video/backlight/locomolcd.c +++ b/drivers/video/backlight/locomolcd.c @@ -229,14 +229,7 @@ static struct locomo_driver poodle_lcd_driver = { static int __init locomolcd_init(void) { - int ret = locomo_driver_register(&poodle_lcd_driver); - if (ret) - return ret; - -#ifdef CONFIG_SA1100_COLLIE - sa1100fb_lcd_power = locomolcd_power; -#endif - return 0; + return locomo_driver_register(&poodle_lcd_driver); } static void __exit locomolcd_exit(void) -- cgit v1.2.3 From 18b9837ea0dc3cf844c6c4196871ce91d047bddb Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Sun, 1 Apr 2012 23:48:38 +1000 Subject: md/raid5: fix handling of bad blocks during recovery. 1/ We can only treat a known-bad-block like a read-error if we have the data that belongs in that block. So fix that test. 2/ If we cannot recovery a stripe due to insufficient data, don't tell "md_done_sync" that the sync failed unless we really did fail something. If we successfully record bad blocks, that is success. Reported-by: "majianpeng" Signed-off-by: NeilBrown --- drivers/md/raid5.c | 55 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 23ac880bba9a..9799be80bf31 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -2471,39 +2471,41 @@ handle_failed_sync(struct r5conf *conf, struct stripe_head *sh, int abort = 0; int i; - md_done_sync(conf->mddev, STRIPE_SECTORS, 0); clear_bit(STRIPE_SYNCING, &sh->state); s->syncing = 0; s->replacing = 0; /* There is nothing more to do for sync/check/repair. + * Don't even need to abort as that is handled elsewhere + * if needed, and not always wanted e.g. if there is a known + * bad block here. * For recover/replace we need to record a bad block on all * non-sync devices, or abort the recovery */ - if (!test_bit(MD_RECOVERY_RECOVER, &conf->mddev->recovery)) - return; - /* During recovery devices cannot be removed, so locking and - * refcounting of rdevs is not needed - */ - for (i = 0; i < conf->raid_disks; i++) { - struct md_rdev *rdev = conf->disks[i].rdev; - if (rdev - && !test_bit(Faulty, &rdev->flags) - && !test_bit(In_sync, &rdev->flags) - && !rdev_set_badblocks(rdev, sh->sector, - STRIPE_SECTORS, 0)) - abort = 1; - rdev = conf->disks[i].replacement; - if (rdev - && !test_bit(Faulty, &rdev->flags) - && !test_bit(In_sync, &rdev->flags) - && !rdev_set_badblocks(rdev, sh->sector, - STRIPE_SECTORS, 0)) - abort = 1; - } - if (abort) { - conf->recovery_disabled = conf->mddev->recovery_disabled; - set_bit(MD_RECOVERY_INTR, &conf->mddev->recovery); + if (test_bit(MD_RECOVERY_RECOVER, &conf->mddev->recovery)) { + /* During recovery devices cannot be removed, so + * locking and refcounting of rdevs is not needed + */ + for (i = 0; i < conf->raid_disks; i++) { + struct md_rdev *rdev = conf->disks[i].rdev; + if (rdev + && !test_bit(Faulty, &rdev->flags) + && !test_bit(In_sync, &rdev->flags) + && !rdev_set_badblocks(rdev, sh->sector, + STRIPE_SECTORS, 0)) + abort = 1; + rdev = conf->disks[i].replacement; + if (rdev + && !test_bit(Faulty, &rdev->flags) + && !test_bit(In_sync, &rdev->flags) + && !rdev_set_badblocks(rdev, sh->sector, + STRIPE_SECTORS, 0)) + abort = 1; + } + if (abort) + conf->recovery_disabled = + conf->mddev->recovery_disabled; } + md_done_sync(conf->mddev, STRIPE_SECTORS, !abort); } static int want_replace(struct stripe_head *sh, int disk_idx) @@ -3203,7 +3205,8 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s) /* Not in-sync */; else if (is_bad) { /* also not in-sync */ - if (!test_bit(WriteErrorSeen, &rdev->flags)) { + if (!test_bit(WriteErrorSeen, &rdev->flags) && + test_bit(R5_UPTODATE, &dev->flags)) { /* treat as in-sync, but with a read error * which we can now try to correct */ -- cgit v1.2.3 From 24b961f811a3e790a9b93604d2594bfb6cce4fa4 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Sun, 1 Apr 2012 23:48:38 +1000 Subject: md: Avoid OOPS when reshaping raid1 to raid0 raid1 arrays do not have the notion of chunk size. Calculate the largest chunk sector size we can use to avoid a divide by zero OOPS when aligning the size of the new array to the chunk size. Signed-off-by: Jes Sorensen Signed-off-by: NeilBrown --- drivers/md/raid0.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index c9809453a346..de63a1fc3737 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -632,6 +632,7 @@ static void *raid0_takeover_raid10(struct mddev *mddev) static void *raid0_takeover_raid1(struct mddev *mddev) { struct r0conf *priv_conf; + int chunksect; /* Check layout: * - (N - 1) mirror drives must be already faulty @@ -642,10 +643,25 @@ static void *raid0_takeover_raid1(struct mddev *mddev) return ERR_PTR(-EINVAL); } + /* + * a raid1 doesn't have the notion of chunk size, so + * figure out the largest suitable size we can use. + */ + chunksect = 64 * 2; /* 64K by default */ + + /* The array must be an exact multiple of chunksize */ + while (chunksect && (mddev->array_sectors & (chunksect - 1))) + chunksect >>= 1; + + if ((chunksect << 9) < PAGE_SIZE) + /* array size does not allow a suitable chunk size */ + return ERR_PTR(-EINVAL); + /* Set new parameters */ mddev->new_level = 0; mddev->new_layout = 0; - mddev->new_chunk_sectors = 128; /* by default set chunk size to 64k */ + mddev->new_chunk_sectors = chunksect; + mddev->chunk_sectors = chunksect; mddev->delta_disks = 1 - mddev->raid_disks; mddev->raid_disks = 1; /* make sure it will be not marked as dirty */ -- cgit v1.2.3 From a42f9d83b5c05dc6e678a1f0cd9767502c2c58de Mon Sep 17 00:00:00 2001 From: majianpeng Date: Mon, 2 Apr 2012 01:04:19 +1000 Subject: md/raid1:Remove unnecessary rcu_dereference(conf->mirrors[i].rdev). Because rde->nr_pending > 0,so can not remove this disk. And in any case, we aren't holding rcu_read_lock() Signed-off-by: majianpeng Signed-off-by: NeilBrown --- drivers/md/raid1.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 242440831b23..8c420f178603 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -2386,8 +2386,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, int *skipp int ok = 1; for (i = 0 ; i < conf->raid_disks * 2 ; i++) if (r1_bio->bios[i]->bi_end_io == end_sync_write) { - struct md_rdev *rdev = - rcu_dereference(conf->mirrors[i].rdev); + struct md_rdev *rdev = conf->mirrors[i].rdev; ok = rdev_set_badblocks(rdev, sector_nr, min_bad, 0 ) && ok; -- cgit v1.2.3 From c6d2e084c7411f61f2b446d94989e5aaf9879b0f Mon Sep 17 00:00:00 2001 From: majianpeng Date: Mon, 2 Apr 2012 01:16:59 +1000 Subject: md/raid5: Fix a bug about judging if the operation is syncing or replacing When create a raid5 using assume-clean and echo check or repair to sync_action.Then component disks did not operated IO but the raid check/resync faster than normal. Because the judgement in function analyse_stripe(): if (do_recovery || sh->sector >= conf->mddev->recovery_cp) s->syncing = 1; else s->replacing = 1; When check or repair,the recovery_cp == MaxSectore,so syncing equal zero not one. This bug was introduced by commit 9a3e1101b827 md/raid5: detect and handle replacements during recovery. so this patch is suitable for 3.3-stable. Cc: stable@vger.kernel.org Signed-off-by: majianpeng Signed-off-by: NeilBrown --- drivers/md/raid5.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 9799be80bf31..f351422938e0 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -3279,12 +3279,14 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s) /* If there is a failed device being replaced, * we must be recovering. * else if we are after recovery_cp, we must be syncing + * else if MD_RECOVERY_REQUESTED is set, we also are syncing. * else we can only be replacing * sync and recovery both need to read all devices, and so * use the same flag. */ if (do_recovery || - sh->sector >= conf->mddev->recovery_cp) + sh->sector >= conf->mddev->recovery_cp || + test_bit(MD_RECOVERY_REQUESTED, &(conf->mddev->recovery))) s->syncing = 1; else s->replacing = 1; -- cgit v1.2.3 From 5020ad7d143ccfcf8149974096220d59e5572120 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 2 Apr 2012 01:39:05 +1000 Subject: md/raid1,raid10: don't compare excess byte during consistency check. When comparing two pages read from different legs of a mirror, only compare the bytes that were read, not the whole page. In most cases we read a whole page, but in some cases with bad blocks or odd sizes devices we might read fewer than that. This bug has been present "forever" but at worst it might cause a report of two many mismatches and generate a little bit extra resync IO, so there is no need to back-port to -stable kernels. Reported-by: majianpeng Signed-off-by: NeilBrown --- drivers/md/raid1.c | 2 +- drivers/md/raid10.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 8c420f178603..d35e4c991e38 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1738,7 +1738,7 @@ static int process_checks(struct r1bio *r1_bio) s = sbio->bi_io_vec[j].bv_page; if (memcmp(page_address(p), page_address(s), - PAGE_SIZE)) + sbio->bi_io_vec[j].bv_len)) break; } } else diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 3540316886f2..fff782189e48 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1821,7 +1821,7 @@ static void sync_request_write(struct mddev *mddev, struct r10bio *r10_bio) for (j = 0; j < vcnt; j++) if (memcmp(page_address(fbio->bi_io_vec[j].bv_page), page_address(tbio->bi_io_vec[j].bv_page), - PAGE_SIZE)) + fbio->bi_io_vec[j].bv_len)) break; if (j == vcnt) continue; -- cgit v1.2.3 From e02f14cd48a5da0ebaecf88c93dbd54a81e0dead Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 2 Apr 2012 23:33:03 +0200 Subject: drm/i915: don't leak struct_mutex lock on ppgtt init failures Reported-by: Konstantin Belousov Reviewed-by: Chris Wilson Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 8a62285ddbd0..785f67f963ef 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1222,8 +1222,10 @@ static int i915_load_gem_init(struct drm_device *dev) i915_gem_do_init(dev, 0, mappable_size, gtt_size); ret = i915_gem_init_aliasing_ppgtt(dev); - if (ret) + if (ret) { + mutex_unlock(&dev->struct_mutex); return ret; + } } else { /* Let GEM Manage all of the aperture. * -- cgit v1.2.3 From 927a2f119e8235238a2fc64871051b16c9bdae75 Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Fri, 23 Mar 2012 08:52:58 -0400 Subject: drm/i915: Add lock on drm_helper_resume_force_mode i915_drm_thaw was not locking the mode_config lock when calling drm_helper_resume_force_mode. When there were multiple wake sources, this caused FDI training failure on SNB which in turn corrupted the display. Signed-off-by: Sean Paul Reviewed-by: Chris Wilson Cc: stable@kernel.org Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 19d55bc54873..dfa55e7478fb 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -538,7 +538,9 @@ static int i915_drm_thaw(struct drm_device *dev) drm_irq_install(dev); /* Resume the modeset for every activated CRTC */ + mutex_lock(&dev->mode_config.mutex); drm_helper_resume_force_mode(dev); + mutex_unlock(&dev->mode_config.mutex); if (IS_IRONLAKE_M(dev)) ironlake_enable_rc6(dev); -- cgit v1.2.3 From 97effadb65ed08809e1720c8d3ee80b73a93665c Mon Sep 17 00:00:00 2001 From: Anisse Astier Date: Wed, 7 Mar 2012 18:36:35 +0100 Subject: drm/i915: no-lvds quirk on MSI DC500 This hardware doesn't have an LVDS, it's a desktop box. Fix incorrect LVDS detection. Cc: stable@kernel.org Signed-off-by: Anisse Astier Acked-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lvds.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index c5c0973af8a1..95db2e988227 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -755,6 +755,14 @@ static const struct dmi_system_id intel_no_lvds[] = { DMI_MATCH(DMI_BOARD_NAME, "hp st5747"), }, }, + { + .callback = intel_no_lvds_dmi_callback, + .ident = "MSI Wind Box DC500", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "MICRO-STAR INTERNATIONAL CO., LTD"), + DMI_MATCH(DMI_BOARD_NAME, "MS-7469"), + }, + }, { } /* terminating entry */ }; -- cgit v1.2.3 From b4db1e35ac59c144965f517bc575a0d75b60b03f Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 20 Mar 2012 10:59:09 -0700 Subject: drm/i915: treat src w & h as fixed point in sprite handling code This was missed when we converted the source values to 16.16 fixed point. Cc: stable@vger.kernel.org Signed-off-by: Jesse Barnes Tested-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_sprite.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 7aa0450399a1..a464771a7240 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -411,6 +411,9 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, old_obj = intel_plane->obj; + src_w = src_w >> 16; + src_h = src_h >> 16; + /* Pipe must be running... */ if (!(I915_READ(PIPECONF(pipe)) & PIPECONF_ENABLE)) return -EINVAL; -- cgit v1.2.3 From 62fb376e214d3c1bfdf6fbb77dac162f6da04d7e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 26 Mar 2012 21:15:53 +0100 Subject: drm: Validate requested virtual size against allocated fb size mplayer -vo fbdev tries to create a screen that is twice as tall as the allocated framebuffer for "doublebuffering". By default, and all in-tree users, only sufficient memory is allocated and mapped to satisfy the smallest framebuffer and the virtual size is no larger than the actual. For these users, we should therefore reject any userspace request to create a screen that requires a buffer larger than the framebuffer originally allocated. References: https://bugs.freedesktop.org/show_bug.cgi?id=38138 Signed-off-by: Chris Wilson Reviewed-by: Daniel Vetter Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_fb_helper.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 7740dd26f007..a0d6e894d97c 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -559,9 +559,13 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var, return -EINVAL; /* Need to resize the fb object !!! */ - if (var->bits_per_pixel > fb->bits_per_pixel || var->xres > fb->width || var->yres > fb->height) { + if (var->bits_per_pixel > fb->bits_per_pixel || + var->xres > fb->width || var->yres > fb->height || + var->xres_virtual > fb->width || var->yres_virtual > fb->height) { DRM_DEBUG("fb userspace requested width/height/bpp is greater than current fb " - "object %dx%d-%d > %dx%d-%d\n", var->xres, var->yres, var->bits_per_pixel, + "request %dx%d-%d (virtual %dx%d) > %dx%d-%d\n", + var->xres, var->yres, var->bits_per_pixel, + var->xres_virtual, var->yres_virtual, fb->width, fb->height, fb->bits_per_pixel); return -EINVAL; } -- cgit v1.2.3 From e466de05194b666114713b753e2f4be1d4200140 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 3 Apr 2012 13:08:53 +0100 Subject: regmap: Export regcache_sync_region() regcache_sync_region() isn't going to be useful to most drivers if we don't export it since otherwise they can't use it when built modular. Signed-off-by: Mark Brown --- drivers/base/regmap/regcache.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index 87f54dbf601b..74b69095def6 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c @@ -346,6 +346,7 @@ out: return ret; } +EXPORT_SYMBOL_GPL(regcache_sync_region); /** * regcache_cache_only: Put a register map into cache only mode -- cgit v1.2.3 From e675f0cc9a872fd152edc0c77acfed19bf28b81e Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 26 Mar 2012 00:03:42 +0000 Subject: ppp: Don't stop and restart queue on every TX packet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For every transmitted packet, ppp_start_xmit() will stop the netdev queue and then, if appropriate, restart it. This causes the TX softirq to run, entirely gratuitously. This is "only" a waste of CPU time in the normal case, but it's actively harmful when the PPP device is a TEQL slave — the wakeup will cause the offending device to receive the next TX packet from the TEQL queue, when it *should* have gone to the next slave in the list. We end up seeing large bursts of packets on just *one* slave device, rather than using the full available bandwidth over all slaves. This patch fixes the problem by *not* unconditionally stopping the queue in ppp_start_xmit(). It adds a return value from ppp_xmit_process() which indicates whether the queue should be stopped or not. It *doesn't* remove the call to netif_wake_queue() from ppp_xmit_process(), because other code paths (especially from ppp_output_wakeup()) need it there and it's messy to push it out to the other callers to do it based on the return value. So we leave it in place — it's a no-op in the case where the queue wasn't stopped, so it's harmless in the TX path. Signed-off-by: David Woodhouse Signed-off-by: David S. Miller --- drivers/net/ppp/ppp_generic.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index 159da2905fe9..33f8c51968b6 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c @@ -235,7 +235,7 @@ struct ppp_net { /* Prototypes. */ static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf, struct file *file, unsigned int cmd, unsigned long arg); -static void ppp_xmit_process(struct ppp *ppp); +static int ppp_xmit_process(struct ppp *ppp); static void ppp_send_frame(struct ppp *ppp, struct sk_buff *skb); static void ppp_push(struct ppp *ppp); static void ppp_channel_push(struct channel *pch); @@ -968,9 +968,9 @@ ppp_start_xmit(struct sk_buff *skb, struct net_device *dev) proto = npindex_to_proto[npi]; put_unaligned_be16(proto, pp); - netif_stop_queue(dev); skb_queue_tail(&ppp->file.xq, skb); - ppp_xmit_process(ppp); + if (!ppp_xmit_process(ppp)) + netif_stop_queue(dev); return NETDEV_TX_OK; outf: @@ -1048,10 +1048,11 @@ static void ppp_setup(struct net_device *dev) * Called to do any work queued up on the transmit side * that can now be done. */ -static void +static int ppp_xmit_process(struct ppp *ppp) { struct sk_buff *skb; + int ret = 0; ppp_xmit_lock(ppp); if (!ppp->closing) { @@ -1061,10 +1062,13 @@ ppp_xmit_process(struct ppp *ppp) ppp_send_frame(ppp, skb); /* If there's no work left to do, tell the core net code that we can accept some more. */ - if (!ppp->xmit_pending && !skb_peek(&ppp->file.xq)) + if (!ppp->xmit_pending && !skb_peek(&ppp->file.xq)) { netif_wake_queue(ppp->dev); + ret = 1; + } } ppp_xmit_unlock(ppp); + return ret; } static inline struct sk_buff * -- cgit v1.2.3 From aacc1bea190d731755a65cb8ec31dd756f4e263e Mon Sep 17 00:00:00 2001 From: "Multanen, Eric W" Date: Wed, 28 Mar 2012 07:49:09 +0000 Subject: ixgbe: driver fix for link flap Fix up code so that changes in DCB settings are detected only when ixgbe_dcbnl_set_all is called. Previously, a series of 'change' commands followed by a call to ixgbe_dcbnl_set_all() would always be handled as a HW change - even if the net change was zero. This patch checks for this case of no actual change and skips going through the HW set process. Without this fix, the link could reset and result in a link flap. The core change in this patch is to check for changes in the ixgbe_copy_dcb_cfg() routine - and return a bitmask of detected changes. The other places where changes were detected previously can be removed. Signed-off-by: Eric Multanen Tested-by: Ross Brattain Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c | 164 ++++++++++++------------ 1 file changed, 80 insertions(+), 84 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c index dde65f951400..652e4b09546d 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c @@ -44,62 +44,94 @@ #define DCB_NO_HW_CHG 1 /* DCB configuration did not change */ #define DCB_HW_CHG 2 /* DCB configuration changed, no reset */ -int ixgbe_copy_dcb_cfg(struct ixgbe_dcb_config *src_dcb_cfg, - struct ixgbe_dcb_config *dst_dcb_cfg, int tc_max) +int ixgbe_copy_dcb_cfg(struct ixgbe_dcb_config *scfg, + struct ixgbe_dcb_config *dcfg, int tc_max) { - struct tc_configuration *src_tc_cfg = NULL; - struct tc_configuration *dst_tc_cfg = NULL; - int i; + struct tc_configuration *src = NULL; + struct tc_configuration *dst = NULL; + int i, j; + int tx = DCB_TX_CONFIG; + int rx = DCB_RX_CONFIG; + int changes = 0; - if (!src_dcb_cfg || !dst_dcb_cfg) - return -EINVAL; + if (!scfg || !dcfg) + return changes; for (i = DCB_PG_ATTR_TC_0; i < tc_max + DCB_PG_ATTR_TC_0; i++) { - src_tc_cfg = &src_dcb_cfg->tc_config[i - DCB_PG_ATTR_TC_0]; - dst_tc_cfg = &dst_dcb_cfg->tc_config[i - DCB_PG_ATTR_TC_0]; + src = &scfg->tc_config[i - DCB_PG_ATTR_TC_0]; + dst = &dcfg->tc_config[i - DCB_PG_ATTR_TC_0]; - dst_tc_cfg->path[DCB_TX_CONFIG].prio_type = - src_tc_cfg->path[DCB_TX_CONFIG].prio_type; + if (dst->path[tx].prio_type != src->path[tx].prio_type) { + dst->path[tx].prio_type = src->path[tx].prio_type; + changes |= BIT_PG_TX; + } - dst_tc_cfg->path[DCB_TX_CONFIG].bwg_id = - src_tc_cfg->path[DCB_TX_CONFIG].bwg_id; + if (dst->path[tx].bwg_id != src->path[tx].bwg_id) { + dst->path[tx].bwg_id = src->path[tx].bwg_id; + changes |= BIT_PG_TX; + } - dst_tc_cfg->path[DCB_TX_CONFIG].bwg_percent = - src_tc_cfg->path[DCB_TX_CONFIG].bwg_percent; + if (dst->path[tx].bwg_percent != src->path[tx].bwg_percent) { + dst->path[tx].bwg_percent = src->path[tx].bwg_percent; + changes |= BIT_PG_TX; + } - dst_tc_cfg->path[DCB_TX_CONFIG].up_to_tc_bitmap = - src_tc_cfg->path[DCB_TX_CONFIG].up_to_tc_bitmap; + if (dst->path[tx].up_to_tc_bitmap != + src->path[tx].up_to_tc_bitmap) { + dst->path[tx].up_to_tc_bitmap = + src->path[tx].up_to_tc_bitmap; + changes |= (BIT_PG_TX | BIT_PFC | BIT_APP_UPCHG); + } - dst_tc_cfg->path[DCB_RX_CONFIG].prio_type = - src_tc_cfg->path[DCB_RX_CONFIG].prio_type; + if (dst->path[rx].prio_type != src->path[rx].prio_type) { + dst->path[rx].prio_type = src->path[rx].prio_type; + changes |= BIT_PG_RX; + } - dst_tc_cfg->path[DCB_RX_CONFIG].bwg_id = - src_tc_cfg->path[DCB_RX_CONFIG].bwg_id; + if (dst->path[rx].bwg_id != src->path[rx].bwg_id) { + dst->path[rx].bwg_id = src->path[rx].bwg_id; + changes |= BIT_PG_RX; + } - dst_tc_cfg->path[DCB_RX_CONFIG].bwg_percent = - src_tc_cfg->path[DCB_RX_CONFIG].bwg_percent; + if (dst->path[rx].bwg_percent != src->path[rx].bwg_percent) { + dst->path[rx].bwg_percent = src->path[rx].bwg_percent; + changes |= BIT_PG_RX; + } - dst_tc_cfg->path[DCB_RX_CONFIG].up_to_tc_bitmap = - src_tc_cfg->path[DCB_RX_CONFIG].up_to_tc_bitmap; + if (dst->path[rx].up_to_tc_bitmap != + src->path[rx].up_to_tc_bitmap) { + dst->path[rx].up_to_tc_bitmap = + src->path[rx].up_to_tc_bitmap; + changes |= (BIT_PG_RX | BIT_PFC | BIT_APP_UPCHG); + } } for (i = DCB_PG_ATTR_BW_ID_0; i < DCB_PG_ATTR_BW_ID_MAX; i++) { - dst_dcb_cfg->bw_percentage[DCB_TX_CONFIG] - [i-DCB_PG_ATTR_BW_ID_0] = src_dcb_cfg->bw_percentage - [DCB_TX_CONFIG][i-DCB_PG_ATTR_BW_ID_0]; - dst_dcb_cfg->bw_percentage[DCB_RX_CONFIG] - [i-DCB_PG_ATTR_BW_ID_0] = src_dcb_cfg->bw_percentage - [DCB_RX_CONFIG][i-DCB_PG_ATTR_BW_ID_0]; + j = i - DCB_PG_ATTR_BW_ID_0; + if (dcfg->bw_percentage[tx][j] != scfg->bw_percentage[tx][j]) { + dcfg->bw_percentage[tx][j] = scfg->bw_percentage[tx][j]; + changes |= BIT_PG_TX; + } + if (dcfg->bw_percentage[rx][j] != scfg->bw_percentage[rx][j]) { + dcfg->bw_percentage[rx][j] = scfg->bw_percentage[rx][j]; + changes |= BIT_PG_RX; + } } for (i = DCB_PFC_UP_ATTR_0; i < DCB_PFC_UP_ATTR_MAX; i++) { - dst_dcb_cfg->tc_config[i - DCB_PFC_UP_ATTR_0].dcb_pfc = - src_dcb_cfg->tc_config[i - DCB_PFC_UP_ATTR_0].dcb_pfc; + j = i - DCB_PFC_UP_ATTR_0; + if (dcfg->tc_config[j].dcb_pfc != scfg->tc_config[j].dcb_pfc) { + dcfg->tc_config[j].dcb_pfc = scfg->tc_config[j].dcb_pfc; + changes |= BIT_PFC; + } } - dst_dcb_cfg->pfc_mode_enable = src_dcb_cfg->pfc_mode_enable; + if (dcfg->pfc_mode_enable != scfg->pfc_mode_enable) { + dcfg->pfc_mode_enable = scfg->pfc_mode_enable; + changes |= BIT_PFC; + } - return 0; + return changes; } static u8 ixgbe_dcbnl_get_state(struct net_device *netdev) @@ -179,20 +211,6 @@ static void ixgbe_dcbnl_set_pg_tc_cfg_tx(struct net_device *netdev, int tc, if (up_map != DCB_ATTR_VALUE_UNDEFINED) adapter->temp_dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap = up_map; - - if ((adapter->temp_dcb_cfg.tc_config[tc].path[0].prio_type != - adapter->dcb_cfg.tc_config[tc].path[0].prio_type) || - (adapter->temp_dcb_cfg.tc_config[tc].path[0].bwg_id != - adapter->dcb_cfg.tc_config[tc].path[0].bwg_id) || - (adapter->temp_dcb_cfg.tc_config[tc].path[0].bwg_percent != - adapter->dcb_cfg.tc_config[tc].path[0].bwg_percent) || - (adapter->temp_dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap != - adapter->dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap)) - adapter->dcb_set_bitmap |= BIT_PG_TX; - - if (adapter->temp_dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap != - adapter->dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap) - adapter->dcb_set_bitmap |= BIT_PFC | BIT_APP_UPCHG; } static void ixgbe_dcbnl_set_pg_bwg_cfg_tx(struct net_device *netdev, int bwg_id, @@ -201,10 +219,6 @@ static void ixgbe_dcbnl_set_pg_bwg_cfg_tx(struct net_device *netdev, int bwg_id, struct ixgbe_adapter *adapter = netdev_priv(netdev); adapter->temp_dcb_cfg.bw_percentage[0][bwg_id] = bw_pct; - - if (adapter->temp_dcb_cfg.bw_percentage[0][bwg_id] != - adapter->dcb_cfg.bw_percentage[0][bwg_id]) - adapter->dcb_set_bitmap |= BIT_PG_TX; } static void ixgbe_dcbnl_set_pg_tc_cfg_rx(struct net_device *netdev, int tc, @@ -223,20 +237,6 @@ static void ixgbe_dcbnl_set_pg_tc_cfg_rx(struct net_device *netdev, int tc, if (up_map != DCB_ATTR_VALUE_UNDEFINED) adapter->temp_dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap = up_map; - - if ((adapter->temp_dcb_cfg.tc_config[tc].path[1].prio_type != - adapter->dcb_cfg.tc_config[tc].path[1].prio_type) || - (adapter->temp_dcb_cfg.tc_config[tc].path[1].bwg_id != - adapter->dcb_cfg.tc_config[tc].path[1].bwg_id) || - (adapter->temp_dcb_cfg.tc_config[tc].path[1].bwg_percent != - adapter->dcb_cfg.tc_config[tc].path[1].bwg_percent) || - (adapter->temp_dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap != - adapter->dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap)) - adapter->dcb_set_bitmap |= BIT_PG_RX; - - if (adapter->temp_dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap != - adapter->dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap) - adapter->dcb_set_bitmap |= BIT_PFC; } static void ixgbe_dcbnl_set_pg_bwg_cfg_rx(struct net_device *netdev, int bwg_id, @@ -245,10 +245,6 @@ static void ixgbe_dcbnl_set_pg_bwg_cfg_rx(struct net_device *netdev, int bwg_id, struct ixgbe_adapter *adapter = netdev_priv(netdev); adapter->temp_dcb_cfg.bw_percentage[1][bwg_id] = bw_pct; - - if (adapter->temp_dcb_cfg.bw_percentage[1][bwg_id] != - adapter->dcb_cfg.bw_percentage[1][bwg_id]) - adapter->dcb_set_bitmap |= BIT_PG_RX; } static void ixgbe_dcbnl_get_pg_tc_cfg_tx(struct net_device *netdev, int tc, @@ -298,10 +294,8 @@ static void ixgbe_dcbnl_set_pfc_cfg(struct net_device *netdev, int priority, adapter->temp_dcb_cfg.tc_config[priority].dcb_pfc = setting; if (adapter->temp_dcb_cfg.tc_config[priority].dcb_pfc != - adapter->dcb_cfg.tc_config[priority].dcb_pfc) { - adapter->dcb_set_bitmap |= BIT_PFC; + adapter->dcb_cfg.tc_config[priority].dcb_pfc) adapter->temp_dcb_cfg.pfc_mode_enable = true; - } } static void ixgbe_dcbnl_get_pfc_cfg(struct net_device *netdev, int priority, @@ -336,7 +330,8 @@ static void ixgbe_dcbnl_devreset(struct net_device *dev) static u8 ixgbe_dcbnl_set_all(struct net_device *netdev) { struct ixgbe_adapter *adapter = netdev_priv(netdev); - int ret, i; + int ret = DCB_NO_HW_CHG; + int i; #ifdef IXGBE_FCOE struct dcb_app app = { .selector = DCB_APP_IDTYPE_ETHTYPE, @@ -355,12 +350,13 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev) /* Fail command if not in CEE mode */ if (!(adapter->dcbx_cap & DCB_CAP_DCBX_VER_CEE)) - return 1; + return ret; - ret = ixgbe_copy_dcb_cfg(&adapter->temp_dcb_cfg, &adapter->dcb_cfg, - MAX_TRAFFIC_CLASS); - if (ret) - return DCB_NO_HW_CHG; + adapter->dcb_set_bitmap |= ixgbe_copy_dcb_cfg(&adapter->temp_dcb_cfg, + &adapter->dcb_cfg, + MAX_TRAFFIC_CLASS); + if (!adapter->dcb_set_bitmap) + return ret; if (adapter->dcb_cfg.pfc_mode_enable) { switch (adapter->hw.mac.type) { @@ -420,6 +416,8 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev) for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) netdev_set_prio_tc_map(netdev, i, prio_tc[i]); + + ret = DCB_HW_CHG_RST; } if (adapter->dcb_set_bitmap & BIT_PFC) { @@ -430,7 +428,8 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev) DCB_TX_CONFIG, prio_tc); ixgbe_dcb_unpack_pfc(&adapter->dcb_cfg, &pfc_en); ixgbe_dcb_hw_pfc_config(&adapter->hw, pfc_en, prio_tc); - ret = DCB_HW_CHG; + if (ret != DCB_HW_CHG_RST) + ret = DCB_HW_CHG; } if (adapter->dcb_cfg.pfc_mode_enable) @@ -531,9 +530,6 @@ static void ixgbe_dcbnl_setpfcstate(struct net_device *netdev, u8 state) struct ixgbe_adapter *adapter = netdev_priv(netdev); adapter->temp_dcb_cfg.pfc_mode_enable = state; - if (adapter->temp_dcb_cfg.pfc_mode_enable != - adapter->dcb_cfg.pfc_mode_enable) - adapter->dcb_set_bitmap |= BIT_PFC; } /** -- cgit v1.2.3 From bb9e44d0d0f45da356c39e485edacff6e14ba961 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Wed, 21 Mar 2012 00:39:12 +0000 Subject: e1000e: prevent oops when adapter is being closed and reset simultaneously When the adapter is closed while it is simultaneously going through a reset, it can cause a null-pointer dereference when the two different code paths simultaneously cleanup up the Tx/Rx resources. Signed-off-by: Bruce Allan Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/e1000.h | 6 ++++++ drivers/net/ethernet/intel/e1000e/netdev.c | 9 +++++++++ 2 files changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h index 86cdd4793992..b83897f76ee3 100644 --- a/drivers/net/ethernet/intel/e1000e/e1000.h +++ b/drivers/net/ethernet/intel/e1000e/e1000.h @@ -161,6 +161,12 @@ struct e1000_info; /* Time to wait before putting the device into D3 if there's no link (in ms). */ #define LINK_TIMEOUT 100 +/* + * Count for polling __E1000_RESET condition every 10-20msec. + * Experimentation has shown the reset can take approximately 210msec. + */ +#define E1000_CHECK_RESET_COUNT 25 + #define DEFAULT_RDTR 0 #define DEFAULT_RADV 8 #define BURST_RDTR 0x20 diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 2c38a65ade87..6878601f20c5 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -3968,6 +3968,10 @@ static int e1000_close(struct net_device *netdev) { struct e1000_adapter *adapter = netdev_priv(netdev); struct pci_dev *pdev = adapter->pdev; + int count = E1000_CHECK_RESET_COUNT; + + while (test_bit(__E1000_RESETTING, &adapter->state) && count--) + usleep_range(10000, 20000); WARN_ON(test_bit(__E1000_RESETTING, &adapter->state)); @@ -5472,6 +5476,11 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake, netif_device_detach(netdev); if (netif_running(netdev)) { + int count = E1000_CHECK_RESET_COUNT; + + while (test_bit(__E1000_RESETTING, &adapter->state) && count--) + usleep_range(10000, 20000); + WARN_ON(test_bit(__E1000_RESETTING, &adapter->state)); e1000e_down(adapter); e1000_free_irq(adapter); -- cgit v1.2.3 From bf03085f85112eac2d19036ea3003071220285bb Mon Sep 17 00:00:00 2001 From: Matthew Vick Date: Fri, 16 Mar 2012 09:03:00 +0000 Subject: e1000e: Guarantee descriptor writeback flush success. In rare circumstances, a descriptor writeback flush may not work if it arrives on a specific clock cycle as a writeback request is going out. Signed-off-by: Matthew Vick Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/netdev.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 6878601f20c5..19ab2154802c 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -1059,6 +1059,13 @@ static void e1000_print_hw_hang(struct work_struct *work) ew32(TIDV, adapter->tx_int_delay | E1000_TIDV_FPD); /* execute the writes immediately */ e1e_flush(); + /* + * Due to rare timing issues, write to TIDV again to ensure + * the write is successful + */ + ew32(TIDV, adapter->tx_int_delay | E1000_TIDV_FPD); + /* execute the writes immediately */ + e1e_flush(); adapter->tx_hang_recheck = true; return; } @@ -3616,6 +3623,16 @@ static void e1000e_flush_descriptors(struct e1000_adapter *adapter) /* execute the writes immediately */ e1e_flush(); + + /* + * due to rare timing issues, write to TIDV/RDTR again to ensure the + * write is successful + */ + ew32(TIDV, adapter->tx_int_delay | E1000_TIDV_FPD); + ew32(RDTR, adapter->rx_int_delay | E1000_RDTR_FPD); + + /* execute the writes immediately */ + e1e_flush(); } static void e1000e_update_stats(struct e1000_adapter *adapter); -- cgit v1.2.3 From b3300146aa8efc5d3937fd33f3cfdc580a3843bc Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 2 Apr 2012 00:02:09 +0000 Subject: phy:icplus:fix Auto Power Saving in ip101a_config_init. This patch fixes Auto Power Saving configuration in ip101a_config_init which was broken as there is no phy register write followed after setting IP101A_APS_ON flag. This patch also fixes the return value of ip101a_config_init. Without this patch ip101a_config_init returns 2 which is not an error accroding to IS_ERR and the mac driver will continue accessing 2 as valid pointer to phy_dev resulting in memory fault. Signed-off-by: Srinivas Kandagatla Signed-off-by: David S. Miller --- drivers/net/phy/icplus.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c index 0856e1b7a849..f08c85acf761 100644 --- a/drivers/net/phy/icplus.c +++ b/drivers/net/phy/icplus.c @@ -162,7 +162,8 @@ static int ip101a_g_config_init(struct phy_device *phydev) /* Enable Auto Power Saving mode */ c = phy_read(phydev, IP10XX_SPEC_CTRL_STATUS); c |= IP101A_G_APS_ON; - return c; + + return phy_write(phydev, IP10XX_SPEC_CTRL_STATUS, c); } static int ip175c_read_status(struct phy_device *phydev) -- cgit v1.2.3 From f2ed5ee1b050495be49e5a0d5df152663558ef08 Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Tue, 3 Apr 2012 00:07:11 +0000 Subject: bnx2x: correction to firmware interface Commit 621b4d6 updated the bnx2x driver to a new FW version, but lacked a commit to a header file with changes to the firmware's interface. The missing interface change causes iscsi and fcoe to misbehave with the updated firmware. Signed-off-by: Yuval Mintz Signed-off-by: Dmitry Kravkov Signed-off-by: Eilon Greenstein CC: Michael Chan CC: Bhanu Prakash Gollapudi Signed-off-by: David S. Miller --- .../net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h | 110 ++++++++++----------- 1 file changed, 55 insertions(+), 55 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h index cd6dfa9eaa3a..b9b263323436 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h @@ -25,31 +25,31 @@ (IRO[149].base + ((funcId) * IRO[149].m1)) #define CSTORM_IGU_MODE_OFFSET (IRO[157].base) #define CSTORM_ISCSI_CQ_SIZE_OFFSET(pfId) \ - (IRO[315].base + ((pfId) * IRO[315].m1)) -#define CSTORM_ISCSI_CQ_SQN_SIZE_OFFSET(pfId) \ (IRO[316].base + ((pfId) * IRO[316].m1)) +#define CSTORM_ISCSI_CQ_SQN_SIZE_OFFSET(pfId) \ + (IRO[317].base + ((pfId) * IRO[317].m1)) #define CSTORM_ISCSI_EQ_CONS_OFFSET(pfId, iscsiEqId) \ - (IRO[308].base + ((pfId) * IRO[308].m1) + ((iscsiEqId) * IRO[308].m2)) + (IRO[309].base + ((pfId) * IRO[309].m1) + ((iscsiEqId) * IRO[309].m2)) #define CSTORM_ISCSI_EQ_NEXT_EQE_ADDR_OFFSET(pfId, iscsiEqId) \ - (IRO[310].base + ((pfId) * IRO[310].m1) + ((iscsiEqId) * IRO[310].m2)) + (IRO[311].base + ((pfId) * IRO[311].m1) + ((iscsiEqId) * IRO[311].m2)) #define CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_OFFSET(pfId, iscsiEqId) \ - (IRO[309].base + ((pfId) * IRO[309].m1) + ((iscsiEqId) * IRO[309].m2)) + (IRO[310].base + ((pfId) * IRO[310].m1) + ((iscsiEqId) * IRO[310].m2)) #define CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_VALID_OFFSET(pfId, iscsiEqId) \ - (IRO[311].base + ((pfId) * IRO[311].m1) + ((iscsiEqId) * IRO[311].m2)) + (IRO[312].base + ((pfId) * IRO[312].m1) + ((iscsiEqId) * IRO[312].m2)) #define CSTORM_ISCSI_EQ_PROD_OFFSET(pfId, iscsiEqId) \ - (IRO[307].base + ((pfId) * IRO[307].m1) + ((iscsiEqId) * IRO[307].m2)) + (IRO[308].base + ((pfId) * IRO[308].m1) + ((iscsiEqId) * IRO[308].m2)) #define CSTORM_ISCSI_EQ_SB_INDEX_OFFSET(pfId, iscsiEqId) \ - (IRO[313].base + ((pfId) * IRO[313].m1) + ((iscsiEqId) * IRO[313].m2)) + (IRO[314].base + ((pfId) * IRO[314].m1) + ((iscsiEqId) * IRO[314].m2)) #define CSTORM_ISCSI_EQ_SB_NUM_OFFSET(pfId, iscsiEqId) \ - (IRO[312].base + ((pfId) * IRO[312].m1) + ((iscsiEqId) * IRO[312].m2)) + (IRO[313].base + ((pfId) * IRO[313].m1) + ((iscsiEqId) * IRO[313].m2)) #define CSTORM_ISCSI_HQ_SIZE_OFFSET(pfId) \ - (IRO[314].base + ((pfId) * IRO[314].m1)) + (IRO[315].base + ((pfId) * IRO[315].m1)) #define CSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfId) \ - (IRO[306].base + ((pfId) * IRO[306].m1)) + (IRO[307].base + ((pfId) * IRO[307].m1)) #define CSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfId) \ - (IRO[305].base + ((pfId) * IRO[305].m1)) + (IRO[306].base + ((pfId) * IRO[306].m1)) #define CSTORM_ISCSI_PAGE_SIZE_OFFSET(pfId) \ - (IRO[304].base + ((pfId) * IRO[304].m1)) + (IRO[305].base + ((pfId) * IRO[305].m1)) #define CSTORM_RECORD_SLOW_PATH_OFFSET(funcId) \ (IRO[151].base + ((funcId) * IRO[151].m1)) #define CSTORM_SP_STATUS_BLOCK_DATA_OFFSET(pfId) \ @@ -96,37 +96,37 @@ #define TSTORM_FUNC_EN_OFFSET(funcId) \ (IRO[103].base + ((funcId) * IRO[103].m1)) #define TSTORM_ISCSI_ERROR_BITMAP_OFFSET(pfId) \ - (IRO[271].base + ((pfId) * IRO[271].m1)) -#define TSTORM_ISCSI_L2_ISCSI_OOO_CID_TABLE_OFFSET(pfId) \ (IRO[272].base + ((pfId) * IRO[272].m1)) -#define TSTORM_ISCSI_L2_ISCSI_OOO_CLIENT_ID_TABLE_OFFSET(pfId) \ +#define TSTORM_ISCSI_L2_ISCSI_OOO_CID_TABLE_OFFSET(pfId) \ (IRO[273].base + ((pfId) * IRO[273].m1)) -#define TSTORM_ISCSI_L2_ISCSI_OOO_PROD_OFFSET(pfId) \ +#define TSTORM_ISCSI_L2_ISCSI_OOO_CLIENT_ID_TABLE_OFFSET(pfId) \ (IRO[274].base + ((pfId) * IRO[274].m1)) +#define TSTORM_ISCSI_L2_ISCSI_OOO_PROD_OFFSET(pfId) \ + (IRO[275].base + ((pfId) * IRO[275].m1)) #define TSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfId) \ - (IRO[270].base + ((pfId) * IRO[270].m1)) + (IRO[271].base + ((pfId) * IRO[271].m1)) #define TSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfId) \ - (IRO[269].base + ((pfId) * IRO[269].m1)) + (IRO[270].base + ((pfId) * IRO[270].m1)) #define TSTORM_ISCSI_PAGE_SIZE_OFFSET(pfId) \ - (IRO[268].base + ((pfId) * IRO[268].m1)) + (IRO[269].base + ((pfId) * IRO[269].m1)) #define TSTORM_ISCSI_RQ_SIZE_OFFSET(pfId) \ - (IRO[267].base + ((pfId) * IRO[267].m1)) + (IRO[268].base + ((pfId) * IRO[268].m1)) #define TSTORM_ISCSI_TCP_LOCAL_ADV_WND_OFFSET(pfId) \ - (IRO[276].base + ((pfId) * IRO[276].m1)) + (IRO[277].base + ((pfId) * IRO[277].m1)) #define TSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(pfId) \ - (IRO[263].base + ((pfId) * IRO[263].m1)) -#define TSTORM_ISCSI_TCP_VARS_LSB_LOCAL_MAC_ADDR_OFFSET(pfId) \ (IRO[264].base + ((pfId) * IRO[264].m1)) -#define TSTORM_ISCSI_TCP_VARS_MID_LOCAL_MAC_ADDR_OFFSET(pfId) \ +#define TSTORM_ISCSI_TCP_VARS_LSB_LOCAL_MAC_ADDR_OFFSET(pfId) \ (IRO[265].base + ((pfId) * IRO[265].m1)) -#define TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(pfId) \ +#define TSTORM_ISCSI_TCP_VARS_MID_LOCAL_MAC_ADDR_OFFSET(pfId) \ (IRO[266].base + ((pfId) * IRO[266].m1)) +#define TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(pfId) \ + (IRO[267].base + ((pfId) * IRO[267].m1)) #define TSTORM_MAC_FILTER_CONFIG_OFFSET(pfId) \ (IRO[202].base + ((pfId) * IRO[202].m1)) #define TSTORM_RECORD_SLOW_PATH_OFFSET(funcId) \ (IRO[105].base + ((funcId) * IRO[105].m1)) #define TSTORM_TCP_MAX_CWND_OFFSET(pfId) \ - (IRO[216].base + ((pfId) * IRO[216].m1)) + (IRO[217].base + ((pfId) * IRO[217].m1)) #define TSTORM_VF_TO_PF_OFFSET(funcId) \ (IRO[104].base + ((funcId) * IRO[104].m1)) #define USTORM_AGG_DATA_OFFSET (IRO[206].base) @@ -140,29 +140,29 @@ #define USTORM_ETH_PAUSE_ENABLED_OFFSET(portId) \ (IRO[183].base + ((portId) * IRO[183].m1)) #define USTORM_FCOE_EQ_PROD_OFFSET(pfId) \ - (IRO[317].base + ((pfId) * IRO[317].m1)) + (IRO[318].base + ((pfId) * IRO[318].m1)) #define USTORM_FUNC_EN_OFFSET(funcId) \ (IRO[178].base + ((funcId) * IRO[178].m1)) #define USTORM_ISCSI_CQ_SIZE_OFFSET(pfId) \ - (IRO[281].base + ((pfId) * IRO[281].m1)) -#define USTORM_ISCSI_CQ_SQN_SIZE_OFFSET(pfId) \ (IRO[282].base + ((pfId) * IRO[282].m1)) +#define USTORM_ISCSI_CQ_SQN_SIZE_OFFSET(pfId) \ + (IRO[283].base + ((pfId) * IRO[283].m1)) #define USTORM_ISCSI_ERROR_BITMAP_OFFSET(pfId) \ - (IRO[286].base + ((pfId) * IRO[286].m1)) + (IRO[287].base + ((pfId) * IRO[287].m1)) #define USTORM_ISCSI_GLOBAL_BUF_PHYS_ADDR_OFFSET(pfId) \ - (IRO[283].base + ((pfId) * IRO[283].m1)) + (IRO[284].base + ((pfId) * IRO[284].m1)) #define USTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfId) \ - (IRO[279].base + ((pfId) * IRO[279].m1)) + (IRO[280].base + ((pfId) * IRO[280].m1)) #define USTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfId) \ - (IRO[278].base + ((pfId) * IRO[278].m1)) + (IRO[279].base + ((pfId) * IRO[279].m1)) #define USTORM_ISCSI_PAGE_SIZE_OFFSET(pfId) \ - (IRO[277].base + ((pfId) * IRO[277].m1)) + (IRO[278].base + ((pfId) * IRO[278].m1)) #define USTORM_ISCSI_R2TQ_SIZE_OFFSET(pfId) \ - (IRO[280].base + ((pfId) * IRO[280].m1)) + (IRO[281].base + ((pfId) * IRO[281].m1)) #define USTORM_ISCSI_RQ_BUFFER_SIZE_OFFSET(pfId) \ - (IRO[284].base + ((pfId) * IRO[284].m1)) -#define USTORM_ISCSI_RQ_SIZE_OFFSET(pfId) \ (IRO[285].base + ((pfId) * IRO[285].m1)) +#define USTORM_ISCSI_RQ_SIZE_OFFSET(pfId) \ + (IRO[286].base + ((pfId) * IRO[286].m1)) #define USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(pfId) \ (IRO[182].base + ((pfId) * IRO[182].m1)) #define USTORM_RECORD_SLOW_PATH_OFFSET(funcId) \ @@ -188,39 +188,39 @@ #define XSTORM_FUNC_EN_OFFSET(funcId) \ (IRO[47].base + ((funcId) * IRO[47].m1)) #define XSTORM_ISCSI_HQ_SIZE_OFFSET(pfId) \ - (IRO[294].base + ((pfId) * IRO[294].m1)) + (IRO[295].base + ((pfId) * IRO[295].m1)) #define XSTORM_ISCSI_LOCAL_MAC_ADDR0_OFFSET(pfId) \ - (IRO[297].base + ((pfId) * IRO[297].m1)) -#define XSTORM_ISCSI_LOCAL_MAC_ADDR1_OFFSET(pfId) \ (IRO[298].base + ((pfId) * IRO[298].m1)) -#define XSTORM_ISCSI_LOCAL_MAC_ADDR2_OFFSET(pfId) \ +#define XSTORM_ISCSI_LOCAL_MAC_ADDR1_OFFSET(pfId) \ (IRO[299].base + ((pfId) * IRO[299].m1)) -#define XSTORM_ISCSI_LOCAL_MAC_ADDR3_OFFSET(pfId) \ +#define XSTORM_ISCSI_LOCAL_MAC_ADDR2_OFFSET(pfId) \ (IRO[300].base + ((pfId) * IRO[300].m1)) -#define XSTORM_ISCSI_LOCAL_MAC_ADDR4_OFFSET(pfId) \ +#define XSTORM_ISCSI_LOCAL_MAC_ADDR3_OFFSET(pfId) \ (IRO[301].base + ((pfId) * IRO[301].m1)) -#define XSTORM_ISCSI_LOCAL_MAC_ADDR5_OFFSET(pfId) \ +#define XSTORM_ISCSI_LOCAL_MAC_ADDR4_OFFSET(pfId) \ (IRO[302].base + ((pfId) * IRO[302].m1)) -#define XSTORM_ISCSI_LOCAL_VLAN_OFFSET(pfId) \ +#define XSTORM_ISCSI_LOCAL_MAC_ADDR5_OFFSET(pfId) \ (IRO[303].base + ((pfId) * IRO[303].m1)) +#define XSTORM_ISCSI_LOCAL_VLAN_OFFSET(pfId) \ + (IRO[304].base + ((pfId) * IRO[304].m1)) #define XSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfId) \ - (IRO[293].base + ((pfId) * IRO[293].m1)) + (IRO[294].base + ((pfId) * IRO[294].m1)) #define XSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfId) \ - (IRO[292].base + ((pfId) * IRO[292].m1)) + (IRO[293].base + ((pfId) * IRO[293].m1)) #define XSTORM_ISCSI_PAGE_SIZE_OFFSET(pfId) \ - (IRO[291].base + ((pfId) * IRO[291].m1)) + (IRO[292].base + ((pfId) * IRO[292].m1)) #define XSTORM_ISCSI_R2TQ_SIZE_OFFSET(pfId) \ - (IRO[296].base + ((pfId) * IRO[296].m1)) + (IRO[297].base + ((pfId) * IRO[297].m1)) #define XSTORM_ISCSI_SQ_SIZE_OFFSET(pfId) \ - (IRO[295].base + ((pfId) * IRO[295].m1)) + (IRO[296].base + ((pfId) * IRO[296].m1)) #define XSTORM_ISCSI_TCP_VARS_ADV_WND_SCL_OFFSET(pfId) \ - (IRO[290].base + ((pfId) * IRO[290].m1)) + (IRO[291].base + ((pfId) * IRO[291].m1)) #define XSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(pfId) \ - (IRO[289].base + ((pfId) * IRO[289].m1)) + (IRO[290].base + ((pfId) * IRO[290].m1)) #define XSTORM_ISCSI_TCP_VARS_TOS_OFFSET(pfId) \ - (IRO[288].base + ((pfId) * IRO[288].m1)) + (IRO[289].base + ((pfId) * IRO[289].m1)) #define XSTORM_ISCSI_TCP_VARS_TTL_OFFSET(pfId) \ - (IRO[287].base + ((pfId) * IRO[287].m1)) + (IRO[288].base + ((pfId) * IRO[288].m1)) #define XSTORM_RATE_SHAPING_PER_VN_VARS_OFFSET(pfId) \ (IRO[44].base + ((pfId) * IRO[44].m1)) #define XSTORM_RECORD_SLOW_PATH_OFFSET(funcId) \ -- cgit v1.2.3 From cff4c16296754888b6fd8c886bc860a888e20257 Mon Sep 17 00:00:00 2001 From: Artem Savkov Date: Tue, 3 Apr 2012 10:29:11 +0000 Subject: r8169: enable napi on resume. NAPI is disabled during suspend and needs to be enabled on resume. Without this the driver locks up during resume in rtl_reset_work() trying to disable NAPI again. Signed-off-by: Artem Savkov Acked-by: Francois Romieu Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 7b23554f80b6..f54509377efa 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -5810,7 +5810,10 @@ static void __rtl8169_resume(struct net_device *dev) rtl_pll_power_up(tp); + rtl_lock_work(tp); + napi_enable(&tp->napi); set_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags); + rtl_unlock_work(tp); rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING); } -- cgit v1.2.3 From e16de9137c8beab02d78fb4fa82bb96e9f3d0ac3 Mon Sep 17 00:00:00 2001 From: Graeme Smecher Date: Tue, 3 Apr 2012 19:42:21 -0400 Subject: hwmon: (ad7314) Adds missing spi_dev initialization This driver was recently moved from IIO (where it worked) to hwmon (where it doesn't.) This breakage occured because the hwmon version neglected to correctly initialize a reference to spi_dev in its drvdata. The result is a segfault every time the temperature is queried. Signed-off-by: Graeme Smecher Cc: stable@vger.kernel.org # 3.2+ Signed-off-by: Guenter Roeck --- drivers/hwmon/ad7314.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/hwmon/ad7314.c b/drivers/hwmon/ad7314.c index 0e0cfcc36f8d..ce43642ef03e 100644 --- a/drivers/hwmon/ad7314.c +++ b/drivers/hwmon/ad7314.c @@ -128,6 +128,7 @@ static int __devinit ad7314_probe(struct spi_device *spi_dev) ret = PTR_ERR(chip->hwmon_dev); goto error_remove_group; } + chip->spi_dev = spi_dev; return 0; error_remove_group: -- cgit v1.2.3 From ca6f327dfdc6b3b90aa0c5247182ae023dce6450 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Wed, 4 Apr 2012 09:35:06 +0200 Subject: serial/sunzilog: fix keyboard on SUN SPARCstation The keyboard on my SUN SPARCstation 5 no longer worked. The culprint was: d4e33fac2408d37f7b52e80ca2a89f9fb482914f ("serial: Kill off NO_IRQ") Fix up logic for no irq / irq so the keyboard works again. Signed-off-by: Sam Ravnborg Cc: Alan Cox Cc: Greg Kroah-Hartman Signed-off-by: David S. Miller --- drivers/tty/serial/sunzilog.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c index b3b70b0bf85b..babd9470982b 100644 --- a/drivers/tty/serial/sunzilog.c +++ b/drivers/tty/serial/sunzilog.c @@ -1581,7 +1581,7 @@ static int __init sunzilog_init(void) if (err) goto out_unregister_uart; - if (!zilog_irq) { + if (zilog_irq) { struct uart_sunzilog_port *up = sunzilog_irq_chain; err = request_irq(zilog_irq, sunzilog_interrupt, IRQF_SHARED, "zs", sunzilog_irq_chain); @@ -1622,7 +1622,7 @@ static void __exit sunzilog_exit(void) { platform_driver_unregister(&zs_driver); - if (!zilog_irq) { + if (zilog_irq) { struct uart_sunzilog_port *up = sunzilog_irq_chain; /* Disable Interrupts */ -- cgit v1.2.3 From ec3e82d6dc46cac7309b01ff9761f469b0263019 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Wed, 4 Apr 2012 14:21:02 +0200 Subject: MCE, AMD: Drop too granulary family model checks MCA details seldom change inbetween the models of a family so don't be too conservative and enable decoding on everything starting from K8 onwards. Minor adjustments can come in later but most importantly, we have some decoding infrastructure in place for upcoming models by default. Signed-off-by: Borislav Petkov --- drivers/edac/mce_amd.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/mce_amd.c b/drivers/edac/mce_amd.c index 36e1486eb9aa..d0c372e30de4 100644 --- a/drivers/edac/mce_amd.c +++ b/drivers/edac/mce_amd.c @@ -754,9 +754,7 @@ static int __init mce_amd_init(void) if (c->x86_vendor != X86_VENDOR_AMD) return 0; - if ((c->x86 < 0xf || c->x86 > 0x12) && - (c->x86 != 0x14 || c->x86_model > 0xf) && - (c->x86 != 0x15 || c->x86_model > 0xf)) + if (c->x86 < 0xf || c->x86 > 0x15) return 0; fam_ops = kzalloc(sizeof(struct amd_decoder_ops), GFP_KERNEL); @@ -797,7 +795,7 @@ static int __init mce_amd_init(void) break; default: - printk(KERN_WARNING "Huh? What family is that: %d?!\n", c->x86); + printk(KERN_WARNING "Huh? What family is it: 0x%x?!\n", c->x86); kfree(fam_ops); return -EINVAL; } -- cgit v1.2.3 From f3718a818f7fb3636130d5f34bde8df34f45c5e5 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 4 Apr 2012 08:16:25 -0700 Subject: Revert "nouveau/bios: Fix tracking of BIOS image data" This reverts commit d06221c0617ab6d0bc41c4980cefdd9c8cc9a1c1. It turns out to trigger the "BUG_ON(!PageCompound(page))" in kfree(), apparently because the code ends up trying to free somethng that was never kmalloced in the first place. BenH points out that the patch was untested and wasn't meant to go into the upstream kernel that quickly in the first place. Backtrace: bios_shadow bios_shadow_prom nv_mask init_io bios_shadow nouveau_bios_init NVReadVgaCrtc NVSetOwner nouveau_card_init nouveau_load Reported-by: Meelis Roos Requested-by: Dave Airlie Acked-by: Benjamin Herrenschmidt Cc: Ben Skeggs Signed-off-by: Linus Torvalds --- drivers/gpu/drm/nouveau/nouveau_bios.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 1947d6139a38..80963d05b54a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -273,7 +273,6 @@ bios_shadow(struct drm_device *dev) mthd->score = score_vbios(bios, mthd->rw); mthd->size = bios->length; mthd->data = bios->data; - bios->data = NULL; } while (mthd->score != 3 && (++mthd)->shadow); mthd = shadow_methods; @@ -282,8 +281,7 @@ bios_shadow(struct drm_device *dev) if (mthd->score > best->score) { kfree(best->data); best = mthd; - } else - kfree(mthd->data); + } } while ((++mthd)->shadow); if (best->score) { -- cgit v1.2.3 From 1e7caf8bcf1b49eae152ad7cf442775472dd587c Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Wed, 21 Mar 2012 14:38:55 +0100 Subject: USB: ohci-at91: fix vbus_pin_active_low handling The information is not properly taken into account for {get|set}_power() functions. Signed-off-by: Nicolas Ferre Acked-by: Jean-Christophe PLAGNIOL-VILLARD Acked-by: Alan Stern Cc: stable [3.2+] --- drivers/usb/host/ohci-at91.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index db8963f5fbce..4d266ae5152d 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -247,7 +247,7 @@ static void ohci_at91_usb_set_power(struct at91_usbh_data *pdata, int port, int return; gpio_set_value(pdata->vbus_pin[port], - !pdata->vbus_pin_active_low[port] ^ enable); + pdata->vbus_pin_active_low[port] ^ enable); } static int ohci_at91_usb_get_power(struct at91_usbh_data *pdata, int port) @@ -259,7 +259,7 @@ static int ohci_at91_usb_get_power(struct at91_usbh_data *pdata, int port) return -EINVAL; return gpio_get_value(pdata->vbus_pin[port]) ^ - !pdata->vbus_pin_active_low[port]; + pdata->vbus_pin_active_low[port]; } /* -- cgit v1.2.3 From aaf9f5fc67c18259760d6302e679dcb3e36709a7 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Wed, 21 Mar 2012 16:58:11 +0100 Subject: USB: ohci-at91: rework and fix initialization The DT information are filled in a pdata structure and then passed on to the usual check code of the probe function. Thus we do not need to redo the gpio checking and irq configuration in the DT-related code. On the other hand, we setup GPIO direction in driver for vbus and overcurrent. It will be useful when moving to pinctrl subsystem. Signed-off-by: Nicolas Ferre Acked-by: Jean-Christophe PLAGNIOL-VILLARD Acked-by: Alan Stern --- drivers/usb/host/ohci-at91.c | 88 +++++++++++++++++++++++--------------------- 1 file changed, 46 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index 4d266ae5152d..c30da6ab9f92 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -492,7 +492,7 @@ static u64 at91_ohci_dma_mask = DMA_BIT_MASK(32); static int __devinit ohci_at91_of_init(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - int i, ret, gpio; + int i, gpio; enum of_gpio_flags flags; struct at91_usbh_data *pdata; u32 ports; @@ -520,42 +520,11 @@ static int __devinit ohci_at91_of_init(struct platform_device *pdev) if (!gpio_is_valid(gpio)) continue; pdata->vbus_pin_active_low[i] = flags & OF_GPIO_ACTIVE_LOW; - ret = gpio_request(gpio, "ohci_vbus"); - if (ret) { - dev_warn(&pdev->dev, "can't request vbus gpio %d", gpio); - continue; - } - ret = gpio_direction_output(gpio, !(flags & OF_GPIO_ACTIVE_LOW) ^ 1); - if (ret) - dev_warn(&pdev->dev, "can't put vbus gpio %d as output %d", - !(flags & OF_GPIO_ACTIVE_LOW) ^ 1, gpio); } - for (i = 0; i < 2; i++) { - gpio = of_get_named_gpio_flags(np, "atmel,oc-gpio", i, &flags); - pdata->overcurrent_pin[i] = gpio; - if (!gpio_is_valid(gpio)) - continue; - ret = gpio_request(gpio, "ohci_overcurrent"); - if (ret) { - dev_err(&pdev->dev, "can't request overcurrent gpio %d", gpio); - continue; - } - - ret = gpio_direction_input(gpio); - if (ret) { - dev_err(&pdev->dev, "can't configure overcurrent gpio %d as input", gpio); - continue; - } - - ret = request_irq(gpio_to_irq(gpio), - ohci_hcd_at91_overcurrent_irq, - IRQF_SHARED, "ohci_overcurrent", pdev); - if (ret) { - gpio_free(gpio); - dev_warn(& pdev->dev, "cannot get GPIO IRQ for overcurrent\n"); - } - } + for (i = 0; i < 2; i++) + pdata->overcurrent_pin[i] = + of_get_named_gpio_flags(np, "atmel,oc-gpio", i, &flags); pdev->dev.platform_data = pdata; @@ -574,6 +543,8 @@ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev) { struct at91_usbh_data *pdata; int i; + int gpio; + int ret; i = ohci_at91_of_init(pdev); @@ -586,23 +557,56 @@ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev) for (i = 0; i < ARRAY_SIZE(pdata->vbus_pin); i++) { if (!gpio_is_valid(pdata->vbus_pin[i])) continue; - gpio_request(pdata->vbus_pin[i], "ohci_vbus"); + gpio = pdata->vbus_pin[i]; + + ret = gpio_request(gpio, "ohci_vbus"); + if (ret) { + dev_err(&pdev->dev, + "can't request vbus gpio %d\n", gpio); + continue; + } + ret = gpio_direction_output(gpio, + !pdata->vbus_pin_active_low[i]); + if (ret) { + dev_err(&pdev->dev, + "can't put vbus gpio %d as output %d\n", + gpio, !pdata->vbus_pin_active_low[i]); + gpio_free(gpio); + continue; + } + ohci_at91_usb_set_power(pdata, i, 1); } for (i = 0; i < ARRAY_SIZE(pdata->overcurrent_pin); i++) { - int ret; - if (!gpio_is_valid(pdata->overcurrent_pin[i])) continue; - gpio_request(pdata->overcurrent_pin[i], "ohci_overcurrent"); + gpio = pdata->overcurrent_pin[i]; + + ret = gpio_request(gpio, "ohci_overcurrent"); + if (ret) { + dev_err(&pdev->dev, + "can't request overcurrent gpio %d\n", + gpio); + continue; + } + + ret = gpio_direction_input(gpio); + if (ret) { + dev_err(&pdev->dev, + "can't configure overcurrent gpio %d as input\n", + gpio); + gpio_free(gpio); + continue; + } - ret = request_irq(gpio_to_irq(pdata->overcurrent_pin[i]), + ret = request_irq(gpio_to_irq(gpio), ohci_hcd_at91_overcurrent_irq, IRQF_SHARED, "ohci_overcurrent", pdev); if (ret) { - gpio_free(pdata->overcurrent_pin[i]); - dev_warn(& pdev->dev, "cannot get GPIO IRQ for overcurrent\n"); + gpio_free(gpio); + dev_err(&pdev->dev, + "can't get gpio IRQ for overcurrent\n"); } } } -- cgit v1.2.3 From 0ee6d1eeef7bf4e08aba37bf1da377b25e8d853a Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Wed, 21 Mar 2012 16:53:09 +0100 Subject: USB: ohci-at91: change maximum number of ports Change number of ports to 3 for newer SoCs. Modify pdata structure and ohci-at91 code that was dealing with ports information and check of port indexes. Several coding style errors have been addresses as the patch was touching affected lines of code and was producing errors while run through checkpatch.pl. Signed-off-by: Nicolas Ferre Acked-by: Jean-Christophe PLAGNIOL-VILLARD Acked-by: Alan Stern --- arch/arm/mach-at91/include/mach/board.h | 13 ++++--- drivers/usb/host/ohci-at91.c | 66 ++++++++++++++++++--------------- 2 files changed, 43 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h index 544a5d5ce416..49a821192c65 100644 --- a/arch/arm/mach-at91/include/mach/board.h +++ b/arch/arm/mach-at91/include/mach/board.h @@ -86,14 +86,15 @@ extern void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *d extern void __init at91_add_device_eth(struct macb_platform_data *data); /* USB Host */ +#define AT91_MAX_USBH_PORTS 3 struct at91_usbh_data { - u8 ports; /* number of ports on root hub */ - int vbus_pin[2]; /* port power-control pin */ - u8 vbus_pin_active_low[2]; + int vbus_pin[AT91_MAX_USBH_PORTS]; /* port power-control pin */ + int overcurrent_pin[AT91_MAX_USBH_PORTS]; + u8 ports; /* number of ports on root hub */ u8 overcurrent_supported; - int overcurrent_pin[2]; - u8 overcurrent_status[2]; - u8 overcurrent_changed[2]; + u8 vbus_pin_active_low[AT91_MAX_USBH_PORTS]; + u8 overcurrent_status[AT91_MAX_USBH_PORTS]; + u8 overcurrent_changed[AT91_MAX_USBH_PORTS]; }; extern void __init at91_add_device_usbh(struct at91_usbh_data *data); extern void __init at91_add_device_usbh_ohci(struct at91_usbh_data *data); diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index c30da6ab9f92..7cf4797a601e 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -27,6 +27,10 @@ #error "CONFIG_ARCH_AT91 must be defined." #endif +#define valid_port(index) ((index) >= 0 && (index) < AT91_MAX_USBH_PORTS) +#define at91_for_each_port(index) \ + for ((index) = 0; (index) < AT91_MAX_USBH_PORTS; (index)++) + /* interface and function clocks; sometimes also an AHB clock */ static struct clk *iclk, *fclk, *hclk; static int clocked; @@ -240,7 +244,7 @@ ohci_at91_start (struct usb_hcd *hcd) static void ohci_at91_usb_set_power(struct at91_usbh_data *pdata, int port, int enable) { - if (port < 0 || port >= 2) + if (!valid_port(port)) return; if (!gpio_is_valid(pdata->vbus_pin[port])) @@ -252,7 +256,7 @@ static void ohci_at91_usb_set_power(struct at91_usbh_data *pdata, int port, int static int ohci_at91_usb_get_power(struct at91_usbh_data *pdata, int port) { - if (port < 0 || port >= 2) + if (!valid_port(port)) return -EINVAL; if (!gpio_is_valid(pdata->vbus_pin[port])) @@ -271,9 +275,9 @@ static int ohci_at91_hub_status_data(struct usb_hcd *hcd, char *buf) int length = ohci_hub_status_data(hcd, buf); int port; - for (port = 0; port < ARRAY_SIZE(pdata->overcurrent_pin); port++) { + at91_for_each_port(port) { if (pdata->overcurrent_changed[port]) { - if (! length) + if (!length) length = 1; buf[0] |= 1 << (port + 1); } @@ -297,11 +301,17 @@ static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, "ohci_at91_hub_control(%p,0x%04x,0x%04x,0x%04x,%p,%04x)\n", hcd, typeReq, wValue, wIndex, buf, wLength); + wIndex--; + switch (typeReq) { case SetPortFeature: if (wValue == USB_PORT_FEAT_POWER) { dev_dbg(hcd->self.controller, "SetPortFeat: POWER\n"); - ohci_at91_usb_set_power(pdata, wIndex - 1, 1); + if (valid_port(wIndex)) { + ohci_at91_usb_set_power(pdata, wIndex, 1); + ret = 0; + } + goto out; } break; @@ -312,9 +322,9 @@ static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, dev_dbg(hcd->self.controller, "ClearPortFeature: C_OVER_CURRENT\n"); - if (wIndex == 1 || wIndex == 2) { - pdata->overcurrent_changed[wIndex-1] = 0; - pdata->overcurrent_status[wIndex-1] = 0; + if (valid_port(wIndex)) { + pdata->overcurrent_changed[wIndex] = 0; + pdata->overcurrent_status[wIndex] = 0; } goto out; @@ -323,9 +333,8 @@ static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, dev_dbg(hcd->self.controller, "ClearPortFeature: OVER_CURRENT\n"); - if (wIndex == 1 || wIndex == 2) { - pdata->overcurrent_status[wIndex-1] = 0; - } + if (valid_port(wIndex)) + pdata->overcurrent_status[wIndex] = 0; goto out; @@ -333,15 +342,15 @@ static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, dev_dbg(hcd->self.controller, "ClearPortFeature: POWER\n"); - if (wIndex == 1 || wIndex == 2) { - ohci_at91_usb_set_power(pdata, wIndex - 1, 0); + if (valid_port(wIndex)) { + ohci_at91_usb_set_power(pdata, wIndex, 0); return 0; } } break; } - ret = ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); + ret = ohci_hub_control(hcd, typeReq, wValue, wIndex + 1, buf, wLength); if (ret) goto out; @@ -377,18 +386,15 @@ static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, dev_dbg(hcd->self.controller, "GetPortStatus(%d)\n", wIndex); - if (wIndex == 1 || wIndex == 2) { - if (! ohci_at91_usb_get_power(pdata, wIndex-1)) { + if (valid_port(wIndex)) { + if (!ohci_at91_usb_get_power(pdata, wIndex)) *data &= ~cpu_to_le32(RH_PS_PPS); - } - if (pdata->overcurrent_changed[wIndex-1]) { + if (pdata->overcurrent_changed[wIndex]) *data |= cpu_to_le32(RH_PS_OCIC); - } - if (pdata->overcurrent_status[wIndex-1]) { + if (pdata->overcurrent_status[wIndex]) *data |= cpu_to_le32(RH_PS_POCI); - } } } @@ -450,14 +456,14 @@ static irqreturn_t ohci_hcd_at91_overcurrent_irq(int irq, void *data) /* From the GPIO notifying the over-current situation, find * out the corresponding port */ - for (port = 0; port < ARRAY_SIZE(pdata->overcurrent_pin); port++) { + at91_for_each_port(port) { if (gpio_to_irq(pdata->overcurrent_pin[port]) == irq) { gpio = pdata->overcurrent_pin[port]; break; } } - if (port == ARRAY_SIZE(pdata->overcurrent_pin)) { + if (port == AT91_MAX_USBH_PORTS) { dev_err(& pdev->dev, "overcurrent interrupt from unknown GPIO\n"); return IRQ_HANDLED; } @@ -467,7 +473,7 @@ static irqreturn_t ohci_hcd_at91_overcurrent_irq(int irq, void *data) /* When notified of an over-current situation, disable power on the corresponding port, and mark this port in over-current. */ - if (! val) { + if (!val) { ohci_at91_usb_set_power(pdata, port, 0); pdata->overcurrent_status[port] = 1; pdata->overcurrent_changed[port] = 1; @@ -514,7 +520,7 @@ static int __devinit ohci_at91_of_init(struct platform_device *pdev) if (!of_property_read_u32(np, "num-ports", &ports)) pdata->ports = ports; - for (i = 0; i < 2; i++) { + at91_for_each_port(i) { gpio = of_get_named_gpio_flags(np, "atmel,vbus-gpio", i, &flags); pdata->vbus_pin[i] = gpio; if (!gpio_is_valid(gpio)) @@ -522,7 +528,7 @@ static int __devinit ohci_at91_of_init(struct platform_device *pdev) pdata->vbus_pin_active_low[i] = flags & OF_GPIO_ACTIVE_LOW; } - for (i = 0; i < 2; i++) + at91_for_each_port(i) pdata->overcurrent_pin[i] = of_get_named_gpio_flags(np, "atmel,oc-gpio", i, &flags); @@ -554,7 +560,7 @@ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev) pdata = pdev->dev.platform_data; if (pdata) { - for (i = 0; i < ARRAY_SIZE(pdata->vbus_pin); i++) { + at91_for_each_port(i) { if (!gpio_is_valid(pdata->vbus_pin[i])) continue; gpio = pdata->vbus_pin[i]; @@ -578,7 +584,7 @@ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev) ohci_at91_usb_set_power(pdata, i, 1); } - for (i = 0; i < ARRAY_SIZE(pdata->overcurrent_pin); i++) { + at91_for_each_port(i) { if (!gpio_is_valid(pdata->overcurrent_pin[i])) continue; gpio = pdata->overcurrent_pin[i]; @@ -621,14 +627,14 @@ static int ohci_hcd_at91_drv_remove(struct platform_device *pdev) int i; if (pdata) { - for (i = 0; i < ARRAY_SIZE(pdata->vbus_pin); i++) { + at91_for_each_port(i) { if (!gpio_is_valid(pdata->vbus_pin[i])) continue; ohci_at91_usb_set_power(pdata, i, 0); gpio_free(pdata->vbus_pin[i]); } - for (i = 0; i < ARRAY_SIZE(pdata->overcurrent_pin); i++) { + at91_for_each_port(i) { if (!gpio_is_valid(pdata->overcurrent_pin[i])) continue; free_irq(gpio_to_irq(pdata->overcurrent_pin[i]), pdev); -- cgit v1.2.3 From 1887ab2bf236596a5ac7c0e7a90127b468c24081 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Wed, 28 Mar 2012 11:49:01 +0200 Subject: USB: ohci-at91: trivial return code name change Signed-off-by: Nicolas Ferre Acked-by: Jean-Christophe PLAGNIOL-VILLARD Acked-by: Alan Stern --- drivers/usb/host/ohci-at91.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index 7cf4797a601e..09f597ad6e00 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -552,10 +552,9 @@ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev) int gpio; int ret; - i = ohci_at91_of_init(pdev); - - if (i) - return i; + ret = ohci_at91_of_init(pdev); + if (ret) + return ret; pdata = pdev->dev.platform_data; -- cgit v1.2.3 From 9475375a5eb2ab9380e644d45173f67cbca0da80 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Tue, 27 Mar 2012 18:23:31 +0200 Subject: USB: ehci-atmel: add needed of.h header file Compilation error in case of non-DT configuration without this of.h header file. Signed-off-by: Nicolas Ferre Acked-by: Jean-Christophe PLAGNIOL-VILLARD Acked-by: Alan Stern --- drivers/usb/host/ehci-atmel.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c index 19f318ababa2..cf14c95a6700 100644 --- a/drivers/usb/host/ehci-atmel.c +++ b/drivers/usb/host/ehci-atmel.c @@ -13,6 +13,7 @@ #include #include +#include #include /* interface and function clocks */ -- cgit v1.2.3 From 2d1f6310d499f8d23e6726292c89380bd1d9693e Mon Sep 17 00:00:00 2001 From: Kukjin Kim Date: Wed, 4 Apr 2012 10:09:03 -0700 Subject: EXYNOS: fix dependency for EXYNOS_CPUFREQ This fixes the CPUFREQ dependency for regarding EXYNOS SoCs such as EXYNOS4210, EXYNOS4X12 and EXYNOS5250. Its cpufreq driver should be built with selection of SoC arch part. Reported-by: Russell King Acked-by: Dave Jones Signed-off-by: Kukjin Kim --- drivers/cpufreq/Kconfig.arm | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 32d790dd8180..ffbb44685915 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -51,9 +51,6 @@ config ARM_S5PV210_CPUFREQ config ARM_EXYNOS_CPUFREQ bool "SAMSUNG EXYNOS SoCs" depends on ARCH_EXYNOS - select ARM_EXYNOS4210_CPUFREQ if CPU_EXYNOS4210 - select ARM_EXYNOS4X12_CPUFREQ if (SOC_EXYNOS4212 || SOC_EXYNOS4412) - select ARM_EXYNOS5250_CPUFREQ if SOC_EXYNOS5250 default y help This adds the CPUFreq driver common part for Samsung @@ -62,20 +59,19 @@ config ARM_EXYNOS_CPUFREQ If in doubt, say N. config ARM_EXYNOS4210_CPUFREQ - bool "Samsung EXYNOS4210" - depends on ARCH_EXYNOS + def_bool CPU_EXYNOS4210 help This adds the CPUFreq driver for Samsung EXYNOS4210 SoC (S5PV310 or S5PC210). config ARM_EXYNOS4X12_CPUFREQ - bool "Samsung EXYNOS4X12" + def_bool (SOC_EXYNOS4212 || SOC_EXYNOS4412) help This adds the CPUFreq driver for Samsung EXYNOS4X12 SoC (EXYNOS4212 or EXYNOS4412). config ARM_EXYNOS5250_CPUFREQ - bool "Samsung EXYNOS5250" + def_bool SOC_EXYNOS5250 help This adds the CPUFreq driver for Samsung EXYNOS5250 SoC. -- cgit v1.2.3 From 5c1e2c9dc684f26fcc78ff4ef15dc97ed0244303 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Fri, 16 Mar 2012 17:35:08 -0600 Subject: gpio: tegra: fix register address calculations for Tegra30 Tegra20 and Tegra30 share the same register layout within registers, but the addresses of the registers is a little different. Fix the driver to cope with this. Signed-off-by: Stephen Warren Acked-by: Olof Johansson --- drivers/gpio/gpio-tegra.c | 55 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 32de6707e3c4..7d05a345776f 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include @@ -37,7 +37,8 @@ #define GPIO_PORT(x) (((x) >> 3) & 0x3) #define GPIO_BIT(x) ((x) & 0x7) -#define GPIO_REG(x) (GPIO_BANK(x) * 0x80 + GPIO_PORT(x) * 4) +#define GPIO_REG(x) (GPIO_BANK(x) * tegra_gpio_bank_stride + \ + GPIO_PORT(x) * 4) #define GPIO_CNF(x) (GPIO_REG(x) + 0x00) #define GPIO_OE(x) (GPIO_REG(x) + 0x10) @@ -48,12 +49,12 @@ #define GPIO_INT_LVL(x) (GPIO_REG(x) + 0x60) #define GPIO_INT_CLR(x) (GPIO_REG(x) + 0x70) -#define GPIO_MSK_CNF(x) (GPIO_REG(x) + 0x800) -#define GPIO_MSK_OE(x) (GPIO_REG(x) + 0x810) -#define GPIO_MSK_OUT(x) (GPIO_REG(x) + 0X820) -#define GPIO_MSK_INT_STA(x) (GPIO_REG(x) + 0x840) -#define GPIO_MSK_INT_ENB(x) (GPIO_REG(x) + 0x850) -#define GPIO_MSK_INT_LVL(x) (GPIO_REG(x) + 0x860) +#define GPIO_MSK_CNF(x) (GPIO_REG(x) + tegra_gpio_upper_offset + 0x00) +#define GPIO_MSK_OE(x) (GPIO_REG(x) + tegra_gpio_upper_offset + 0x10) +#define GPIO_MSK_OUT(x) (GPIO_REG(x) + tegra_gpio_upper_offset + 0X20) +#define GPIO_MSK_INT_STA(x) (GPIO_REG(x) + tegra_gpio_upper_offset + 0x40) +#define GPIO_MSK_INT_ENB(x) (GPIO_REG(x) + tegra_gpio_upper_offset + 0x50) +#define GPIO_MSK_INT_LVL(x) (GPIO_REG(x) + tegra_gpio_upper_offset + 0x60) #define GPIO_INT_LVL_MASK 0x010101 #define GPIO_INT_LVL_EDGE_RISING 0x000101 @@ -78,6 +79,8 @@ struct tegra_gpio_bank { static struct irq_domain *irq_domain; static void __iomem *regs; static u32 tegra_gpio_bank_count; +static u32 tegra_gpio_bank_stride; +static u32 tegra_gpio_upper_offset; static struct tegra_gpio_bank *tegra_gpio_banks; static inline void tegra_gpio_writel(u32 val, u32 reg) @@ -333,6 +336,26 @@ static struct irq_chip tegra_gpio_irq_chip = { #endif }; +struct tegra_gpio_soc_config { + u32 bank_stride; + u32 upper_offset; +}; + +static struct tegra_gpio_soc_config tegra20_gpio_config = { + .bank_stride = 0x80, + .upper_offset = 0x800, +}; + +static struct tegra_gpio_soc_config tegra30_gpio_config = { + .bank_stride = 0x100, + .upper_offset = 0x80, +}; + +static struct of_device_id tegra_gpio_of_match[] __devinitdata = { + { .compatible = "nvidia,tegra30-gpio", .data = &tegra30_gpio_config }, + { .compatible = "nvidia,tegra20-gpio", .data = &tegra20_gpio_config }, + { }, +}; /* This lock class tells lockdep that GPIO irqs are in a different * category than their parents, so it won't report false recursion. @@ -341,6 +364,8 @@ static struct lock_class_key gpio_lock_class; static int __devinit tegra_gpio_probe(struct platform_device *pdev) { + const struct of_device_id *match; + struct tegra_gpio_soc_config *config; int irq_base; struct resource *res; struct tegra_gpio_bank *bank; @@ -348,6 +373,15 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev) int i; int j; + match = of_match_device(tegra_gpio_of_match, &pdev->dev); + if (match) + config = (struct tegra_gpio_soc_config *)match->data; + else + config = &tegra20_gpio_config; + + tegra_gpio_bank_stride = config->bank_stride; + tegra_gpio_upper_offset = config->upper_offset; + for (;;) { res = platform_get_resource(pdev, IORESOURCE_IRQ, tegra_gpio_bank_count); if (!res) @@ -441,11 +475,6 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev) return 0; } -static struct of_device_id tegra_gpio_of_match[] __devinitdata = { - { .compatible = "nvidia,tegra20-gpio", }, - { }, -}; - static struct platform_driver tegra_gpio_driver = { .driver = { .name = "tegra-gpio", -- cgit v1.2.3 From 4a3398ee9d7d8008ee9bfc8a600b734a1b22af23 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Fri, 16 Mar 2012 17:37:24 -0600 Subject: gpio: tegra: Iterate over the correct number of banks When Tegra30 support was added to the Tegra GPIO driver, a few places which iterated over all banks were not converted to use the variable tegra_gpio_bank_count rather than hard-coding the bank count. Fix this. Signed-off-by: Stephen Warren Acked-by: Olof Johansson --- drivers/gpio/gpio-tegra.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 7d05a345776f..12f349b3830d 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -436,7 +436,7 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev) return -ENODEV; } - for (i = 0; i < 7; i++) { + for (i = 0; i < tegra_gpio_bank_count; i++) { for (j = 0; j < 4; j++) { int gpio = tegra_gpio_compose(i, j, 0); tegra_gpio_writel(0x00, GPIO_INT_ENB(gpio)); @@ -514,7 +514,7 @@ static int dbg_gpio_show(struct seq_file *s, void *unused) int i; int j; - for (i = 0; i < 7; i++) { + for (i = 0; i < tegra_gpio_bank_count; i++) { for (j = 0; j < 4; j++) { int gpio = tegra_gpio_compose(i, j, 0); seq_printf(s, -- cgit v1.2.3 From 2af73d4b2afe826d23e83f3747f850eefbd867ff Mon Sep 17 00:00:00 2001 From: Shlomo Pongratz Date: Tue, 3 Apr 2012 22:56:19 +0000 Subject: net/bonding: emit address change event also in bond_release commit 7d26bb103c4 "bonding: emit event when bonding changes MAC" didn't take care to emit the NETDEV_CHANGEADDR event in bond_release, where bonding actually changes the mac address (to all zeroes). As a result the neighbours aren't deleted by the core networking code (which does so upon getting that event). Signed-off-by: Shlomo Pongratz Signed-off-by: Jay Vosburgh Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 941b4e189adf..5cb85cb0be4f 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2034,6 +2034,9 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) write_unlock_bh(&bond->lock); unblock_netpoll_tx(); + if (bond->slave_cnt == 0) + call_netdevice_notifiers(NETDEV_CHANGEADDR, bond->dev); + bond_compute_features(bond); if (!(bond_dev->features & NETIF_F_VLAN_CHALLENGED) && (old_features & NETIF_F_VLAN_CHALLENGED)) -- cgit v1.2.3 From 234bcf8a499ee206145c7007d12d9706a254f790 Mon Sep 17 00:00:00 2001 From: Shlomo Pongratz Date: Tue, 3 Apr 2012 22:56:20 +0000 Subject: net/bonding: correctly proxy slave neigh param setup ndo function The current implemenation was buggy for slaves who use ndo_neigh_setup, since the networking stack invokes the bonding device ndo entry (from neigh_params_alloc) before any devices are enslaved, and the bonding driver can't further delegate the call at that point in time. As a result when bonding IPoIB devices, the neigh_cleanup hasn't been called. Fix that by deferring the actual call into the slave ndo_neigh_setup from the time the bonding neigh_setup is called. Signed-off-by: Shlomo Pongratz Signed-off-by: Jay Vosburgh Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 51 ++++++++++++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 5cb85cb0be4f..fc8a8d5c4dbd 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3704,17 +3704,52 @@ static void bond_set_multicast_list(struct net_device *bond_dev) read_unlock(&bond->lock); } -static int bond_neigh_setup(struct net_device *dev, struct neigh_parms *parms) +static int bond_neigh_init(struct neighbour *n) { - struct bonding *bond = netdev_priv(dev); + struct bonding *bond = netdev_priv(n->dev); struct slave *slave = bond->first_slave; + const struct net_device_ops *slave_ops; + struct neigh_parms parms; + int ret; + + if (!slave) + return 0; + + slave_ops = slave->dev->netdev_ops; + + if (!slave_ops->ndo_neigh_setup) + return 0; + + parms.neigh_setup = NULL; + parms.neigh_cleanup = NULL; + ret = slave_ops->ndo_neigh_setup(slave->dev, &parms); + if (ret) + return ret; + + /* + * Assign slave's neigh_cleanup to neighbour in case cleanup is called + * after the last slave has been detached. Assumes that all slaves + * utilize the same neigh_cleanup (true at this writing as only user + * is ipoib). + */ + n->parms->neigh_cleanup = parms.neigh_cleanup; + + if (!parms.neigh_setup) + return 0; + + return parms.neigh_setup(n); +} + +/* + * The bonding ndo_neigh_setup is called at init time beofre any + * slave exists. So we must declare proxy setup function which will + * be used at run time to resolve the actual slave neigh param setup. + */ +static int bond_neigh_setup(struct net_device *dev, + struct neigh_parms *parms) +{ + parms->neigh_setup = bond_neigh_init; - if (slave) { - const struct net_device_ops *slave_ops - = slave->dev->netdev_ops; - if (slave_ops->ndo_neigh_setup) - return slave_ops->ndo_neigh_setup(slave->dev, parms); - } return 0; } -- cgit v1.2.3 From 857504d06d565ad5b401d505937932775ddf1c47 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Wed, 4 Apr 2012 12:10:27 +0000 Subject: sky2: copy received packets on inefficient unaligned architecture Modified from original patch from Chris. The sky2 driver has to have 8 byte alignment of receive buffer on some chip versions. On architectures which don't support efficient unaligned access this doesn't work very well. The solution is to just copy all received packets which is what the driver already does for small packets. This allows the driver to be used on the Tilera TILEmpower-Gx, since the tile architecture doesn't currently handle kernel unaligned accesses, just userspace. Signed-off-by: Stephen Hemminger Acked-by: Chris Metcalf Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/sky2.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c index b806d9b4defb..c9b504e2dfc3 100644 --- a/drivers/net/ethernet/marvell/sky2.c +++ b/drivers/net/ethernet/marvell/sky2.c @@ -2469,6 +2469,17 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu) return err; } +static inline bool needs_copy(const struct rx_ring_info *re, + unsigned length) +{ +#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS + /* Some architectures need the IP header to be aligned */ + if (!IS_ALIGNED(re->data_addr + ETH_HLEN, sizeof(u32))) + return true; +#endif + return length < copybreak; +} + /* For small just reuse existing skb for next receive */ static struct sk_buff *receive_copy(struct sky2_port *sky2, const struct rx_ring_info *re, @@ -2599,7 +2610,7 @@ static struct sk_buff *sky2_receive(struct net_device *dev, goto error; okay: - if (length < copybreak) + if (needs_copy(re, length)) skb = receive_copy(sky2, re, length); else skb = receive_new(sky2, re, length); -- cgit v1.2.3 From c04c1b9ee8f30c7a3a25e20e406247003f634ebe Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 4 Apr 2012 15:48:33 -0600 Subject: regmap: prevent division by zero in rbtree_show If there are no nodes in the cache, nodes will be 0, so calculating "registers / nodes" will cause division by zero. Signed-off-by: Stephen Warren Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- drivers/base/regmap/regcache-rbtree.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c index 5157fa04c2f0..ea76a90630bf 100644 --- a/drivers/base/regmap/regcache-rbtree.c +++ b/drivers/base/regmap/regcache-rbtree.c @@ -138,6 +138,7 @@ static int rbtree_show(struct seq_file *s, void *ignored) unsigned int base, top; int nodes = 0; int registers = 0; + int average; mutex_lock(&map->lock); @@ -152,8 +153,13 @@ static int rbtree_show(struct seq_file *s, void *ignored) registers += top - base + 1; } + if (nodes) + average = registers / nodes; + else + average = 0; + seq_printf(s, "%d nodes, %d registers, average %d registers\n", - nodes, registers, registers / nodes); + nodes, registers, average); mutex_unlock(&map->lock); -- cgit v1.2.3 From 27d9129f5ae830cc031a898e0c220e1cdda69b34 Mon Sep 17 00:00:00 2001 From: Yaniv Rosner Date: Wed, 4 Apr 2012 01:28:54 +0000 Subject: bnx2x: PFC fix Fix a problem in which PFC frames are not honored, due to incorrect link attributes synchronization following PMF migration, and verify PFC XON is not stuck from previous link change. Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c | 18 +++++++++++++++++- drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h | 1 + 2 files changed, 18 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c index efa557b76ac7..7e2ebbad7587 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c @@ -1371,7 +1371,14 @@ static void bnx2x_update_pfc_xmac(struct link_params *params, pfc1_val |= XMAC_PFC_CTRL_HI_REG_PFC_REFRESH_EN | XMAC_PFC_CTRL_HI_REG_PFC_STATS_EN | XMAC_PFC_CTRL_HI_REG_RX_PFC_EN | - XMAC_PFC_CTRL_HI_REG_TX_PFC_EN; + XMAC_PFC_CTRL_HI_REG_TX_PFC_EN | + XMAC_PFC_CTRL_HI_REG_FORCE_PFC_XON; + /* Write pause and PFC registers */ + REG_WR(bp, xmac_base + XMAC_REG_PAUSE_CTRL, pause_val); + REG_WR(bp, xmac_base + XMAC_REG_PFC_CTRL, pfc0_val); + REG_WR(bp, xmac_base + XMAC_REG_PFC_CTRL_HI, pfc1_val); + pfc1_val &= ~XMAC_PFC_CTRL_HI_REG_FORCE_PFC_XON; + } /* Write pause and PFC registers */ @@ -6843,6 +6850,12 @@ int bnx2x_link_update(struct link_params *params, struct link_vars *vars) SINGLE_MEDIA_DIRECT(params)) && (phy_vars[active_external_phy].fault_detected == 0)); + /* Update the PFC configuration in case it was changed */ + if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED) + vars->link_status |= LINK_STATUS_PFC_ENABLED; + else + vars->link_status &= ~LINK_STATUS_PFC_ENABLED; + if (vars->link_up) rc = bnx2x_update_link_up(params, vars, link_10g_plus); else @@ -12049,6 +12062,9 @@ int bnx2x_phy_init(struct link_params *params, struct link_vars *vars) bnx2x_emac_init(params, vars); + if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED) + vars->link_status |= LINK_STATUS_PFC_ENABLED; + if (params->num_phys == 0) { DP(NETIF_MSG_LINK, "No phy found for initialization !!\n"); return -EINVAL; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h index ab0a250f95fa..ecc7fa6a6ca5 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h @@ -5354,6 +5354,7 @@ #define XMAC_CTRL_REG_TX_EN (0x1<<0) #define XMAC_PAUSE_CTRL_REG_RX_PAUSE_EN (0x1<<18) #define XMAC_PAUSE_CTRL_REG_TX_PAUSE_EN (0x1<<17) +#define XMAC_PFC_CTRL_HI_REG_FORCE_PFC_XON (0x1<<1) #define XMAC_PFC_CTRL_HI_REG_PFC_REFRESH_EN (0x1<<0) #define XMAC_PFC_CTRL_HI_REG_PFC_STATS_EN (0x1<<3) #define XMAC_PFC_CTRL_HI_REG_RX_PFC_EN (0x1<<4) -- cgit v1.2.3 From ca05f29cf515ac4a8e162c8e0eee886727f5dcc7 Mon Sep 17 00:00:00 2001 From: Yaniv Rosner Date: Wed, 4 Apr 2012 01:28:55 +0000 Subject: bnx2x: Fix BCM57810-KR FC Fix 57810-KR flow-control handling link is achieved via CL37 AN. Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c | 27 ++++++++++++++++++++++++ drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h | 4 ++++ 2 files changed, 31 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c index 7e2ebbad7587..8c00bbc94038 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c @@ -3655,6 +3655,33 @@ static void bnx2x_ext_phy_update_adv_fc(struct bnx2x_phy *phy, if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54618SE) { bnx2x_cl22_read(bp, phy, 0x4, &ld_pause); bnx2x_cl22_read(bp, phy, 0x5, &lp_pause); + } else if (CHIP_IS_E3(bp) && + SINGLE_MEDIA_DIRECT(params)) { + u8 lane = bnx2x_get_warpcore_lane(phy, params); + u16 gp_status, gp_mask; + bnx2x_cl45_read(bp, phy, + MDIO_AN_DEVAD, MDIO_WC_REG_GP2_STATUS_GP_2_4, + &gp_status); + gp_mask = (MDIO_WC_REG_GP2_STATUS_GP_2_4_CL73_AN_CMPL | + MDIO_WC_REG_GP2_STATUS_GP_2_4_CL37_LP_AN_CAP) << + lane; + if ((gp_status & gp_mask) == gp_mask) { + bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, + MDIO_AN_REG_ADV_PAUSE, &ld_pause); + bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, + MDIO_AN_REG_LP_AUTO_NEG, &lp_pause); + } else { + bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, + MDIO_AN_REG_CL37_FC_LD, &ld_pause); + bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, + MDIO_AN_REG_CL37_FC_LP, &lp_pause); + ld_pause = ((ld_pause & + MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) + << 3); + lp_pause = ((lp_pause & + MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) + << 3); + } } else { bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h index ecc7fa6a6ca5..1ea2b956e194 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h @@ -6944,6 +6944,10 @@ Theotherbitsarereservedandshouldbezero*/ #define MDIO_WC_REG_GP2_STATUS_GP_2_2 0x81d2 #define MDIO_WC_REG_GP2_STATUS_GP_2_3 0x81d3 #define MDIO_WC_REG_GP2_STATUS_GP_2_4 0x81d4 +#define MDIO_WC_REG_GP2_STATUS_GP_2_4_CL73_AN_CMPL 0x1000 +#define MDIO_WC_REG_GP2_STATUS_GP_2_4_CL37_AN_CMPL 0x0100 +#define MDIO_WC_REG_GP2_STATUS_GP_2_4_CL37_LP_AN_CAP 0x0010 +#define MDIO_WC_REG_GP2_STATUS_GP_2_4_CL37_AN_CAP 0x1 #define MDIO_WC_REG_UC_INFO_B0_DEAD_TRAP 0x81EE #define MDIO_WC_REG_UC_INFO_B1_VERSION 0x81F0 #define MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE 0x81F2 -- cgit v1.2.3 From 6a51c0d17b8fb6ae300ba5bc42a020160944e1b2 Mon Sep 17 00:00:00 2001 From: Yaniv Rosner Date: Wed, 4 Apr 2012 01:28:56 +0000 Subject: bnx2x: Fix BCM57810-KR AN speed transition BCM57810-KR link may not come up in 1G after running loopback test, so set the relevant registers to their default values before starting KR autoneg. Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c index 8c00bbc94038..ce0b0c220e64 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c @@ -3732,7 +3732,23 @@ static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy, u16 val16 = 0, lane, bam37 = 0; struct bnx2x *bp = params->bp; DP(NETIF_MSG_LINK, "Enable Auto Negotiation for KR\n"); - + /* Set to default registers that may be overriden by 10G force */ + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, 0x7); + bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, + MDIO_WC_REG_PAR_DET_10G_CTRL, 0); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL, 0); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_XGXSBLK1_LANECTRL0, 0xff); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_XGXSBLK1_LANECTRL1, 0x5555); + bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, + MDIO_WC_REG_IEEE0BLK_AUTONEGNP, 0x0); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_RX66_CONTROL, 0x7415); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_SERDESDIGITAL_MISC2, 0x6190); /* Disable Autoneg: re-enable it after adv is done. */ bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_WC_REG_IEEE0BLK_MIICNTL, 0); @@ -4402,7 +4418,7 @@ static void bnx2x_warpcore_config_init(struct bnx2x_phy *phy, switch (serdes_net_if) { case PORT_HW_CFG_NET_SERDES_IF_KR: /* Enable KR Auto Neg */ - if (params->loopback_mode == LOOPBACK_NONE) + if (params->loopback_mode != LOOPBACK_EXT) bnx2x_warpcore_enable_AN_KR(phy, params, vars); else { DP(NETIF_MSG_LINK, "Setting KR 10G-Force\n"); -- cgit v1.2.3 From 25182fc22237f0fb1789c7ac9a79e871a1898ae5 Mon Sep 17 00:00:00 2001 From: Yaniv Rosner Date: Wed, 4 Apr 2012 01:28:57 +0000 Subject: bnx2x: Fix BCM578x0-SFI pre-emphasis settings Fix 578x0-SFI pre-emphasis settings per HW recommendations to achieve better link strength. Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c index ce0b0c220e64..1e2fea37eec9 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c @@ -3994,13 +3994,13 @@ static void bnx2x_warpcore_set_10G_XFI(struct bnx2x_phy *phy, } else { misc1_val |= 0x9; - tap_val = ((0x12 << MDIO_WC_REG_TX_FIR_TAP_POST_TAP_OFFSET) | - (0x2d << MDIO_WC_REG_TX_FIR_TAP_MAIN_TAP_OFFSET) | - (0x00 << MDIO_WC_REG_TX_FIR_TAP_PRE_TAP_OFFSET)); + tap_val = ((0x0f << MDIO_WC_REG_TX_FIR_TAP_POST_TAP_OFFSET) | + (0x2b << MDIO_WC_REG_TX_FIR_TAP_MAIN_TAP_OFFSET) | + (0x02 << MDIO_WC_REG_TX_FIR_TAP_PRE_TAP_OFFSET)); tx_driver_val = - ((0x02 << MDIO_WC_REG_TX0_TX_DRIVER_POST2_COEFF_OFFSET) | + ((0x03 << MDIO_WC_REG_TX0_TX_DRIVER_POST2_COEFF_OFFSET) | (0x02 << MDIO_WC_REG_TX0_TX_DRIVER_IDRIVER_OFFSET) | - (0x02 << MDIO_WC_REG_TX0_TX_DRIVER_IPRE_DRIVER_OFFSET)); + (0x06 << MDIO_WC_REG_TX0_TX_DRIVER_IPRE_DRIVER_OFFSET)); } bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, MDIO_WC_REG_SERDESDIGITAL_MISC1, misc1_val); -- cgit v1.2.3 From 9379c9be4b20d5cb7bde577f402b749cd7d3caa2 Mon Sep 17 00:00:00 2001 From: Yaniv Rosner Date: Wed, 4 Apr 2012 01:28:58 +0000 Subject: bnx2x: Restore 1G LED on BCM57712+BCM8727 designs. Fix no-LED problem when link speed is 1G on BCM57712 + BCM8727 designs, by removing a logic error checking for a different PHY. Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c | 33 +++++++++++++----------- 1 file changed, 18 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c index 1e2fea37eec9..1438da858678 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c @@ -6216,12 +6216,14 @@ int bnx2x_set_led(struct link_params *params, tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED); if (params->phy[EXT_PHY1].type == - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54618SE) - EMAC_WR(bp, EMAC_REG_EMAC_LED, tmp & 0xfff1); - else { - EMAC_WR(bp, EMAC_REG_EMAC_LED, - (tmp | EMAC_LED_OVERRIDE)); - } + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54618SE) + tmp &= ~(EMAC_LED_1000MB_OVERRIDE | + EMAC_LED_100MB_OVERRIDE | + EMAC_LED_10MB_OVERRIDE); + else + tmp |= EMAC_LED_OVERRIDE; + + EMAC_WR(bp, EMAC_REG_EMAC_LED, tmp); break; case LED_MODE_OPER: @@ -6276,10 +6278,15 @@ int bnx2x_set_led(struct link_params *params, hw_led_mode); } else if ((params->phy[EXT_PHY1].type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54618SE) && - (mode != LED_MODE_OPER)) { + (mode == LED_MODE_ON)) { REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0); tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED); - EMAC_WR(bp, EMAC_REG_EMAC_LED, tmp | 0x3); + EMAC_WR(bp, EMAC_REG_EMAC_LED, tmp | + EMAC_LED_OVERRIDE | EMAC_LED_1000MB_OVERRIDE); + /* Break here; otherwise, it'll disable the + * intended override. + */ + break; } else REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, hw_led_mode); @@ -6294,13 +6301,9 @@ int bnx2x_set_led(struct link_params *params, LED_BLINK_RATE_VAL_E1X_E2); REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 + port*4, 1); - if ((params->phy[EXT_PHY1].type != - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54618SE) && - (mode != LED_MODE_OPER)) { - tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED); - EMAC_WR(bp, EMAC_REG_EMAC_LED, - (tmp & (~EMAC_LED_OVERRIDE))); - } + tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED); + EMAC_WR(bp, EMAC_REG_EMAC_LED, + (tmp & (~EMAC_LED_OVERRIDE))); if (CHIP_IS_E1(bp) && ((speed == SPEED_2500) || -- cgit v1.2.3 From 59a2e53b826103be8c22d9820355320b749b38ef Mon Sep 17 00:00:00 2001 From: Yaniv Rosner Date: Wed, 4 Apr 2012 01:28:59 +0000 Subject: bnx2x: Fix link issue for BCM8727 boards. This patch fixes a link problem on BCM57712 + BCM8727 designs in which the TX laser is controller by GPIO, after 1.60.xx drivers were previously loaded. On these designs the TX_LASER is enabled by logic AND between the PHY (through MDIO), and the GPIO. When an old driver is used, it disables the MDIO part, hence the GPIO control had no affect de facto. Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c index 1438da858678..732b4c80f116 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c @@ -8089,7 +8089,9 @@ static int bnx2x_verify_sfp_module(struct bnx2x_phy *phy, netdev_err(bp->dev, "Warning: Unqualified SFP+ module detected," " Port %d from %s part number %s\n", params->port, vendor_name, vendor_pn); - phy->flags |= FLAGS_SFP_NOT_APPROVED; + if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) != + PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_WARNING_MSG) + phy->flags |= FLAGS_SFP_NOT_APPROVED; return -EINVAL; } @@ -9149,6 +9151,12 @@ static int bnx2x_8727_config_init(struct bnx2x_phy *phy, tmp2 &= 0xFFEF; bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_OPT_CFG_REG, tmp2); + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, + &tmp2); + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, + (tmp2 & 0x7fff)); } return 0; @@ -9329,12 +9337,11 @@ static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy, MDIO_PMA_DEVAD, MDIO_PMA_LASI_RXCTRL, ((1<<5) | (1<<2))); } - DP(NETIF_MSG_LINK, "Enabling 8727 TX laser if SFP is approved\n"); - bnx2x_8727_specific_func(phy, params, ENABLE_TX); - /* If transmitter is disabled, ignore false link up indication */ - bnx2x_cl45_read(bp, phy, - MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &val1); - if (val1 & (1<<15)) { + + if (!(phy->flags & FLAGS_SFP_NOT_APPROVED)) { + DP(NETIF_MSG_LINK, "Enabling 8727 TX laser\n"); + bnx2x_sfp_set_transmitter(params, phy, 1); + } else { DP(NETIF_MSG_LINK, "Tx is disabled\n"); return 0; } -- cgit v1.2.3 From 8267bbb01f005fa8d0c8d046ecc24ae0b52e4d70 Mon Sep 17 00:00:00 2001 From: Yaniv Rosner Date: Wed, 4 Apr 2012 01:29:00 +0000 Subject: bnx2x: Fix BCM84833 PHY FW version presentation Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c index 732b4c80f116..b576a3ae8e91 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c @@ -9435,8 +9435,7 @@ static void bnx2x_save_848xx_spirom_version(struct bnx2x_phy *phy, if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) { bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, 0x400f, &fw_ver1); - bnx2x_save_spirom_version(bp, port, - ((fw_ver1 & 0xf000)>>5) | (fw_ver1 & 0x7f), + bnx2x_save_spirom_version(bp, port, fw_ver1 & 0xfff, phy->ver_addr); } else { /* For 32-bit registers in 848xx, access via MDIO2ARM i/f. */ -- cgit v1.2.3 From 99bf7f34368aac9b54dfa8801ae490a2326704f9 Mon Sep 17 00:00:00 2001 From: Yaniv Rosner Date: Wed, 4 Apr 2012 01:29:01 +0000 Subject: bnx2x: Clear BCM84833 LED after fan failure Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c | 9 +++++++++ drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h | 3 +++ 2 files changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c index b576a3ae8e91..ce95ef71f96f 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c @@ -9858,6 +9858,15 @@ static int bnx2x_84833_hw_reset_phy(struct bnx2x_phy *phy, other_shmem_base_addr)); u32 shmem_base_path[2]; + + /* Work around for 84833 LED failure inside RESET status */ + bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, + MDIO_AN_REG_8481_LEGACY_MII_CTRL, + MDIO_AN_REG_8481_MII_CTRL_FORCE_1G); + bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, + MDIO_AN_REG_8481_1G_100T_EXT_CTRL, + MIDO_AN_REG_8481_EXT_CTRL_FORCE_LEDS_OFF); + shmem_base_path[0] = params->shmem_base; shmem_base_path[1] = other_shmem_base_addr; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h index 1ea2b956e194..c25803b9c0ca 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h @@ -6821,10 +6821,13 @@ Theotherbitsarereservedandshouldbezero*/ #define MDIO_AN_REG_8481_10GBASE_T_AN_CTRL 0x0020 #define MDIO_AN_REG_8481_LEGACY_MII_CTRL 0xffe0 +#define MDIO_AN_REG_8481_MII_CTRL_FORCE_1G 0x40 #define MDIO_AN_REG_8481_LEGACY_MII_STATUS 0xffe1 #define MDIO_AN_REG_8481_LEGACY_AN_ADV 0xffe4 #define MDIO_AN_REG_8481_LEGACY_AN_EXPANSION 0xffe6 #define MDIO_AN_REG_8481_1000T_CTRL 0xffe9 +#define MDIO_AN_REG_8481_1G_100T_EXT_CTRL 0xfff0 +#define MIDO_AN_REG_8481_EXT_CTRL_FORCE_LEDS_OFF 0x0008 #define MDIO_AN_REG_8481_EXPANSION_REG_RD_RW 0xfff5 #define MDIO_AN_REG_8481_EXPANSION_REG_ACCESS 0xfff7 #define MDIO_AN_REG_8481_AUX_CTRL 0xfff8 -- cgit v1.2.3 From f93fb01628c00d1f26e8b45d2f10b8feb650dd4b Mon Sep 17 00:00:00 2001 From: Yaniv Rosner Date: Wed, 4 Apr 2012 01:29:02 +0000 Subject: bnx2x: Fix BCM57711+BCM84823 link issue Fix a link problem on the second port of BCM57711 + BCM84823 boards due to incorrect macro usage. Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c index ce95ef71f96f..7e41682bc2dd 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c @@ -10177,7 +10177,7 @@ static void bnx2x_848x3_link_reset(struct bnx2x_phy *phy, u8 port; u16 val16; - if (!(CHIP_IS_E1(bp))) + if (!(CHIP_IS_E1x(bp))) port = BP_PATH(bp); else port = params->port; @@ -10204,7 +10204,7 @@ static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy, u16 val; u8 port; - if (!(CHIP_IS_E1(bp))) + if (!(CHIP_IS_E1x(bp))) port = BP_PATH(bp); else port = params->port; -- cgit v1.2.3 From ca7b91bbd1f150216e6354cc20818aa993f331f2 Mon Sep 17 00:00:00 2001 From: Yaniv Rosner Date: Wed, 4 Apr 2012 01:40:02 +0000 Subject: bnx2x: Clear MDC/MDIO warning message This patch clears a warning message of "MDC/MDIO access timeout" which may appear when interface is loaded due to missing clock setting before resetting the LED, and starting periodic function too early. Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 1 - drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index 44556b719e81..4b054812713a 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -1874,7 +1874,6 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode) * bnx2x_periodic_task(). */ smp_mb(); - queue_delayed_work(bnx2x_wq, &bp->period_task, 0); } else bp->port.pmf = 0; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c index 7e41682bc2dd..ad95324dc042 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c @@ -12205,10 +12205,10 @@ int bnx2x_link_reset(struct link_params *params, struct link_vars *vars, * Hold it as vars low */ /* clear link led */ + bnx2x_set_mdio_clk(bp, params->chip_id, port); bnx2x_set_led(params, vars, LED_MODE_OFF, 0); if (reset_ext_phy) { - bnx2x_set_mdio_clk(bp, params->chip_id, port); for (phy_index = EXT_PHY1; phy_index < params->num_phys; phy_index++) { if (params->phy[phy_index].link_reset) { -- cgit v1.2.3 From 03f2eecdfc8aadae395ac593c099006390c8085c Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Tue, 3 Apr 2012 22:13:01 +0000 Subject: stmmac: re-add IFF_UNICAST_FLT for dwmac1000 In commit (bfab27a stmmac: add the experimental PCI support) the IFF_UNICAST_FLT flag has been removed from the stmmac_mac_device_setup() function. This patch re-adds the flag. Signed-off-by: Marc Kleine-Budde Acked-by: Giuseppe Cavallaro Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index e85ffbd54830..48d56da62f08 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -1737,10 +1737,12 @@ static int stmmac_hw_init(struct stmmac_priv *priv) struct mac_device_info *mac; /* Identify the MAC HW device */ - if (priv->plat->has_gmac) + if (priv->plat->has_gmac) { + priv->dev->priv_flags |= IFF_UNICAST_FLT; mac = dwmac1000_setup(priv->ioaddr); - else + } else { mac = dwmac100_setup(priv->ioaddr); + } if (!mac) return -ENOMEM; -- cgit v1.2.3 From 117980c4c994b6fe58e873fe803c9bcdcb4337a3 Mon Sep 17 00:00:00 2001 From: Thadeu Lima de Souza Cascardo Date: Wed, 4 Apr 2012 09:40:40 +0000 Subject: mlx4: allocate just enough pages instead of always 4 pages The driver uses a 2-order allocation, which is too much on architectures like ppc64, which has a 64KiB page. This particular allocation is used for large packet fragments that may have a size of 512, 1024, 4096 or fill the whole allocation. So, a minimum size of 16384 is good enough and will be the same size that is used in architectures of 4KiB sized pages. This will avoid allocation failures that we see when the system is under stress, but still has plenty of memory, like the one below. This will also allow us to set the interface MTU to higher values like 9000, which was not possible on ppc64 without this patch. Node 1 DMA: 737*64kB 37*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB 0*8192kB 0*16384kB = 51904kB 83137 total pagecache pages 0 pages in swap cache Swap cache stats: add 0, delete 0, find 0/0 Free swap = 10420096kB Total swap = 10420096kB 107776 pages RAM 1184 pages reserved 147343 pages shared 28152 pages non-shared netstat: page allocation failure. order:2, mode:0x4020 Call Trace: [c0000001a4fa3770] [c000000000012f04] .show_stack+0x74/0x1c0 (unreliable) [c0000001a4fa3820] [c00000000016af38] .__alloc_pages_nodemask+0x618/0x930 [c0000001a4fa39a0] [c0000000001a71a0] .alloc_pages_current+0xb0/0x170 [c0000001a4fa3a40] [d00000000dcc3e00] .mlx4_en_alloc_frag+0x200/0x240 [mlx4_en] [c0000001a4fa3b10] [d00000000dcc3f8c] .mlx4_en_complete_rx_desc+0x14c/0x250 [mlx4_en] [c0000001a4fa3be0] [d00000000dcc4eec] .mlx4_en_process_rx_cq+0x62c/0x850 [mlx4_en] [c0000001a4fa3d20] [d00000000dcc5150] .mlx4_en_poll_rx_cq+0x40/0x90 [mlx4_en] [c0000001a4fa3dc0] [c0000000004e2bb8] .net_rx_action+0x178/0x450 [c0000001a4fa3eb0] [c00000000009c9b8] .__do_softirq+0x118/0x290 [c0000001a4fa3f90] [c000000000031df8] .call_do_softirq+0x14/0x24 [c000000184c3b520] [c00000000000e700] .do_softirq+0xf0/0x110 [c000000184c3b5c0] [c00000000009c6d4] .irq_exit+0xb4/0xc0 [c000000184c3b640] [c00000000000e964] .do_IRQ+0x144/0x230 Signed-off-by: Thadeu Lima de Souza Cascardo Signed-off-by: Kleber Sacilotto de Souza Tested-by: Kleber Sacilotto de Souza Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index 9e2b911a1230..d69fee41f24a 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -83,8 +83,9 @@ #define MLX4_EN_WATCHDOG_TIMEOUT (15 * HZ) -#define MLX4_EN_ALLOC_ORDER 2 -#define MLX4_EN_ALLOC_SIZE (PAGE_SIZE << MLX4_EN_ALLOC_ORDER) +/* Use the maximum between 16384 and a single page */ +#define MLX4_EN_ALLOC_SIZE PAGE_ALIGN(16384) +#define MLX4_EN_ALLOC_ORDER get_order(MLX4_EN_ALLOC_SIZE) #define MLX4_EN_MAX_LRO_DESCRIPTORS 32 -- cgit v1.2.3 From 54f70077768e9aba37d9c5030b43497b6d5084fb Mon Sep 17 00:00:00 2001 From: "Luck, Tony" Date: Tue, 3 Apr 2012 09:37:28 -0700 Subject: ACPI processor: Use safe_halt() rather than halt() in acpi_idle_play_dead() ACPI code is shared by arch/x86 and arch/ia64. ia64 doesn't provide a plain "halt()" function. Use safe_halt() instead. Signed-off-by: Tony Luck Tested-by: Boris Ostrovsky Signed-off-by: Len Brown --- drivers/acpi/processor_idle.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 6b1d32a161ae..784f9a7beb17 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -786,7 +786,7 @@ static int acpi_idle_play_dead(struct cpuidle_device *dev, int index) while (1) { if (cx->entry_method == ACPI_CSTATE_HALT) - halt(); + safe_halt(); else if (cx->entry_method == ACPI_CSTATE_SYSTEMIO) { inb(cx->address); /* See comment in acpi_idle_do_entry() */ -- cgit v1.2.3 From b82c32872db20667d6ee8e2ea1e7bdec791bdcc7 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Thu, 5 Apr 2012 14:25:05 -0700 Subject: sysrq: use SEND_SIG_FORCED instead of force_sig() Change send_sig_all() to use do_send_sig_info(SEND_SIG_FORCED) instead of force_sig(SIGKILL). With the recent changes we do not need force_ to kill the CLONE_NEWPID tasks. And this is more correct. force_sig() can race with the exiting thread, while do_send_sig_info(group => true) kill the whole process. Some more notes from Oleg Nesterov: > Just one note. This change makes no difference for sysrq_handle_kill(). > But it obviously changes the behaviour sysrq_handle_term(). I think > this is fine, if you want to really kill the task which blocks/ignores > SIGTERM you can use sysrq_handle_kill(). > > Even ignoring the reasons why force_sig() is simply wrong here, > force_sig(SIGTERM) looks strange. The task won't be killed if it has > a handler, but SIG_IGN can't help. However if it has the handler > but blocks SIGTERM temporary (this is very common) it will be killed. Also, > force_sig() can't kill the process if the main thread has already > exited. IOW, it is trivial to create the process which can't be > killed by sysrq. So, this patch fixes the issue. Suggested-by: Oleg Nesterov Acked-by: Greg Kroah-Hartman Acked-by: Oleg Nesterov Signed-off-by: Anton Vorontsov Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/tty/sysrq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 136e86faa1e1..05728894a88c 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -327,7 +327,7 @@ static void send_sig_all(int sig) if (is_global_init(p)) continue; - force_sig(sig, p); + do_send_sig_info(sig, SEND_SIG_FORCED, p, true); } read_unlock(&tasklist_lock); } -- cgit v1.2.3 From fd835d1f2d4826a19530bc045579ffda5775b8f7 Mon Sep 17 00:00:00 2001 From: "Jett.Zhou" Date: Thu, 5 Apr 2012 14:25:08 -0700 Subject: drivers/rtc/rtc-88pm860x.c: fix rtc irq enable callback According to 88pm860x spec, rtc alarm irq enable control is bit3 for RTC_ALARM_EN, so fix it. Signed-off-by: Jett.Zhou Cc: Axel Lin Cc: Haojian Zhuang Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-88pm860x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-88pm860x.c b/drivers/rtc/rtc-88pm860x.c index f04761e6622d..8b72b4cd83d5 100644 --- a/drivers/rtc/rtc-88pm860x.c +++ b/drivers/rtc/rtc-88pm860x.c @@ -72,9 +72,9 @@ static int pm860x_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) struct pm860x_rtc_info *info = dev_get_drvdata(dev); if (enabled) - pm860x_set_bits(info->i2c, PM8607_RTC1, ALARM, ALARM); + pm860x_set_bits(info->i2c, PM8607_RTC1, ALARM_EN, ALARM_EN); else - pm860x_set_bits(info->i2c, PM8607_RTC1, ALARM, 0); + pm860x_set_bits(info->i2c, PM8607_RTC1, ALARM_EN, 0); return 0; } -- cgit v1.2.3 From 234e340582901211f40d8c732afc49f0630ecf05 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 5 Apr 2012 14:25:11 -0700 Subject: simple_open: automatically convert to simple_open() Many users of debugfs copy the implementation of default_open() when they want to support a custom read/write function op. This leads to a proliferation of the default_open() implementation across the entire tree. Now that the common implementation has been consolidated into libfs we can replace all the users of this function with simple_open(). This replacement was done with the following semantic patch: @ open @ identifier open_f != simple_open; identifier i, f; @@ -int open_f(struct inode *i, struct file *f) -{ ( -if (i->i_private) -f->private_data = i->i_private; | -f->private_data = i->i_private; ) -return 0; -} @ has_open depends on open @ identifier fops; identifier open.open_f; @@ struct file_operations fops = { ... -.open = open_f, +.open = simple_open, ... }; [akpm@linux-foundation.org: checkpatch fixes] Signed-off-by: Stephen Boyd Cc: Greg Kroah-Hartman Cc: Al Viro Cc: Julia Lawall Acked-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/arm/mach-msm/smd_debug.c | 8 +---- arch/x86/kernel/kdebugfs.c | 9 +----- drivers/acpi/ec_sys.c | 8 +---- drivers/base/regmap/regmap-debugfs.c | 12 ++----- drivers/bluetooth/btmrvl_debugfs.c | 26 ++++++--------- drivers/char/virtio_console.c | 8 +---- drivers/dma/coh901318.c | 9 +----- drivers/gpu/drm/i915/i915_debugfs.c | 14 ++------- drivers/hid/hid-picolcd.c | 16 ++-------- drivers/hid/hid-wiimote-debug.c | 8 +---- drivers/idle/i7300_idle.c | 8 +---- drivers/iommu/omap-iommu-debug.c | 10 ++---- drivers/mfd/aat2870-core.c | 9 +----- drivers/mfd/ab3100-core.c | 8 +---- drivers/misc/ibmasm/ibmasmfs.c | 8 +---- drivers/mtd/ubi/debug.c | 10 +----- drivers/net/caif/caif_spi.c | 10 ++---- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 9 +----- drivers/net/wimax/i2400m/debugfs.c | 15 ++------- drivers/net/wireless/ath/ath5k/debug.c | 23 +++++--------- drivers/net/wireless/ath/ath6kl/debug.c | 42 +++++++++++-------------- drivers/net/wireless/ath/ath9k/debug.c | 37 ++++++++++------------ drivers/net/wireless/ath/ath9k/dfs_debug.c | 9 +----- drivers/net/wireless/ath/ath9k/htc_drv_debug.c | 26 ++++++--------- drivers/net/wireless/ath/ath9k/rc.c | 8 +---- drivers/net/wireless/ath/carl9170/debug.c | 7 +---- drivers/net/wireless/b43/debugfs.c | 8 +---- drivers/net/wireless/b43legacy/debugfs.c | 8 +---- drivers/net/wireless/iwlegacy/3945-rs.c | 8 +---- drivers/net/wireless/iwlegacy/4965-rs.c | 12 ++----- drivers/net/wireless/iwlegacy/debug.c | 12 ++----- drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 11 ++----- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 12 ++----- drivers/net/wireless/iwlwifi/iwl-trans-pcie.c | 12 ++----- drivers/net/wireless/iwmc3200wifi/debugfs.c | 14 +++------ drivers/net/wireless/iwmc3200wifi/sdio.c | 9 +----- drivers/net/wireless/libertas/debugfs.c | 10 ++---- drivers/net/wireless/mwifiex/debugfs.c | 18 ++--------- drivers/net/wireless/wl1251/debugfs.c | 14 +++------ drivers/net/wireless/wl12xx/debugfs.c | 38 ++++++++++------------ drivers/oprofile/oprofilefs.c | 14 ++------- drivers/remoteproc/remoteproc_debugfs.c | 13 ++------ drivers/scsi/lpfc/lpfc_debugfs.c | 9 +----- drivers/spi/spi-dw.c | 8 +---- drivers/tty/serial/mfd.c | 9 ++---- drivers/tty/serial/pch_uart.c | 8 ++--- drivers/usb/core/inode.c | 10 +----- drivers/usb/host/ehci-dbg.c | 9 +----- drivers/uwb/uwb-debug.c | 9 +----- fs/debugfs/file.c | 14 ++------- fs/dlm/debug_fs.c | 9 +----- fs/pstore/inode.c | 8 +---- kernel/trace/blktrace.c | 18 ++--------- net/mac80211/debugfs.c | 12 ++----- net/mac80211/debugfs.h | 1 - net/mac80211/debugfs_key.c | 4 +-- net/mac80211/debugfs_netdev.c | 2 +- net/mac80211/debugfs_sta.c | 4 +-- net/mac80211/rate.c | 2 +- net/wireless/debugfs.c | 10 ++---- sound/soc/imx/imx-audmux.c | 8 +---- sound/soc/soc-core.c | 8 +---- sound/soc/soc-dapm.c | 16 ++-------- 63 files changed, 176 insertions(+), 572 deletions(-) (limited to 'drivers') diff --git a/arch/arm/mach-msm/smd_debug.c b/arch/arm/mach-msm/smd_debug.c index 0c56a5aaf588..c56df9e932ae 100644 --- a/arch/arm/mach-msm/smd_debug.c +++ b/arch/arm/mach-msm/smd_debug.c @@ -203,15 +203,9 @@ static ssize_t debug_read(struct file *file, char __user *buf, return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize); } -static int debug_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - static const struct file_operations debug_ops = { .read = debug_read, - .open = debug_open, + .open = simple_open, .llseek = default_llseek, }; diff --git a/arch/x86/kernel/kdebugfs.c b/arch/x86/kernel/kdebugfs.c index 90fcf62854bb..1d5d31ea686b 100644 --- a/arch/x86/kernel/kdebugfs.c +++ b/arch/x86/kernel/kdebugfs.c @@ -68,16 +68,9 @@ static ssize_t setup_data_read(struct file *file, char __user *user_buf, return count; } -static int setup_data_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - - return 0; -} - static const struct file_operations fops_setup_data = { .read = setup_data_read, - .open = setup_data_open, + .open = simple_open, .llseek = default_llseek, }; diff --git a/drivers/acpi/ec_sys.c b/drivers/acpi/ec_sys.c index b258cab9061c..7586544fddb4 100644 --- a/drivers/acpi/ec_sys.c +++ b/drivers/acpi/ec_sys.c @@ -27,12 +27,6 @@ MODULE_PARM_DESC(write_support, "Dangerous, reboot and removal of battery may " static struct dentry *acpi_ec_debugfs_dir; -static int acpi_ec_open_io(struct inode *i, struct file *f) -{ - f->private_data = i->i_private; - return 0; -} - static ssize_t acpi_ec_read_io(struct file *f, char __user *buf, size_t count, loff_t *off) { @@ -95,7 +89,7 @@ static ssize_t acpi_ec_write_io(struct file *f, const char __user *buf, static const struct file_operations acpi_ec_io_ops = { .owner = THIS_MODULE, - .open = acpi_ec_open_io, + .open = simple_open, .read = acpi_ec_read_io, .write = acpi_ec_write_io, .llseek = default_llseek, diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c index 58517a5dac13..251eb70f83e7 100644 --- a/drivers/base/regmap/regmap-debugfs.c +++ b/drivers/base/regmap/regmap-debugfs.c @@ -27,12 +27,6 @@ static size_t regmap_calc_reg_len(int max_val, char *buf, size_t buf_size) return strlen(buf); } -static int regmap_open_file(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - static ssize_t regmap_name_read_file(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -57,7 +51,7 @@ static ssize_t regmap_name_read_file(struct file *file, } static const struct file_operations regmap_name_fops = { - .open = regmap_open_file, + .open = simple_open, .read = regmap_name_read_file, .llseek = default_llseek, }; @@ -174,7 +168,7 @@ static ssize_t regmap_map_write_file(struct file *file, #endif static const struct file_operations regmap_map_fops = { - .open = regmap_open_file, + .open = simple_open, .read = regmap_map_read_file, .write = regmap_map_write_file, .llseek = default_llseek, @@ -243,7 +237,7 @@ out: } static const struct file_operations regmap_access_fops = { - .open = regmap_open_file, + .open = simple_open, .read = regmap_access_read_file, .llseek = default_llseek, }; diff --git a/drivers/bluetooth/btmrvl_debugfs.c b/drivers/bluetooth/btmrvl_debugfs.c index 6c20bbb54b71..428dbb7574bd 100644 --- a/drivers/bluetooth/btmrvl_debugfs.c +++ b/drivers/bluetooth/btmrvl_debugfs.c @@ -45,12 +45,6 @@ struct btmrvl_debugfs_data { struct dentry *txdnldready; }; -static int btmrvl_open_generic(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - static ssize_t btmrvl_hscfgcmd_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) { @@ -93,7 +87,7 @@ static ssize_t btmrvl_hscfgcmd_read(struct file *file, char __user *userbuf, static const struct file_operations btmrvl_hscfgcmd_fops = { .read = btmrvl_hscfgcmd_read, .write = btmrvl_hscfgcmd_write, - .open = btmrvl_open_generic, + .open = simple_open, .llseek = default_llseek, }; @@ -134,7 +128,7 @@ static ssize_t btmrvl_psmode_read(struct file *file, char __user *userbuf, static const struct file_operations btmrvl_psmode_fops = { .read = btmrvl_psmode_read, .write = btmrvl_psmode_write, - .open = btmrvl_open_generic, + .open = simple_open, .llseek = default_llseek, }; @@ -180,7 +174,7 @@ static ssize_t btmrvl_pscmd_read(struct file *file, char __user *userbuf, static const struct file_operations btmrvl_pscmd_fops = { .read = btmrvl_pscmd_read, .write = btmrvl_pscmd_write, - .open = btmrvl_open_generic, + .open = simple_open, .llseek = default_llseek, }; @@ -221,7 +215,7 @@ static ssize_t btmrvl_gpiogap_read(struct file *file, char __user *userbuf, static const struct file_operations btmrvl_gpiogap_fops = { .read = btmrvl_gpiogap_read, .write = btmrvl_gpiogap_write, - .open = btmrvl_open_generic, + .open = simple_open, .llseek = default_llseek, }; @@ -265,7 +259,7 @@ static ssize_t btmrvl_hscmd_read(struct file *file, char __user *userbuf, static const struct file_operations btmrvl_hscmd_fops = { .read = btmrvl_hscmd_read, .write = btmrvl_hscmd_write, - .open = btmrvl_open_generic, + .open = simple_open, .llseek = default_llseek, }; @@ -305,7 +299,7 @@ static ssize_t btmrvl_hsmode_read(struct file *file, char __user * userbuf, static const struct file_operations btmrvl_hsmode_fops = { .read = btmrvl_hsmode_read, .write = btmrvl_hsmode_write, - .open = btmrvl_open_generic, + .open = simple_open, .llseek = default_llseek, }; @@ -323,7 +317,7 @@ static ssize_t btmrvl_curpsmode_read(struct file *file, char __user *userbuf, static const struct file_operations btmrvl_curpsmode_fops = { .read = btmrvl_curpsmode_read, - .open = btmrvl_open_generic, + .open = simple_open, .llseek = default_llseek, }; @@ -341,7 +335,7 @@ static ssize_t btmrvl_psstate_read(struct file *file, char __user * userbuf, static const struct file_operations btmrvl_psstate_fops = { .read = btmrvl_psstate_read, - .open = btmrvl_open_generic, + .open = simple_open, .llseek = default_llseek, }; @@ -359,7 +353,7 @@ static ssize_t btmrvl_hsstate_read(struct file *file, char __user *userbuf, static const struct file_operations btmrvl_hsstate_fops = { .read = btmrvl_hsstate_read, - .open = btmrvl_open_generic, + .open = simple_open, .llseek = default_llseek, }; @@ -378,7 +372,7 @@ static ssize_t btmrvl_txdnldready_read(struct file *file, char __user *userbuf, static const struct file_operations btmrvl_txdnldready_fops = { .read = btmrvl_txdnldready_read, - .open = btmrvl_open_generic, + .open = simple_open, .llseek = default_llseek, }; diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index b58b56187065..ddf86b6500b7 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1038,12 +1038,6 @@ static struct attribute_group port_attribute_group = { .attrs = port_sysfs_entries, }; -static int debugfs_open(struct inode *inode, struct file *filp) -{ - filp->private_data = inode->i_private; - return 0; -} - static ssize_t debugfs_read(struct file *filp, char __user *ubuf, size_t count, loff_t *offp) { @@ -1087,7 +1081,7 @@ static ssize_t debugfs_read(struct file *filp, char __user *ubuf, static const struct file_operations port_debugfs_ops = { .owner = THIS_MODULE, - .open = debugfs_open, + .open = simple_open, .read = debugfs_read, }; diff --git a/drivers/dma/coh901318.c b/drivers/dma/coh901318.c index d65a718c0f9b..a63badcd2d6e 100644 --- a/drivers/dma/coh901318.c +++ b/drivers/dma/coh901318.c @@ -104,13 +104,6 @@ static void coh901318_list_print(struct coh901318_chan *cohc, static struct coh901318_base *debugfs_dma_base; static struct dentry *dma_dentry; -static int coh901318_debugfs_open(struct inode *inode, struct file *file) -{ - - file->private_data = inode->i_private; - return 0; -} - static int coh901318_debugfs_read(struct file *file, char __user *buf, size_t count, loff_t *f_pos) { @@ -158,7 +151,7 @@ static int coh901318_debugfs_read(struct file *file, char __user *buf, static const struct file_operations coh901318_debugfs_status_operations = { .owner = THIS_MODULE, - .open = coh901318_debugfs_open, + .open = simple_open, .read = coh901318_debugfs_read, .llseek = default_llseek, }; diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index fdb7ccefffbd..b505b70dba05 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1502,14 +1502,6 @@ static int i915_ppgtt_info(struct seq_file *m, void *data) return 0; } -static int -i915_debugfs_common_open(struct inode *inode, - struct file *filp) -{ - filp->private_data = inode->i_private; - return 0; -} - static ssize_t i915_wedged_read(struct file *filp, char __user *ubuf, @@ -1560,7 +1552,7 @@ i915_wedged_write(struct file *filp, static const struct file_operations i915_wedged_fops = { .owner = THIS_MODULE, - .open = i915_debugfs_common_open, + .open = simple_open, .read = i915_wedged_read, .write = i915_wedged_write, .llseek = default_llseek, @@ -1622,7 +1614,7 @@ i915_max_freq_write(struct file *filp, static const struct file_operations i915_max_freq_fops = { .owner = THIS_MODULE, - .open = i915_debugfs_common_open, + .open = simple_open, .read = i915_max_freq_read, .write = i915_max_freq_write, .llseek = default_llseek, @@ -1693,7 +1685,7 @@ i915_cache_sharing_write(struct file *filp, static const struct file_operations i915_cache_sharing_fops = { .owner = THIS_MODULE, - .open = i915_debugfs_common_open, + .open = simple_open, .read = i915_cache_sharing_read, .write = i915_cache_sharing_write, .llseek = default_llseek, diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c index 12f9777c385d..45c3433f7986 100644 --- a/drivers/hid/hid-picolcd.c +++ b/drivers/hid/hid-picolcd.c @@ -1525,12 +1525,6 @@ static const struct file_operations picolcd_debug_reset_fops = { /* * The "eeprom" file */ -static int picolcd_debug_eeprom_open(struct inode *i, struct file *f) -{ - f->private_data = i->i_private; - return 0; -} - static ssize_t picolcd_debug_eeprom_read(struct file *f, char __user *u, size_t s, loff_t *off) { @@ -1618,7 +1612,7 @@ static ssize_t picolcd_debug_eeprom_write(struct file *f, const char __user *u, */ static const struct file_operations picolcd_debug_eeprom_fops = { .owner = THIS_MODULE, - .open = picolcd_debug_eeprom_open, + .open = simple_open, .read = picolcd_debug_eeprom_read, .write = picolcd_debug_eeprom_write, .llseek = generic_file_llseek, @@ -1627,12 +1621,6 @@ static const struct file_operations picolcd_debug_eeprom_fops = { /* * The "flash" file */ -static int picolcd_debug_flash_open(struct inode *i, struct file *f) -{ - f->private_data = i->i_private; - return 0; -} - /* record a flash address to buf (bounds check to be done by caller) */ static int _picolcd_flash_setaddr(struct picolcd_data *data, u8 *buf, long off) { @@ -1817,7 +1805,7 @@ static ssize_t picolcd_debug_flash_write(struct file *f, const char __user *u, */ static const struct file_operations picolcd_debug_flash_fops = { .owner = THIS_MODULE, - .open = picolcd_debug_flash_open, + .open = simple_open, .read = picolcd_debug_flash_read, .write = picolcd_debug_flash_write, .llseek = generic_file_llseek, diff --git a/drivers/hid/hid-wiimote-debug.c b/drivers/hid/hid-wiimote-debug.c index 17dabc1f339e..eec329197c16 100644 --- a/drivers/hid/hid-wiimote-debug.c +++ b/drivers/hid/hid-wiimote-debug.c @@ -23,12 +23,6 @@ struct wiimote_debug { struct dentry *drm; }; -static int wiidebug_eeprom_open(struct inode *i, struct file *f) -{ - f->private_data = i->i_private; - return 0; -} - static ssize_t wiidebug_eeprom_read(struct file *f, char __user *u, size_t s, loff_t *off) { @@ -83,7 +77,7 @@ static ssize_t wiidebug_eeprom_read(struct file *f, char __user *u, size_t s, static const struct file_operations wiidebug_eeprom_fops = { .owner = THIS_MODULE, - .open = wiidebug_eeprom_open, + .open = simple_open, .read = wiidebug_eeprom_read, .llseek = generic_file_llseek, }; diff --git a/drivers/idle/i7300_idle.c b/drivers/idle/i7300_idle.c index c976285d313e..fa080ebd568f 100644 --- a/drivers/idle/i7300_idle.c +++ b/drivers/idle/i7300_idle.c @@ -516,12 +516,6 @@ static struct notifier_block i7300_idle_nb = { MODULE_DEVICE_TABLE(pci, pci_tbl); -int stats_open_generic(struct inode *inode, struct file *fp) -{ - fp->private_data = inode->i_private; - return 0; -} - static ssize_t stats_read_ul(struct file *fp, char __user *ubuf, size_t count, loff_t *off) { @@ -534,7 +528,7 @@ static ssize_t stats_read_ul(struct file *fp, char __user *ubuf, size_t count, } static const struct file_operations idle_fops = { - .open = stats_open_generic, + .open = simple_open, .read = stats_read_ul, .llseek = default_llseek, }; diff --git a/drivers/iommu/omap-iommu-debug.c b/drivers/iommu/omap-iommu-debug.c index 103dbd92e256..f55fc5dfbadc 100644 --- a/drivers/iommu/omap-iommu-debug.c +++ b/drivers/iommu/omap-iommu-debug.c @@ -323,15 +323,9 @@ err_out: return count; } -static int debug_open_generic(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - #define DEBUG_FOPS(name) \ static const struct file_operations debug_##name##_fops = { \ - .open = debug_open_generic, \ + .open = simple_open, \ .read = debug_read_##name, \ .write = debug_write_##name, \ .llseek = generic_file_llseek, \ @@ -339,7 +333,7 @@ static int debug_open_generic(struct inode *inode, struct file *file) #define DEBUG_FOPS_RO(name) \ static const struct file_operations debug_##name##_fops = { \ - .open = debug_open_generic, \ + .open = simple_open, \ .read = debug_read_##name, \ .llseek = generic_file_llseek, \ }; diff --git a/drivers/mfd/aat2870-core.c b/drivers/mfd/aat2870-core.c index 3aa36eb5c79b..44a3fdbadef4 100644 --- a/drivers/mfd/aat2870-core.c +++ b/drivers/mfd/aat2870-core.c @@ -262,13 +262,6 @@ static ssize_t aat2870_dump_reg(struct aat2870_data *aat2870, char *buf) return count; } -static int aat2870_reg_open_file(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - - return 0; -} - static ssize_t aat2870_reg_read_file(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -330,7 +323,7 @@ static ssize_t aat2870_reg_write_file(struct file *file, } static const struct file_operations aat2870_reg_fops = { - .open = aat2870_reg_open_file, + .open = simple_open, .read = aat2870_reg_read_file, .write = aat2870_reg_write_file, }; diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c index 60107ee166fc..1efad20fb175 100644 --- a/drivers/mfd/ab3100-core.c +++ b/drivers/mfd/ab3100-core.c @@ -483,12 +483,6 @@ struct ab3100_get_set_reg_priv { bool mode; }; -static int ab3100_get_set_reg_open_file(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - static ssize_t ab3100_get_set_reg(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) @@ -583,7 +577,7 @@ static ssize_t ab3100_get_set_reg(struct file *file, } static const struct file_operations ab3100_get_set_reg_fops = { - .open = ab3100_get_set_reg_open_file, + .open = simple_open, .write = ab3100_get_set_reg, .llseek = noop_llseek, }; diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c index 1c034b80d408..6673e578b3e9 100644 --- a/drivers/misc/ibmasm/ibmasmfs.c +++ b/drivers/misc/ibmasm/ibmasmfs.c @@ -500,12 +500,6 @@ static ssize_t r_heartbeat_file_write(struct file *file, const char __user *buf, return 1; } -static int remote_settings_file_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - static int remote_settings_file_close(struct inode *inode, struct file *file) { return 0; @@ -600,7 +594,7 @@ static const struct file_operations r_heartbeat_fops = { }; static const struct file_operations remote_settings_fops = { - .open = remote_settings_file_open, + .open = simple_open, .release = remote_settings_file_close, .read = remote_settings_file_read, .write = remote_settings_file_write, diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c index e2cdebf40840..61af9bb560ab 100644 --- a/drivers/mtd/ubi/debug.c +++ b/drivers/mtd/ubi/debug.c @@ -386,19 +386,11 @@ out: return count; } -static int default_open(struct inode *inode, struct file *file) -{ - if (inode->i_private) - file->private_data = inode->i_private; - - return 0; -} - /* File operations for all UBI debugfs files */ static const struct file_operations dfs_fops = { .read = dfs_file_read, .write = dfs_file_write, - .open = default_open, + .open = simple_open, .llseek = no_llseek, .owner = THIS_MODULE, }; diff --git a/drivers/net/caif/caif_spi.c b/drivers/net/caif/caif_spi.c index 96391c36fa74..b71ce9bf0afb 100644 --- a/drivers/net/caif/caif_spi.c +++ b/drivers/net/caif/caif_spi.c @@ -127,12 +127,6 @@ static inline void dev_debugfs_rem(struct cfspi *cfspi) debugfs_remove(cfspi->dbgfs_dir); } -static int dbgfs_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - static ssize_t dbgfs_state(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -243,13 +237,13 @@ static ssize_t dbgfs_frame(struct file *file, char __user *user_buf, } static const struct file_operations dbgfs_state_fops = { - .open = dbgfs_open, + .open = simple_open, .read = dbgfs_state, .owner = THIS_MODULE }; static const struct file_operations dbgfs_frame_fops = { - .open = dbgfs_open, + .open = simple_open, .read = dbgfs_frame, .owner = THIS_MODULE }; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 05ff076af06d..b126b98065a9 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -2000,13 +2000,6 @@ static const struct ethtool_ops cxgb_ethtool_ops = { /* * debugfs support */ - -static int mem_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - static ssize_t mem_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { @@ -2050,7 +2043,7 @@ static ssize_t mem_read(struct file *file, char __user *buf, size_t count, static const struct file_operations mem_debugfs_fops = { .owner = THIS_MODULE, - .open = mem_open, + .open = simple_open, .read = mem_read, .llseek = default_llseek, }; diff --git a/drivers/net/wimax/i2400m/debugfs.c b/drivers/net/wimax/i2400m/debugfs.c index 129ba36bd04d..4b66ab1d0e5c 100644 --- a/drivers/net/wimax/i2400m/debugfs.c +++ b/drivers/net/wimax/i2400m/debugfs.c @@ -53,17 +53,6 @@ struct dentry *debugfs_create_netdev_queue_stopped( &fops_netdev_queue_stopped); } - -/* - * inode->i_private has the @data argument to debugfs_create_file() - */ -static -int i2400m_stats_open(struct inode *inode, struct file *filp) -{ - filp->private_data = inode->i_private; - return 0; -} - /* * We don't allow partial reads of this file, as then the reader would * get weirdly confused data as it is updated. @@ -117,7 +106,7 @@ ssize_t i2400m_rx_stats_write(struct file *filp, const char __user *buffer, static const struct file_operations i2400m_rx_stats_fops = { .owner = THIS_MODULE, - .open = i2400m_stats_open, + .open = simple_open, .read = i2400m_rx_stats_read, .write = i2400m_rx_stats_write, .llseek = default_llseek, @@ -170,7 +159,7 @@ ssize_t i2400m_tx_stats_write(struct file *filp, const char __user *buffer, static const struct file_operations i2400m_tx_stats_fops = { .owner = THIS_MODULE, - .open = i2400m_stats_open, + .open = simple_open, .read = i2400m_tx_stats_read, .write = i2400m_tx_stats_write, .llseek = default_llseek, diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index 8c5ce8b0c734..e5e8f45d86ac 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c @@ -71,13 +71,6 @@ static unsigned int ath5k_debug; module_param_named(debug, ath5k_debug, uint, 0); -static int ath5k_debugfs_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - - /* debugfs: registers */ struct reg { @@ -265,7 +258,7 @@ static ssize_t write_file_beacon(struct file *file, static const struct file_operations fops_beacon = { .read = read_file_beacon, .write = write_file_beacon, - .open = ath5k_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -285,7 +278,7 @@ static ssize_t write_file_reset(struct file *file, static const struct file_operations fops_reset = { .write = write_file_reset, - .open = ath5k_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = noop_llseek, }; @@ -365,7 +358,7 @@ static ssize_t write_file_debug(struct file *file, static const struct file_operations fops_debug = { .read = read_file_debug, .write = write_file_debug, - .open = ath5k_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -477,7 +470,7 @@ static ssize_t write_file_antenna(struct file *file, static const struct file_operations fops_antenna = { .read = read_file_antenna, .write = write_file_antenna, - .open = ath5k_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -532,7 +525,7 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf, static const struct file_operations fops_misc = { .read = read_file_misc, - .open = ath5k_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, }; @@ -647,7 +640,7 @@ static ssize_t write_file_frameerrors(struct file *file, static const struct file_operations fops_frameerrors = { .read = read_file_frameerrors, .write = write_file_frameerrors, - .open = ath5k_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -810,7 +803,7 @@ static ssize_t write_file_ani(struct file *file, static const struct file_operations fops_ani = { .read = read_file_ani, .write = write_file_ani, - .open = ath5k_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -881,7 +874,7 @@ static ssize_t write_file_queue(struct file *file, static const struct file_operations fops_queue = { .read = read_file_queue, .write = write_file_queue, - .open = ath5k_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c index 552adb3f80d0..d01403a263ff 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.c +++ b/drivers/net/wireless/ath/ath6kl/debug.c @@ -217,12 +217,6 @@ void dump_cred_dist_stats(struct htc_target *target) target->credit_info->cur_free_credits); } -static int ath6kl_debugfs_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - void ath6kl_debug_war(struct ath6kl *ar, enum ath6kl_war war) { switch (war) { @@ -263,7 +257,7 @@ static ssize_t read_file_war_stats(struct file *file, char __user *user_buf, static const struct file_operations fops_war_stats = { .read = read_file_war_stats, - .open = ath6kl_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -488,7 +482,7 @@ static ssize_t ath6kl_fwlog_mask_write(struct file *file, } static const struct file_operations fops_fwlog_mask = { - .open = ath6kl_debugfs_open, + .open = simple_open, .read = ath6kl_fwlog_mask_read, .write = ath6kl_fwlog_mask_write, .owner = THIS_MODULE, @@ -634,7 +628,7 @@ static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf, static const struct file_operations fops_tgt_stats = { .read = read_file_tgt_stats, - .open = ath6kl_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -699,7 +693,7 @@ static ssize_t read_file_credit_dist_stats(struct file *file, static const struct file_operations fops_credit_dist_stats = { .read = read_file_credit_dist_stats, - .open = ath6kl_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -802,7 +796,7 @@ static ssize_t ath6kl_endpoint_stats_write(struct file *file, } static const struct file_operations fops_endpoint_stats = { - .open = ath6kl_debugfs_open, + .open = simple_open, .read = ath6kl_endpoint_stats_read, .write = ath6kl_endpoint_stats_write, .owner = THIS_MODULE, @@ -875,7 +869,7 @@ static ssize_t ath6kl_regread_write(struct file *file, static const struct file_operations fops_diag_reg_read = { .read = ath6kl_regread_read, .write = ath6kl_regread_write, - .open = ath6kl_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -999,7 +993,7 @@ static ssize_t ath6kl_lrssi_roam_read(struct file *file, static const struct file_operations fops_lrssi_roam_threshold = { .read = ath6kl_lrssi_roam_read, .write = ath6kl_lrssi_roam_write, - .open = ath6kl_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -1061,7 +1055,7 @@ static ssize_t ath6kl_regwrite_write(struct file *file, static const struct file_operations fops_diag_reg_write = { .read = ath6kl_regwrite_read, .write = ath6kl_regwrite_write, - .open = ath6kl_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -1166,7 +1160,7 @@ static ssize_t ath6kl_roam_table_read(struct file *file, char __user *user_buf, static const struct file_operations fops_roam_table = { .read = ath6kl_roam_table_read, - .open = ath6kl_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -1204,7 +1198,7 @@ static ssize_t ath6kl_force_roam_write(struct file *file, static const struct file_operations fops_force_roam = { .write = ath6kl_force_roam_write, - .open = ath6kl_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -1244,7 +1238,7 @@ static ssize_t ath6kl_roam_mode_write(struct file *file, static const struct file_operations fops_roam_mode = { .write = ath6kl_roam_mode_write, - .open = ath6kl_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -1286,7 +1280,7 @@ static ssize_t ath6kl_keepalive_write(struct file *file, } static const struct file_operations fops_keepalive = { - .open = ath6kl_debugfs_open, + .open = simple_open, .read = ath6kl_keepalive_read, .write = ath6kl_keepalive_write, .owner = THIS_MODULE, @@ -1331,7 +1325,7 @@ static ssize_t ath6kl_disconnect_timeout_write(struct file *file, } static const struct file_operations fops_disconnect_timeout = { - .open = ath6kl_debugfs_open, + .open = simple_open, .read = ath6kl_disconnect_timeout_read, .write = ath6kl_disconnect_timeout_write, .owner = THIS_MODULE, @@ -1512,7 +1506,7 @@ static ssize_t ath6kl_create_qos_write(struct file *file, static const struct file_operations fops_create_qos = { .write = ath6kl_create_qos_write, - .open = ath6kl_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -1560,7 +1554,7 @@ static ssize_t ath6kl_delete_qos_write(struct file *file, static const struct file_operations fops_delete_qos = { .write = ath6kl_delete_qos_write, - .open = ath6kl_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -1593,7 +1587,7 @@ static ssize_t ath6kl_bgscan_int_write(struct file *file, static const struct file_operations fops_bgscan_int = { .write = ath6kl_bgscan_int_write, - .open = ath6kl_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -1651,7 +1645,7 @@ static ssize_t ath6kl_listen_int_read(struct file *file, static const struct file_operations fops_listen_int = { .read = ath6kl_listen_int_read, .write = ath6kl_listen_int_write, - .open = ath6kl_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -1711,7 +1705,7 @@ static ssize_t ath6kl_power_params_write(struct file *file, static const struct file_operations fops_power_params = { .write = ath6kl_power_params_write, - .open = ath6kl_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 35d1c8e91d1c..ff47b32ecaf4 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -26,11 +26,6 @@ #define REG_READ_D(_ah, _reg) \ ath9k_hw_common(_ah)->ops->read((_ah), (_reg)) -static int ath9k_debugfs_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} static ssize_t ath9k_debugfs_read_buf(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -83,7 +78,7 @@ static ssize_t write_file_debug(struct file *file, const char __user *user_buf, static const struct file_operations fops_debug = { .read = read_file_debug, .write = write_file_debug, - .open = ath9k_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -129,7 +124,7 @@ static ssize_t write_file_tx_chainmask(struct file *file, const char __user *use static const struct file_operations fops_tx_chainmask = { .read = read_file_tx_chainmask, .write = write_file_tx_chainmask, - .open = ath9k_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -172,7 +167,7 @@ static ssize_t write_file_rx_chainmask(struct file *file, const char __user *use static const struct file_operations fops_rx_chainmask = { .read = read_file_rx_chainmask, .write = write_file_rx_chainmask, - .open = ath9k_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -223,7 +218,7 @@ static ssize_t write_file_disable_ani(struct file *file, static const struct file_operations fops_disable_ani = { .read = read_file_disable_ani, .write = write_file_disable_ani, - .open = ath9k_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -324,7 +319,7 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf, static const struct file_operations fops_dma = { .read = read_file_dma, - .open = ath9k_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -446,7 +441,7 @@ static ssize_t read_file_interrupt(struct file *file, char __user *user_buf, static const struct file_operations fops_interrupt = { .read = read_file_interrupt, - .open = ath9k_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -852,28 +847,28 @@ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, static const struct file_operations fops_xmit = { .read = read_file_xmit, - .open = ath9k_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; static const struct file_operations fops_stations = { .read = read_file_stations, - .open = ath9k_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; static const struct file_operations fops_misc = { .read = read_file_misc, - .open = ath9k_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; static const struct file_operations fops_reset = { .read = read_file_reset, - .open = ath9k_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -1016,7 +1011,7 @@ void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs) static const struct file_operations fops_recv = { .read = read_file_recv, - .open = ath9k_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -1055,7 +1050,7 @@ static ssize_t write_file_regidx(struct file *file, const char __user *user_buf, static const struct file_operations fops_regidx = { .read = read_file_regidx, .write = write_file_regidx, - .open = ath9k_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -1102,7 +1097,7 @@ static ssize_t write_file_regval(struct file *file, const char __user *user_buf, static const struct file_operations fops_regval = { .read = read_file_regval, .write = write_file_regval, - .open = ath9k_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -1191,7 +1186,7 @@ static ssize_t read_file_dump_nfcal(struct file *file, char __user *user_buf, static const struct file_operations fops_dump_nfcal = { .read = read_file_dump_nfcal, - .open = ath9k_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -1219,7 +1214,7 @@ static ssize_t read_file_base_eeprom(struct file *file, char __user *user_buf, static const struct file_operations fops_base_eeprom = { .read = read_file_base_eeprom, - .open = ath9k_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -1247,7 +1242,7 @@ static ssize_t read_file_modal_eeprom(struct file *file, char __user *user_buf, static const struct file_operations fops_modal_eeprom = { .read = read_file_modal_eeprom, - .open = ath9k_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; diff --git a/drivers/net/wireless/ath/ath9k/dfs_debug.c b/drivers/net/wireless/ath/ath9k/dfs_debug.c index 106d031d834a..4364c103ed33 100644 --- a/drivers/net/wireless/ath/ath9k/dfs_debug.c +++ b/drivers/net/wireless/ath/ath9k/dfs_debug.c @@ -60,16 +60,9 @@ static ssize_t read_file_dfs(struct file *file, char __user *user_buf, return retval; } -static int ath9k_dfs_debugfs_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - - return 0; -} - static const struct file_operations fops_dfs_stats = { .read = read_file_dfs, - .open = ath9k_dfs_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c index d3ff33c71aa5..3035deb7a0cd 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c @@ -16,12 +16,6 @@ #include "htc.h" -static int ath9k_debugfs_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - static ssize_t read_file_tgt_int_stats(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -75,7 +69,7 @@ static ssize_t read_file_tgt_int_stats(struct file *file, char __user *user_buf, static const struct file_operations fops_tgt_int_stats = { .read = read_file_tgt_int_stats, - .open = ath9k_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -145,7 +139,7 @@ static ssize_t read_file_tgt_tx_stats(struct file *file, char __user *user_buf, static const struct file_operations fops_tgt_tx_stats = { .read = read_file_tgt_tx_stats, - .open = ath9k_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -191,7 +185,7 @@ static ssize_t read_file_tgt_rx_stats(struct file *file, char __user *user_buf, static const struct file_operations fops_tgt_rx_stats = { .read = read_file_tgt_rx_stats, - .open = ath9k_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -243,7 +237,7 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf, static const struct file_operations fops_xmit = { .read = read_file_xmit, - .open = ath9k_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -364,7 +358,7 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf, static const struct file_operations fops_recv = { .read = read_file_recv, - .open = ath9k_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -399,7 +393,7 @@ static ssize_t read_file_slot(struct file *file, char __user *user_buf, static const struct file_operations fops_slot = { .read = read_file_slot, - .open = ath9k_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -446,7 +440,7 @@ static ssize_t read_file_queue(struct file *file, char __user *user_buf, static const struct file_operations fops_queue = { .read = read_file_queue, - .open = ath9k_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -487,7 +481,7 @@ static ssize_t write_file_debug(struct file *file, const char __user *user_buf, static const struct file_operations fops_debug = { .read = read_file_debug, .write = write_file_debug, - .open = ath9k_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -636,7 +630,7 @@ static ssize_t read_file_base_eeprom(struct file *file, char __user *user_buf, static const struct file_operations fops_base_eeprom = { .read = read_file_base_eeprom, - .open = ath9k_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -917,7 +911,7 @@ static ssize_t read_file_modal_eeprom(struct file *file, char __user *user_buf, static const struct file_operations fops_modal_eeprom = { .read = read_file_modal_eeprom, - .open = ath9k_debugfs_open, + .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 4f848493fece..08bb45532701 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1480,12 +1480,6 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband, #ifdef CONFIG_ATH9K_DEBUGFS -static int ath9k_debugfs_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - static ssize_t read_file_rcstat(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -1553,7 +1547,7 @@ static ssize_t read_file_rcstat(struct file *file, char __user *user_buf, static const struct file_operations fops_rcstat = { .read = read_file_rcstat, - .open = ath9k_debugfs_open, + .open = simple_open, .owner = THIS_MODULE }; diff --git a/drivers/net/wireless/ath/carl9170/debug.c b/drivers/net/wireless/ath/carl9170/debug.c index 3c164226687f..93fe6003a493 100644 --- a/drivers/net/wireless/ath/carl9170/debug.c +++ b/drivers/net/wireless/ath/carl9170/debug.c @@ -48,11 +48,6 @@ #define ADD(buf, off, max, fmt, args...) \ off += snprintf(&buf[off], max - off, fmt, ##args); -static int carl9170_debugfs_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} struct carl9170_debugfs_fops { unsigned int read_bufsize; @@ -178,7 +173,7 @@ static const struct carl9170_debugfs_fops carl_debugfs_##name ##_ops = {\ .attr = _attr, \ .req_dev_state = _dstate, \ .fops = { \ - .open = carl9170_debugfs_open, \ + .open = simple_open, \ .read = carl9170_debugfs_read, \ .write = carl9170_debugfs_write, \ .owner = THIS_MODULE \ diff --git a/drivers/net/wireless/b43/debugfs.c b/drivers/net/wireless/b43/debugfs.c index e751fdee89b2..e807bd930647 100644 --- a/drivers/net/wireless/b43/debugfs.c +++ b/drivers/net/wireless/b43/debugfs.c @@ -500,12 +500,6 @@ out: #undef fappend -static int b43_debugfs_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { @@ -624,7 +618,7 @@ out_unlock: .read = _read, \ .write = _write, \ .fops = { \ - .open = b43_debugfs_open, \ + .open = simple_open, \ .read = b43_debugfs_read, \ .write = b43_debugfs_write, \ .llseek = generic_file_llseek, \ diff --git a/drivers/net/wireless/b43legacy/debugfs.c b/drivers/net/wireless/b43legacy/debugfs.c index 5e28ad0d6d17..1965edb765a2 100644 --- a/drivers/net/wireless/b43legacy/debugfs.c +++ b/drivers/net/wireless/b43legacy/debugfs.c @@ -197,12 +197,6 @@ static int restart_write_file(struct b43legacy_wldev *dev, const char *buf, size #undef fappend -static int b43legacy_debugfs_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - static ssize_t b43legacy_debugfs_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { @@ -331,7 +325,7 @@ out_unlock: .read = _read, \ .write = _write, \ .fops = { \ - .open = b43legacy_debugfs_open, \ + .open = simple_open, \ .read = b43legacy_debugfs_read, \ .write = b43legacy_debugfs_write, \ .llseek = generic_file_llseek, \ diff --git a/drivers/net/wireless/iwlegacy/3945-rs.c b/drivers/net/wireless/iwlegacy/3945-rs.c index 70bee1a4d876..4b10157d8686 100644 --- a/drivers/net/wireless/iwlegacy/3945-rs.c +++ b/drivers/net/wireless/iwlegacy/3945-rs.c @@ -821,12 +821,6 @@ out: } #ifdef CONFIG_MAC80211_DEBUGFS -static int -il3945_open_file_generic(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} static ssize_t il3945_sta_dbgfs_stats_table_read(struct file *file, char __user *user_buf, @@ -862,7 +856,7 @@ il3945_sta_dbgfs_stats_table_read(struct file *file, char __user *user_buf, static const struct file_operations rs_sta_dbgfs_stats_table_ops = { .read = il3945_sta_dbgfs_stats_table_read, - .open = il3945_open_file_generic, + .open = simple_open, .llseek = default_llseek, }; diff --git a/drivers/net/wireless/iwlegacy/4965-rs.c b/drivers/net/wireless/iwlegacy/4965-rs.c index d7e2856e41d3..11ab1247fae1 100644 --- a/drivers/net/wireless/iwlegacy/4965-rs.c +++ b/drivers/net/wireless/iwlegacy/4965-rs.c @@ -2518,12 +2518,6 @@ il4965_rs_free_sta(void *il_r, struct ieee80211_sta *sta, void *il_sta) } #ifdef CONFIG_MAC80211_DEBUGFS -static int -il4965_open_file_generic(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} static void il4965_rs_dbgfs_set_mcs(struct il_lq_sta *lq_sta, u32 * rate_n_flags, int idx) @@ -2695,7 +2689,7 @@ il4965_rs_sta_dbgfs_scale_table_read(struct file *file, char __user *user_buf, static const struct file_operations rs_sta_dbgfs_scale_table_ops = { .write = il4965_rs_sta_dbgfs_scale_table_write, .read = il4965_rs_sta_dbgfs_scale_table_read, - .open = il4965_open_file_generic, + .open = simple_open, .llseek = default_llseek, }; @@ -2740,7 +2734,7 @@ il4965_rs_sta_dbgfs_stats_table_read(struct file *file, char __user *user_buf, static const struct file_operations rs_sta_dbgfs_stats_table_ops = { .read = il4965_rs_sta_dbgfs_stats_table_read, - .open = il4965_open_file_generic, + .open = simple_open, .llseek = default_llseek, }; @@ -2768,7 +2762,7 @@ il4965_rs_sta_dbgfs_rate_scale_data_read(struct file *file, static const struct file_operations rs_sta_dbgfs_rate_scale_data_ops = { .read = il4965_rs_sta_dbgfs_rate_scale_data_read, - .open = il4965_open_file_generic, + .open = simple_open, .llseek = default_llseek, }; diff --git a/drivers/net/wireless/iwlegacy/debug.c b/drivers/net/wireless/iwlegacy/debug.c index 229849150aac..eff26501d60a 100644 --- a/drivers/net/wireless/iwlegacy/debug.c +++ b/drivers/net/wireless/iwlegacy/debug.c @@ -160,18 +160,12 @@ static ssize_t il_dbgfs_##name##_write(struct file *file, \ const char __user *user_buf, \ size_t count, loff_t *ppos); -static int -il_dbgfs_open_file_generic(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} #define DEBUGFS_READ_FILE_OPS(name) \ DEBUGFS_READ_FUNC(name); \ static const struct file_operations il_dbgfs_##name##_ops = { \ .read = il_dbgfs_##name##_read, \ - .open = il_dbgfs_open_file_generic, \ + .open = simple_open, \ .llseek = generic_file_llseek, \ }; @@ -179,7 +173,7 @@ static const struct file_operations il_dbgfs_##name##_ops = { \ DEBUGFS_WRITE_FUNC(name); \ static const struct file_operations il_dbgfs_##name##_ops = { \ .write = il_dbgfs_##name##_write, \ - .open = il_dbgfs_open_file_generic, \ + .open = simple_open, \ .llseek = generic_file_llseek, \ }; @@ -189,7 +183,7 @@ static const struct file_operations il_dbgfs_##name##_ops = { \ static const struct file_operations il_dbgfs_##name##_ops = { \ .write = il_dbgfs_##name##_write, \ .read = il_dbgfs_##name##_read, \ - .open = il_dbgfs_open_file_generic, \ + .open = simple_open, \ .llseek = generic_file_llseek, \ }; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 53f8c51cfcdb..7e590b349dd7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -3083,11 +3083,6 @@ static void rs_free_sta(void *priv_r, struct ieee80211_sta *sta, } #ifdef CONFIG_MAC80211_DEBUGFS -static int open_file_generic(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, u32 *rate_n_flags, int index) { @@ -3226,7 +3221,7 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, static const struct file_operations rs_sta_dbgfs_scale_table_ops = { .write = rs_sta_dbgfs_scale_table_write, .read = rs_sta_dbgfs_scale_table_read, - .open = open_file_generic, + .open = simple_open, .llseek = default_llseek, }; static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file, @@ -3269,7 +3264,7 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file, static const struct file_operations rs_sta_dbgfs_stats_table_ops = { .read = rs_sta_dbgfs_stats_table_read, - .open = open_file_generic, + .open = simple_open, .llseek = default_llseek, }; @@ -3295,7 +3290,7 @@ static ssize_t rs_sta_dbgfs_rate_scale_data_read(struct file *file, static const struct file_operations rs_sta_dbgfs_rate_scale_data_ops = { .read = rs_sta_dbgfs_rate_scale_data_read, - .open = open_file_generic, + .open = simple_open, .llseek = default_llseek, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index b7b1c04f2fba..2bbaebd99ad4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -84,17 +84,11 @@ static ssize_t iwl_dbgfs_##name##_write(struct file *file, \ size_t count, loff_t *ppos); -static int iwl_dbgfs_open_file_generic(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - #define DEBUGFS_READ_FILE_OPS(name) \ DEBUGFS_READ_FUNC(name); \ static const struct file_operations iwl_dbgfs_##name##_ops = { \ .read = iwl_dbgfs_##name##_read, \ - .open = iwl_dbgfs_open_file_generic, \ + .open = simple_open, \ .llseek = generic_file_llseek, \ }; @@ -102,7 +96,7 @@ static const struct file_operations iwl_dbgfs_##name##_ops = { \ DEBUGFS_WRITE_FUNC(name); \ static const struct file_operations iwl_dbgfs_##name##_ops = { \ .write = iwl_dbgfs_##name##_write, \ - .open = iwl_dbgfs_open_file_generic, \ + .open = simple_open, \ .llseek = generic_file_llseek, \ }; @@ -113,7 +107,7 @@ static const struct file_operations iwl_dbgfs_##name##_ops = { \ static const struct file_operations iwl_dbgfs_##name##_ops = { \ .write = iwl_dbgfs_##name##_write, \ .read = iwl_dbgfs_##name##_read, \ - .open = iwl_dbgfs_open_file_generic, \ + .open = simple_open, \ .llseek = generic_file_llseek, \ }; diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c index b4f796c82e1e..4d7b30d3e648 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c @@ -1898,17 +1898,11 @@ static ssize_t iwl_dbgfs_##name##_write(struct file *file, \ size_t count, loff_t *ppos); -static int iwl_dbgfs_open_file_generic(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - #define DEBUGFS_READ_FILE_OPS(name) \ DEBUGFS_READ_FUNC(name); \ static const struct file_operations iwl_dbgfs_##name##_ops = { \ .read = iwl_dbgfs_##name##_read, \ - .open = iwl_dbgfs_open_file_generic, \ + .open = simple_open, \ .llseek = generic_file_llseek, \ }; @@ -1916,7 +1910,7 @@ static const struct file_operations iwl_dbgfs_##name##_ops = { \ DEBUGFS_WRITE_FUNC(name); \ static const struct file_operations iwl_dbgfs_##name##_ops = { \ .write = iwl_dbgfs_##name##_write, \ - .open = iwl_dbgfs_open_file_generic, \ + .open = simple_open, \ .llseek = generic_file_llseek, \ }; @@ -1926,7 +1920,7 @@ static const struct file_operations iwl_dbgfs_##name##_ops = { \ static const struct file_operations iwl_dbgfs_##name##_ops = { \ .write = iwl_dbgfs_##name##_write, \ .read = iwl_dbgfs_##name##_read, \ - .open = iwl_dbgfs_open_file_generic, \ + .open = simple_open, \ .llseek = generic_file_llseek, \ }; diff --git a/drivers/net/wireless/iwmc3200wifi/debugfs.c b/drivers/net/wireless/iwmc3200wifi/debugfs.c index 87eef5773a02..b6199d124bb9 100644 --- a/drivers/net/wireless/iwmc3200wifi/debugfs.c +++ b/drivers/net/wireless/iwmc3200wifi/debugfs.c @@ -99,12 +99,6 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_iwm_dbg_modules, iwm_debugfs_u32_read, iwm_debugfs_dbg_modules_write, "%llu\n"); -static int iwm_generic_open(struct inode *inode, struct file *filp) -{ - filp->private_data = inode->i_private; - return 0; -} - static ssize_t iwm_debugfs_txq_read(struct file *filp, char __user *buffer, size_t count, loff_t *ppos) @@ -401,28 +395,28 @@ out: static const struct file_operations iwm_debugfs_txq_fops = { .owner = THIS_MODULE, - .open = iwm_generic_open, + .open = simple_open, .read = iwm_debugfs_txq_read, .llseek = default_llseek, }; static const struct file_operations iwm_debugfs_tx_credit_fops = { .owner = THIS_MODULE, - .open = iwm_generic_open, + .open = simple_open, .read = iwm_debugfs_tx_credit_read, .llseek = default_llseek, }; static const struct file_operations iwm_debugfs_rx_ticket_fops = { .owner = THIS_MODULE, - .open = iwm_generic_open, + .open = simple_open, .read = iwm_debugfs_rx_ticket_read, .llseek = default_llseek, }; static const struct file_operations iwm_debugfs_fw_err_fops = { .owner = THIS_MODULE, - .open = iwm_generic_open, + .open = simple_open, .read = iwm_debugfs_fw_err_read, .llseek = default_llseek, }; diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.c b/drivers/net/wireless/iwmc3200wifi/sdio.c index 764b40dd24ad..0042f204b07f 100644 --- a/drivers/net/wireless/iwmc3200wifi/sdio.c +++ b/drivers/net/wireless/iwmc3200wifi/sdio.c @@ -264,13 +264,6 @@ static int if_sdio_send_chunk(struct iwm_priv *iwm, u8 *buf, int count) return ret; } -/* debugfs hooks */ -static int iwm_debugfs_sdio_open(struct inode *inode, struct file *filp) -{ - filp->private_data = inode->i_private; - return 0; -} - static ssize_t iwm_debugfs_sdio_read(struct file *filp, char __user *buffer, size_t count, loff_t *ppos) { @@ -363,7 +356,7 @@ err: static const struct file_operations iwm_debugfs_sdio_fops = { .owner = THIS_MODULE, - .open = iwm_debugfs_sdio_open, + .open = simple_open, .read = iwm_debugfs_sdio_read, .llseek = default_llseek, }; diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index c192671610fc..a06cc283e23d 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -21,12 +21,6 @@ static char *szStates[] = { static void lbs_debug_init(struct lbs_private *priv); #endif -static int open_file_generic(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - static ssize_t write_file_dummy(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { @@ -696,7 +690,7 @@ out_unlock: #define FOPS(fread, fwrite) { \ .owner = THIS_MODULE, \ - .open = open_file_generic, \ + .open = simple_open, \ .read = (fread), \ .write = (fwrite), \ .llseek = generic_file_llseek, \ @@ -962,7 +956,7 @@ static ssize_t lbs_debugfs_write(struct file *f, const char __user *buf, static const struct file_operations lbs_debug_fops = { .owner = THIS_MODULE, - .open = open_file_generic, + .open = simple_open, .write = lbs_debugfs_write, .read = lbs_debugfs_read, .llseek = default_llseek, diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c index d26a78b6b3c4..1a845074c52a 100644 --- a/drivers/net/wireless/mwifiex/debugfs.c +++ b/drivers/net/wireless/mwifiex/debugfs.c @@ -139,18 +139,6 @@ static struct mwifiex_debug_data items[] = { static int num_of_items = ARRAY_SIZE(items); -/* - * Generic proc file open handler. - * - * This function is called every time a file is accessed for read or write. - */ -static int -mwifiex_open_generic(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - /* * Proc info file read handler. * @@ -676,19 +664,19 @@ done: static const struct file_operations mwifiex_dfs_##name##_fops = { \ .read = mwifiex_##name##_read, \ .write = mwifiex_##name##_write, \ - .open = mwifiex_open_generic, \ + .open = simple_open, \ }; #define MWIFIEX_DFS_FILE_READ_OPS(name) \ static const struct file_operations mwifiex_dfs_##name##_fops = { \ .read = mwifiex_##name##_read, \ - .open = mwifiex_open_generic, \ + .open = simple_open, \ }; #define MWIFIEX_DFS_FILE_WRITE_OPS(name) \ static const struct file_operations mwifiex_dfs_##name##_fops = { \ .write = mwifiex_##name##_write, \ - .open = mwifiex_open_generic, \ + .open = simple_open, \ }; diff --git a/drivers/net/wireless/wl1251/debugfs.c b/drivers/net/wireless/wl1251/debugfs.c index 6c274007d200..448da1f8c22f 100644 --- a/drivers/net/wireless/wl1251/debugfs.c +++ b/drivers/net/wireless/wl1251/debugfs.c @@ -47,7 +47,7 @@ static ssize_t name## _read(struct file *file, char __user *userbuf, \ \ static const struct file_operations name## _ops = { \ .read = name## _read, \ - .open = wl1251_open_file_generic, \ + .open = simple_open, \ .llseek = generic_file_llseek, \ }; @@ -84,7 +84,7 @@ static ssize_t sub## _ ##name## _read(struct file *file, \ \ static const struct file_operations sub## _ ##name## _ops = { \ .read = sub## _ ##name## _read, \ - .open = wl1251_open_file_generic, \ + .open = simple_open, \ .llseek = generic_file_llseek, \ }; @@ -117,12 +117,6 @@ out: mutex_unlock(&wl->mutex); } -static int wl1251_open_file_generic(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - DEBUGFS_FWSTATS_FILE(tx, internal_desc_overflow, 20, "%u"); DEBUGFS_FWSTATS_FILE(rx, out_of_mem, 20, "%u"); @@ -235,7 +229,7 @@ static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf, static const struct file_operations tx_queue_len_ops = { .read = tx_queue_len_read, - .open = wl1251_open_file_generic, + .open = simple_open, .llseek = generic_file_llseek, }; @@ -257,7 +251,7 @@ static ssize_t tx_queue_status_read(struct file *file, char __user *userbuf, static const struct file_operations tx_queue_status_ops = { .read = tx_queue_status_read, - .open = wl1251_open_file_generic, + .open = simple_open, .llseek = generic_file_llseek, }; diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c index e1cf72765965..564d49575c94 100644 --- a/drivers/net/wireless/wl12xx/debugfs.c +++ b/drivers/net/wireless/wl12xx/debugfs.c @@ -63,7 +63,7 @@ static ssize_t name## _read(struct file *file, char __user *userbuf, \ \ static const struct file_operations name## _ops = { \ .read = name## _read, \ - .open = wl1271_open_file_generic, \ + .open = simple_open, \ .llseek = generic_file_llseek, \ }; @@ -96,7 +96,7 @@ static ssize_t sub## _ ##name## _read(struct file *file, \ \ static const struct file_operations sub## _ ##name## _ops = { \ .read = sub## _ ##name## _read, \ - .open = wl1271_open_file_generic, \ + .open = simple_open, \ .llseek = generic_file_llseek, \ }; @@ -126,12 +126,6 @@ out: mutex_unlock(&wl->mutex); } -static int wl1271_open_file_generic(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - DEBUGFS_FWSTATS_FILE(tx, internal_desc_overflow, "%u"); DEBUGFS_FWSTATS_FILE(rx, out_of_mem, "%u"); @@ -243,7 +237,7 @@ static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf, static const struct file_operations tx_queue_len_ops = { .read = tx_queue_len_read, - .open = wl1271_open_file_generic, + .open = simple_open, .llseek = default_llseek, }; @@ -289,7 +283,7 @@ static ssize_t gpio_power_write(struct file *file, static const struct file_operations gpio_power_ops = { .read = gpio_power_read, .write = gpio_power_write, - .open = wl1271_open_file_generic, + .open = simple_open, .llseek = default_llseek, }; @@ -308,7 +302,7 @@ static ssize_t start_recovery_write(struct file *file, static const struct file_operations start_recovery_ops = { .write = start_recovery_write, - .open = wl1271_open_file_generic, + .open = simple_open, .llseek = default_llseek, }; @@ -372,7 +366,7 @@ out: static const struct file_operations dynamic_ps_timeout_ops = { .read = dynamic_ps_timeout_read, .write = dynamic_ps_timeout_write, - .open = wl1271_open_file_generic, + .open = simple_open, .llseek = default_llseek, }; @@ -441,7 +435,7 @@ out: static const struct file_operations forced_ps_ops = { .read = forced_ps_read, .write = forced_ps_write, - .open = wl1271_open_file_generic, + .open = simple_open, .llseek = default_llseek, }; @@ -483,7 +477,7 @@ static ssize_t split_scan_timeout_write(struct file *file, static const struct file_operations split_scan_timeout_ops = { .read = split_scan_timeout_read, .write = split_scan_timeout_write, - .open = wl1271_open_file_generic, + .open = simple_open, .llseek = default_llseek, }; @@ -566,7 +560,7 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf, static const struct file_operations driver_state_ops = { .read = driver_state_read, - .open = wl1271_open_file_generic, + .open = simple_open, .llseek = default_llseek, }; @@ -675,7 +669,7 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf, static const struct file_operations vifs_state_ops = { .read = vifs_state_read, - .open = wl1271_open_file_generic, + .open = simple_open, .llseek = default_llseek, }; @@ -733,7 +727,7 @@ static ssize_t dtim_interval_write(struct file *file, static const struct file_operations dtim_interval_ops = { .read = dtim_interval_read, .write = dtim_interval_write, - .open = wl1271_open_file_generic, + .open = simple_open, .llseek = default_llseek, }; @@ -791,7 +785,7 @@ static ssize_t suspend_dtim_interval_write(struct file *file, static const struct file_operations suspend_dtim_interval_ops = { .read = suspend_dtim_interval_read, .write = suspend_dtim_interval_write, - .open = wl1271_open_file_generic, + .open = simple_open, .llseek = default_llseek, }; @@ -849,7 +843,7 @@ static ssize_t beacon_interval_write(struct file *file, static const struct file_operations beacon_interval_ops = { .read = beacon_interval_read, .write = beacon_interval_write, - .open = wl1271_open_file_generic, + .open = simple_open, .llseek = default_llseek, }; @@ -904,7 +898,7 @@ static ssize_t rx_streaming_interval_read(struct file *file, static const struct file_operations rx_streaming_interval_ops = { .read = rx_streaming_interval_read, .write = rx_streaming_interval_write, - .open = wl1271_open_file_generic, + .open = simple_open, .llseek = default_llseek, }; @@ -959,7 +953,7 @@ static ssize_t rx_streaming_always_read(struct file *file, static const struct file_operations rx_streaming_always_ops = { .read = rx_streaming_always_read, .write = rx_streaming_always_write, - .open = wl1271_open_file_generic, + .open = simple_open, .llseek = default_llseek, }; @@ -1003,7 +997,7 @@ out: static const struct file_operations beacon_filtering_ops = { .write = beacon_filtering_write, - .open = wl1271_open_file_generic, + .open = simple_open, .llseek = default_llseek, }; diff --git a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c index ee8fd037bb53..849357c1045c 100644 --- a/drivers/oprofile/oprofilefs.c +++ b/drivers/oprofile/oprofilefs.c @@ -117,25 +117,17 @@ static ssize_t ulong_write_file(struct file *file, char const __user *buf, size_ } -static int default_open(struct inode *inode, struct file *filp) -{ - if (inode->i_private) - filp->private_data = inode->i_private; - return 0; -} - - static const struct file_operations ulong_fops = { .read = ulong_read_file, .write = ulong_write_file, - .open = default_open, + .open = simple_open, .llseek = default_llseek, }; static const struct file_operations ulong_ro_fops = { .read = ulong_read_file, - .open = default_open, + .open = simple_open, .llseek = default_llseek, }; @@ -187,7 +179,7 @@ static ssize_t atomic_read_file(struct file *file, char __user *buf, size_t coun static const struct file_operations atomic_ro_fops = { .read = atomic_read_file, - .open = default_open, + .open = simple_open, .llseek = default_llseek, }; diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c index 70277a530133..85d31a69e117 100644 --- a/drivers/remoteproc/remoteproc_debugfs.c +++ b/drivers/remoteproc/remoteproc_debugfs.c @@ -50,16 +50,9 @@ static ssize_t rproc_trace_read(struct file *filp, char __user *userbuf, return simple_read_from_buffer(userbuf, count, ppos, trace->va, len); } -static int rproc_open_generic(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - - return 0; -} - static const struct file_operations trace_rproc_ops = { .read = rproc_trace_read, - .open = rproc_open_generic, + .open = simple_open, .llseek = generic_file_llseek, }; @@ -94,7 +87,7 @@ static ssize_t rproc_state_read(struct file *filp, char __user *userbuf, static const struct file_operations rproc_state_ops = { .read = rproc_state_read, - .open = rproc_open_generic, + .open = simple_open, .llseek = generic_file_llseek, }; @@ -114,7 +107,7 @@ static ssize_t rproc_name_read(struct file *filp, char __user *userbuf, static const struct file_operations rproc_name_ops = { .read = rproc_name_read, - .open = rproc_open_generic, + .open = simple_open, .llseek = generic_file_llseek, }; diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index 22e17be04d8a..34f7cf76bf4f 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -997,13 +997,6 @@ lpfc_debugfs_dumpDataDif_write(struct file *file, const char __user *buf, return nbytes; } -static int -lpfc_debugfs_dif_err_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - static ssize_t lpfc_debugfs_dif_err_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) @@ -3521,7 +3514,7 @@ static const struct file_operations lpfc_debugfs_op_dumpDif = { #undef lpfc_debugfs_op_dif_err static const struct file_operations lpfc_debugfs_op_dif_err = { .owner = THIS_MODULE, - .open = lpfc_debugfs_dif_err_open, + .open = simple_open, .llseek = lpfc_debugfs_lseek, .read = lpfc_debugfs_dif_err_read, .write = lpfc_debugfs_dif_err_write, diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index 082458d73ce9..d1a495f64e2d 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -63,12 +63,6 @@ struct chip_data { }; #ifdef CONFIG_DEBUG_FS -static int spi_show_regs_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - #define SPI_REGS_BUFSIZE 1024 static ssize_t spi_show_regs(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -128,7 +122,7 @@ static ssize_t spi_show_regs(struct file *file, char __user *user_buf, static const struct file_operations mrst_spi_regs_ops = { .owner = THIS_MODULE, - .open = spi_show_regs_open, + .open = simple_open, .read = spi_show_regs, .llseek = default_llseek, }; diff --git a/drivers/tty/serial/mfd.c b/drivers/tty/serial/mfd.c index a9234ba8f8d5..c4b50af46c44 100644 --- a/drivers/tty/serial/mfd.c +++ b/drivers/tty/serial/mfd.c @@ -127,11 +127,6 @@ static inline void serial_out(struct uart_hsu_port *up, int offset, int value) #define HSU_REGS_BUFSIZE 1024 -static int hsu_show_regs_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} static ssize_t port_show_regs(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -231,14 +226,14 @@ static ssize_t dma_show_regs(struct file *file, char __user *user_buf, static const struct file_operations port_regs_ops = { .owner = THIS_MODULE, - .open = hsu_show_regs_open, + .open = simple_open, .read = port_show_regs, .llseek = default_llseek, }; static const struct file_operations dma_regs_ops = { .owner = THIS_MODULE, - .open = hsu_show_regs_open, + .open = simple_open, .read = dma_show_regs, .llseek = default_llseek, }; diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 332f2eb8abbc..46ec722b4406 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -304,11 +304,7 @@ static const int trigger_level_1[4] = { 1, 1, 1, 1 }; #ifdef CONFIG_DEBUG_FS #define PCH_REGS_BUFSIZE 1024 -static int pch_show_regs_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} + static ssize_t port_show_regs(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -362,7 +358,7 @@ static ssize_t port_show_regs(struct file *file, char __user *user_buf, static const struct file_operations port_regs_ops = { .owner = THIS_MODULE, - .open = pch_show_regs_open, + .open = simple_open, .read = port_show_regs, .llseek = default_llseek, }; diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index cefa0c8b5b6a..d2b9af59cba9 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -428,18 +428,10 @@ static loff_t default_file_lseek (struct file *file, loff_t offset, int orig) return retval; } -static int default_open (struct inode *inode, struct file *file) -{ - if (inode->i_private) - file->private_data = inode->i_private; - - return 0; -} - static const struct file_operations default_file_operations = { .read = default_read_file, .write = default_write_file, - .open = default_open, + .open = simple_open, .llseek = default_file_lseek, }; diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index fd9109d7eb0e..680e1a31fb87 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -352,7 +352,6 @@ static int debug_async_open(struct inode *, struct file *); static int debug_periodic_open(struct inode *, struct file *); static int debug_registers_open(struct inode *, struct file *); static int debug_async_open(struct inode *, struct file *); -static int debug_lpm_open(struct inode *, struct file *); static ssize_t debug_lpm_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos); static ssize_t debug_lpm_write(struct file *file, const char __user *buffer, @@ -385,7 +384,7 @@ static const struct file_operations debug_registers_fops = { }; static const struct file_operations debug_lpm_fops = { .owner = THIS_MODULE, - .open = debug_lpm_open, + .open = simple_open, .read = debug_lpm_read, .write = debug_lpm_write, .release = debug_lpm_close, @@ -970,12 +969,6 @@ static int debug_registers_open(struct inode *inode, struct file *file) return file->private_data ? 0 : -ENOMEM; } -static int debug_lpm_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - static int debug_lpm_close(struct inode *inode, struct file *file) { return 0; diff --git a/drivers/uwb/uwb-debug.c b/drivers/uwb/uwb-debug.c index 2eecec0c13c9..6ec45beb7af5 100644 --- a/drivers/uwb/uwb-debug.c +++ b/drivers/uwb/uwb-debug.c @@ -159,13 +159,6 @@ static int cmd_ie_rm(struct uwb_rc *rc, struct uwb_dbg_cmd_ie *ie_to_rm) return uwb_rc_ie_rm(rc, ie_to_rm->data[0]); } -static int command_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - - return 0; -} - static ssize_t command_write(struct file *file, const char __user *buf, size_t len, loff_t *off) { @@ -206,7 +199,7 @@ static ssize_t command_write(struct file *file, const char __user *buf, } static const struct file_operations command_fops = { - .open = command_open, + .open = simple_open, .write = command_write, .read = NULL, .llseek = no_llseek, diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index 21e93605161c..5dfafdd1dbd3 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -33,18 +33,10 @@ static ssize_t default_write_file(struct file *file, const char __user *buf, return count; } -static int default_open(struct inode *inode, struct file *file) -{ - if (inode->i_private) - file->private_data = inode->i_private; - - return 0; -} - const struct file_operations debugfs_file_operations = { .read = default_read_file, .write = default_write_file, - .open = default_open, + .open = simple_open, .llseek = noop_llseek, }; @@ -447,7 +439,7 @@ static ssize_t write_file_bool(struct file *file, const char __user *user_buf, static const struct file_operations fops_bool = { .read = read_file_bool, .write = write_file_bool, - .open = default_open, + .open = simple_open, .llseek = default_llseek, }; @@ -492,7 +484,7 @@ static ssize_t read_file_blob(struct file *file, char __user *user_buf, static const struct file_operations fops_blob = { .read = read_file_blob, - .open = default_open, + .open = simple_open, .llseek = default_llseek, }; diff --git a/fs/dlm/debug_fs.c b/fs/dlm/debug_fs.c index 3dca2b39e83f..1c9b08095f98 100644 --- a/fs/dlm/debug_fs.c +++ b/fs/dlm/debug_fs.c @@ -609,13 +609,6 @@ static const struct file_operations format3_fops = { /* * dump lkb's on the ls_waiters list */ - -static int waiters_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - static ssize_t waiters_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { @@ -644,7 +637,7 @@ static ssize_t waiters_read(struct file *file, char __user *userbuf, static const struct file_operations waiters_fops = { .owner = THIS_MODULE, - .open = waiters_open, + .open = simple_open, .read = waiters_read, .llseek = default_llseek, }; diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c index f37c32b94525..8ae5a03376ae 100644 --- a/fs/pstore/inode.c +++ b/fs/pstore/inode.c @@ -52,12 +52,6 @@ struct pstore_private { char data[]; }; -static int pstore_file_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - static ssize_t pstore_file_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { @@ -67,7 +61,7 @@ static ssize_t pstore_file_read(struct file *file, char __user *userbuf, } static const struct file_operations pstore_file_operations = { - .open = pstore_file_open, + .open = simple_open, .read = pstore_file_read, .llseek = default_llseek, }; diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c index cdea7b56b0c9..c0bd0308741c 100644 --- a/kernel/trace/blktrace.c +++ b/kernel/trace/blktrace.c @@ -311,13 +311,6 @@ int blk_trace_remove(struct request_queue *q) } EXPORT_SYMBOL_GPL(blk_trace_remove); -static int blk_dropped_open(struct inode *inode, struct file *filp) -{ - filp->private_data = inode->i_private; - - return 0; -} - static ssize_t blk_dropped_read(struct file *filp, char __user *buffer, size_t count, loff_t *ppos) { @@ -331,18 +324,11 @@ static ssize_t blk_dropped_read(struct file *filp, char __user *buffer, static const struct file_operations blk_dropped_fops = { .owner = THIS_MODULE, - .open = blk_dropped_open, + .open = simple_open, .read = blk_dropped_read, .llseek = default_llseek, }; -static int blk_msg_open(struct inode *inode, struct file *filp) -{ - filp->private_data = inode->i_private; - - return 0; -} - static ssize_t blk_msg_write(struct file *filp, const char __user *buffer, size_t count, loff_t *ppos) { @@ -371,7 +357,7 @@ static ssize_t blk_msg_write(struct file *filp, const char __user *buffer, static const struct file_operations blk_msg_fops = { .owner = THIS_MODULE, - .open = blk_msg_open, + .open = simple_open, .write = blk_msg_write, .llseek = noop_llseek, }; diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index cc5b7a6e7e0b..778e5916d7c3 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -15,12 +15,6 @@ #include "rate.h" #include "debugfs.h" -int mac80211_open_file_generic(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - #define DEBUGFS_FORMAT_BUFFER_SIZE 100 int mac80211_format_buffer(char __user *userbuf, size_t count, @@ -50,7 +44,7 @@ static ssize_t name## _read(struct file *file, char __user *userbuf, \ #define DEBUGFS_READONLY_FILE_OPS(name) \ static const struct file_operations name## _ops = { \ .read = name## _read, \ - .open = mac80211_open_file_generic, \ + .open = simple_open, \ .llseek = generic_file_llseek, \ }; @@ -93,7 +87,7 @@ static ssize_t reset_write(struct file *file, const char __user *user_buf, static const struct file_operations reset_ops = { .write = reset_write, - .open = mac80211_open_file_generic, + .open = simple_open, .llseek = noop_llseek, }; @@ -254,7 +248,7 @@ static ssize_t stats_ ##name## _read(struct file *file, \ \ static const struct file_operations stats_ ##name## _ops = { \ .read = stats_ ##name## _read, \ - .open = mac80211_open_file_generic, \ + .open = simple_open, \ .llseek = generic_file_llseek, \ }; diff --git a/net/mac80211/debugfs.h b/net/mac80211/debugfs.h index 7c87529630f5..9be4e6d71d00 100644 --- a/net/mac80211/debugfs.h +++ b/net/mac80211/debugfs.h @@ -3,7 +3,6 @@ #ifdef CONFIG_MAC80211_DEBUGFS extern void debugfs_hw_add(struct ieee80211_local *local); -extern int mac80211_open_file_generic(struct inode *inode, struct file *file); extern int mac80211_format_buffer(char __user *userbuf, size_t count, loff_t *ppos, char *fmt, ...); #else diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index 59edcd95a58d..7932767bb482 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c @@ -30,7 +30,7 @@ static ssize_t key_##name##_read(struct file *file, \ #define KEY_OPS(name) \ static const struct file_operations key_ ##name## _ops = { \ .read = key_##name##_read, \ - .open = mac80211_open_file_generic, \ + .open = simple_open, \ .llseek = generic_file_llseek, \ } @@ -45,7 +45,7 @@ static const struct file_operations key_ ##name## _ops = { \ #define KEY_CONF_OPS(name) \ static const struct file_operations key_ ##name## _ops = { \ .read = key_conf_##name##_read, \ - .open = mac80211_open_file_generic, \ + .open = simple_open, \ .llseek = generic_file_llseek, \ } diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index a32eeda04aa3..30f99c344847 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -135,7 +135,7 @@ static ssize_t ieee80211_if_read_##name(struct file *file, \ static const struct file_operations name##_ops = { \ .read = ieee80211_if_read_##name, \ .write = (_write), \ - .open = mac80211_open_file_generic, \ + .open = simple_open, \ .llseek = generic_file_llseek, \ } diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 6d45804d09bc..832b2da5e4cd 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -33,7 +33,7 @@ static ssize_t sta_ ##name## _read(struct file *file, \ #define STA_OPS(name) \ static const struct file_operations sta_ ##name## _ops = { \ .read = sta_##name##_read, \ - .open = mac80211_open_file_generic, \ + .open = simple_open, \ .llseek = generic_file_llseek, \ } @@ -41,7 +41,7 @@ static const struct file_operations sta_ ##name## _ops = { \ static const struct file_operations sta_ ##name## _ops = { \ .read = sta_##name##_read, \ .write = sta_##name##_write, \ - .open = mac80211_open_file_generic, \ + .open = simple_open, \ .llseek = generic_file_llseek, \ } diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index b4f7600a3e36..3313c117b322 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -145,7 +145,7 @@ static ssize_t rcname_read(struct file *file, char __user *userbuf, static const struct file_operations rcname_ops = { .read = rcname_read, - .open = mac80211_open_file_generic, + .open = simple_open, .llseek = default_llseek, }; #endif diff --git a/net/wireless/debugfs.c b/net/wireless/debugfs.c index 39765bcfb472..920cabe0461b 100644 --- a/net/wireless/debugfs.c +++ b/net/wireless/debugfs.c @@ -13,12 +13,6 @@ #include "core.h" #include "debugfs.h" -static int cfg80211_open_file_generic(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - #define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...) \ static ssize_t name## _read(struct file *file, char __user *userbuf, \ size_t count, loff_t *ppos) \ @@ -33,7 +27,7 @@ static ssize_t name## _read(struct file *file, char __user *userbuf, \ \ static const struct file_operations name## _ops = { \ .read = name## _read, \ - .open = cfg80211_open_file_generic, \ + .open = simple_open, \ .llseek = generic_file_llseek, \ }; @@ -102,7 +96,7 @@ static ssize_t ht40allow_map_read(struct file *file, static const struct file_operations ht40allow_map_ops = { .read = ht40allow_map_read, - .open = cfg80211_open_file_generic, + .open = simple_open, .llseek = default_llseek, }; diff --git a/sound/soc/imx/imx-audmux.c b/sound/soc/imx/imx-audmux.c index 601df809a26a..1765a197acb0 100644 --- a/sound/soc/imx/imx-audmux.c +++ b/sound/soc/imx/imx-audmux.c @@ -40,12 +40,6 @@ static void __iomem *audmux_base; #ifdef CONFIG_DEBUG_FS static struct dentry *audmux_debugfs_root; -static int audmux_open_file(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - /* There is an annoying discontinuity in the SSI numbering with regard * to the Linux number of the devices */ static const char *audmux_port_string(int port) @@ -142,7 +136,7 @@ static ssize_t audmux_read_file(struct file *file, char __user *user_buf, } static const struct file_operations audmux_debugfs_fops = { - .open = audmux_open_file, + .open = simple_open, .read = audmux_read_file, .llseek = default_llseek, }; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index a4deebc0801a..e19c24ade414 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -201,12 +201,6 @@ static ssize_t pmdown_time_set(struct device *dev, static DEVICE_ATTR(pmdown_time, 0644, pmdown_time_show, pmdown_time_set); #ifdef CONFIG_DEBUG_FS -static int codec_reg_open_file(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - static ssize_t codec_reg_read_file(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -264,7 +258,7 @@ static ssize_t codec_reg_write_file(struct file *file, } static const struct file_operations codec_reg_fops = { - .open = codec_reg_open_file, + .open = simple_open, .read = codec_reg_read_file, .write = codec_reg_write_file, .llseek = default_llseek, diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 6241490fff30..5cbd2d7623b8 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1544,12 +1544,6 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) } #ifdef CONFIG_DEBUG_FS -static int dapm_widget_power_open_file(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - static ssize_t dapm_widget_power_read_file(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -1613,17 +1607,11 @@ static ssize_t dapm_widget_power_read_file(struct file *file, } static const struct file_operations dapm_widget_power_fops = { - .open = dapm_widget_power_open_file, + .open = simple_open, .read = dapm_widget_power_read_file, .llseek = default_llseek, }; -static int dapm_bias_open_file(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - static ssize_t dapm_bias_read_file(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -1654,7 +1642,7 @@ static ssize_t dapm_bias_read_file(struct file *file, char __user *user_buf, } static const struct file_operations dapm_bias_fops = { - .open = dapm_bias_open_file, + .open = simple_open, .read = dapm_bias_read_file, .llseek = default_llseek, }; -- cgit v1.2.3 From 6ede3d832aaa038e7465e677569f7acc96b4dcdf Mon Sep 17 00:00:00 2001 From: Ashish Jangam Date: Thu, 5 Apr 2012 14:25:15 -0700 Subject: backlight: add driver for DA9052/53 PMIC v1 DA9052/53 PMIC has capability to supply power for upto 3 banks of 6 white serial LEDS. It can also control intensity of independent banks and to drive these banks boost converter will provide up to 24V and forward current of max 50mA. This patch allows to control intensity of the individual WLEDs bank through DA9052/53 PMIC. This patch is functionally tested on Samsung SMDKV6410. Signed-off-by: David Dajun Chen Signed-off-by: Ashish Jangam Cc: Richard Purdie Cc: Samuel Ortiz Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/backlight/Kconfig | 6 ++ drivers/video/backlight/Makefile | 1 + drivers/video/backlight/da9052_bl.c | 187 ++++++++++++++++++++++++++++++++++++ 3 files changed, 194 insertions(+) create mode 100644 drivers/video/backlight/da9052_bl.c (limited to 'drivers') diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 7ed9991fa747..af16884491ed 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -245,6 +245,12 @@ config BACKLIGHT_DA903X If you have a LCD backlight connected to the WLED output of DA9030 or DA9034 WLED output, say Y here to enable this driver. +config BACKLIGHT_DA9052 + tristate "Dialog DA9052/DA9053 WLED" + depends on PMIC_DA9052 + help + Enable the Backlight Driver for DA9052-BC and DA9053-AA/Bx PMICs. + config BACKLIGHT_MAX8925 tristate "Backlight driver for MAX8925" depends on MFD_MAX8925 diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index 8071eb656147..36855ae887d6 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_BACKLIGHT_PROGEAR) += progear_bl.o obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH) += cr_bllcd.o obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.o obj-$(CONFIG_BACKLIGHT_DA903X) += da903x_bl.o +obj-$(CONFIG_BACKLIGHT_DA9052) += da9052_bl.o obj-$(CONFIG_BACKLIGHT_MAX8925) += max8925_bl.o obj-$(CONFIG_BACKLIGHT_APPLE) += apple_bl.o obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o diff --git a/drivers/video/backlight/da9052_bl.c b/drivers/video/backlight/da9052_bl.c new file mode 100644 index 000000000000..b628d68f5162 --- /dev/null +++ b/drivers/video/backlight/da9052_bl.c @@ -0,0 +1,187 @@ +/* + * Backlight Driver for Dialog DA9052 PMICs + * + * Copyright(c) 2012 Dialog Semiconductor Ltd. + * + * Author: David Dajun Chen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include + +#include +#include + +#define DA9052_MAX_BRIGHTNESS 0xFF + +enum { + DA9052_WLEDS_OFF, + DA9052_WLEDS_ON, +}; + +enum { + DA9052_TYPE_WLED1, + DA9052_TYPE_WLED2, + DA9052_TYPE_WLED3, +}; + +static unsigned char wled_bank[] = { + DA9052_LED1_CONF_REG, + DA9052_LED2_CONF_REG, + DA9052_LED3_CONF_REG, +}; + +struct da9052_bl { + struct da9052 *da9052; + uint brightness; + uint state; + uint led_reg; +}; + +static int da9052_adjust_wled_brightness(struct da9052_bl *wleds) +{ + unsigned char boost_en; + unsigned char i_sink; + int ret; + + boost_en = 0x3F; + i_sink = 0xFF; + if (wleds->state == DA9052_WLEDS_OFF) { + boost_en = 0x00; + i_sink = 0x00; + } + + ret = da9052_reg_write(wleds->da9052, DA9052_BOOST_REG, boost_en); + if (ret < 0) + return ret; + + ret = da9052_reg_write(wleds->da9052, DA9052_LED_CONT_REG, i_sink); + if (ret < 0) + return ret; + + ret = da9052_reg_write(wleds->da9052, wled_bank[wleds->led_reg], 0x0); + if (ret < 0) + return ret; + + msleep(10); + + if (wleds->brightness) { + ret = da9052_reg_write(wleds->da9052, wled_bank[wleds->led_reg], + wleds->brightness); + if (ret < 0) + return ret; + } + + return 0; +} + +static int da9052_backlight_update_status(struct backlight_device *bl) +{ + int brightness = bl->props.brightness; + struct da9052_bl *wleds = bl_get_data(bl); + + wleds->brightness = brightness; + wleds->state = DA9052_WLEDS_ON; + + return da9052_adjust_wled_brightness(wleds); +} + +static int da9052_backlight_get_brightness(struct backlight_device *bl) +{ + struct da9052_bl *wleds = bl_get_data(bl); + + return wleds->brightness; +} + +static const struct backlight_ops da9052_backlight_ops = { + .update_status = da9052_backlight_update_status, + .get_brightness = da9052_backlight_get_brightness, +}; + +static int da9052_backlight_probe(struct platform_device *pdev) +{ + struct backlight_device *bl; + struct backlight_properties props; + struct da9052_bl *wleds; + + wleds = devm_kzalloc(&pdev->dev, sizeof(struct da9052_bl), GFP_KERNEL); + if (!wleds) + return -ENOMEM; + + wleds->da9052 = dev_get_drvdata(pdev->dev.parent); + wleds->brightness = 0; + wleds->led_reg = platform_get_device_id(pdev)->driver_data; + wleds->state = DA9052_WLEDS_OFF; + + props.type = BACKLIGHT_RAW; + props.max_brightness = DA9052_MAX_BRIGHTNESS; + + bl = backlight_device_register(pdev->name, wleds->da9052->dev, wleds, + &da9052_backlight_ops, &props); + if (IS_ERR(bl)) { + dev_err(&pdev->dev, "Failed to register backlight\n"); + devm_kfree(&pdev->dev, wleds); + return PTR_ERR(bl); + } + + bl->props.max_brightness = DA9052_MAX_BRIGHTNESS; + bl->props.brightness = 0; + platform_set_drvdata(pdev, bl); + + return da9052_adjust_wled_brightness(wleds); +} + +static int da9052_backlight_remove(struct platform_device *pdev) +{ + struct backlight_device *bl = platform_get_drvdata(pdev); + struct da9052_bl *wleds = bl_get_data(bl); + + wleds->brightness = 0; + wleds->state = DA9052_WLEDS_OFF; + da9052_adjust_wled_brightness(wleds); + backlight_device_unregister(bl); + devm_kfree(&pdev->dev, wleds); + + return 0; +} + +static struct platform_device_id da9052_wled_ids[] = { + { + .name = "da9052-wled1", + .driver_data = DA9052_TYPE_WLED1, + }, + { + .name = "da9052-wled2", + .driver_data = DA9052_TYPE_WLED2, + }, + { + .name = "da9052-wled3", + .driver_data = DA9052_TYPE_WLED3, + }, +}; + +static struct platform_driver da9052_wled_driver = { + .probe = da9052_backlight_probe, + .remove = da9052_backlight_remove, + .id_table = da9052_wled_ids, + .driver = { + .name = "da9052-wled", + .owner = THIS_MODULE, + }, +}; + +module_platform_driver(da9052_wled_driver); + +MODULE_AUTHOR("David Dajun Chen "); +MODULE_DESCRIPTION("Backlight driver for DA9052 PMIC"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:da9052-backlight"); -- cgit v1.2.3 From 5a4309746cd74734daa964acb02690c22b3c8911 Mon Sep 17 00:00:00 2001 From: Veaceslav Falico Date: Thu, 5 Apr 2012 03:47:43 +0000 Subject: bonding: properly unset current_arp_slave on slave link up When a slave comes up, we're unsetting the current_arp_slave without removing active flags from it, which can lead to situations where we have more than one slave with active flags in active-backup mode. To avoid this situation we must remove the active flags from a slave before removing it as a current_arp_slave. Signed-off-by: Veaceslav Falico Signed-off-by: Jay Vosburgh Signed-off-by: Andy Gospodarek Signed-off-by: Marcelo Ricardo Leitner Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index fc8a8d5c4dbd..62d2409bb293 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3010,7 +3010,11 @@ static void bond_ab_arp_commit(struct bonding *bond, int delta_in_ticks) trans_start + delta_in_ticks)) || bond->curr_active_slave != slave) { slave->link = BOND_LINK_UP; - bond->current_arp_slave = NULL; + if (bond->current_arp_slave) { + bond_set_slave_inactive_flags( + bond->current_arp_slave); + bond->current_arp_slave = NULL; + } pr_info("%s: link status definitely up for interface %s.\n", bond->dev->name, slave->dev->name); -- cgit v1.2.3 From 3119936a289db88cf749143fa5ef6b4a4712e3c0 Mon Sep 17 00:00:00 2001 From: Thomas Abraham Date: Thu, 16 Feb 2012 22:23:58 +0900 Subject: mmc: sdhci-s3c: Remove usage of clk_type member in platform data SDHCI controllers on Exynos4 do not include the sdclk divider as per the sdhci controller specification. This case can be represented using the sdhci quirk SDHCI_QUIRK_NONSTANDARD_CLOCK instead of using an additional enum type definition 'clk_types'. Hence, usage of clk_type member in platform data is removed and the sdhci quirk is used. In addition to that, since this qurik is SoC specific, driver data is introduced to represent controllers on SoC's that require this quirk. Cc: Ben Dooks Cc: Jeongbae Seo Signed-off-by: Thomas Abraham Signed-off-by: Kukjin Kim Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci-s3c.c | 74 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 70 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index b19e7d435f8d..5fce14385910 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -53,6 +53,18 @@ struct sdhci_s3c { struct clk *clk_bus[MAX_BUS_CLK]; }; +/** + * struct sdhci_s3c_driver_data - S3C SDHCI platform specific driver data + * @sdhci_quirks: sdhci host specific quirks. + * + * Specifies platform specific configuration of sdhci controller. + * Note: A structure for driver specific platform data is used for future + * expansion of its usage. + */ +struct sdhci_s3c_drv_data { + unsigned int sdhci_quirks; +}; + static inline struct sdhci_s3c *to_s3c(struct sdhci_host *host) { return sdhci_priv(host); @@ -132,10 +144,10 @@ static unsigned int sdhci_s3c_consider_clock(struct sdhci_s3c *ourhost, return UINT_MAX; /* - * Clock divider's step is different as 1 from that of host controller - * when 'clk_type' is S3C_SDHCI_CLK_DIV_EXTERNAL. + * If controller uses a non-standard clock division, find the best clock + * speed possible with selected clock source and skip the division. */ - if (ourhost->pdata->clk_type) { + if (ourhost->host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) { rate = clk_round_rate(clksrc, wanted); return wanted - rate; } @@ -272,6 +284,8 @@ static unsigned int sdhci_cmu_get_min_clock(struct sdhci_host *host) static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock) { struct sdhci_s3c *ourhost = to_s3c(host); + unsigned long timeout; + u16 clk = 0; /* don't bother if the clock is going off */ if (clock == 0) @@ -282,6 +296,25 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock) clk_set_rate(ourhost->clk_bus[ourhost->cur_clk], clock); host->clock = clock; + + clk = SDHCI_CLOCK_INT_EN; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); + + /* Wait max 20 ms */ + timeout = 20; + while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL)) + & SDHCI_CLOCK_INT_STABLE)) { + if (timeout == 0) { + printk(KERN_ERR "%s: Internal clock never " + "stabilised.\n", mmc_hostname(host->mmc)); + return; + } + timeout--; + mdelay(1); + } + + clk |= SDHCI_CLOCK_CARD_EN; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); } /** @@ -382,9 +415,17 @@ static void sdhci_s3c_setup_card_detect_gpio(struct sdhci_s3c *sc) } } +static inline struct sdhci_s3c_drv_data *sdhci_s3c_get_driver_data( + struct platform_device *pdev) +{ + return (struct sdhci_s3c_drv_data *) + platform_get_device_id(pdev)->driver_data; +} + static int __devinit sdhci_s3c_probe(struct platform_device *pdev) { struct s3c_sdhci_platdata *pdata = pdev->dev.platform_data; + struct sdhci_s3c_drv_data *drv_data; struct device *dev = &pdev->dev; struct sdhci_host *host; struct sdhci_s3c *sc; @@ -414,6 +455,7 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) return PTR_ERR(host); } + drv_data = sdhci_s3c_get_driver_data(pdev); sc = sdhci_priv(host); sc->host = host; @@ -491,6 +533,8 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) /* Setup quirks for the controller */ host->quirks |= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC; host->quirks |= SDHCI_QUIRK_NO_HISPD_BIT; + if (drv_data) + host->quirks |= drv_data->sdhci_quirks; #ifndef CONFIG_MMC_SDHCI_S3C_DMA @@ -531,7 +575,7 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) * If controller does not have internal clock divider, * we can use overriding functions instead of default. */ - if (pdata->clk_type) { + if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) { sdhci_s3c_ops.set_clock = sdhci_cmu_set_clock; sdhci_s3c_ops.get_min_clock = sdhci_cmu_get_min_clock; sdhci_s3c_ops.get_max_clock = sdhci_cmu_get_max_clock; @@ -647,9 +691,31 @@ static const struct dev_pm_ops sdhci_s3c_pmops = { #define SDHCI_S3C_PMOPS NULL #endif +#if defined(CONFIG_CPU_EXYNOS4210) || defined(CONFIG_SOC_EXYNOS4212) +static struct sdhci_s3c_drv_data exynos4_sdhci_drv_data = { + .sdhci_quirks = SDHCI_QUIRK_NONSTANDARD_CLOCK, +}; +#define EXYNOS4_SDHCI_DRV_DATA ((kernel_ulong_t)&exynos4_sdhci_drv_data) +#else +#define EXYNOS4_SDHCI_DRV_DATA ((kernel_ulong_t)NULL) +#endif + +static struct platform_device_id sdhci_s3c_driver_ids[] = { + { + .name = "s3c-sdhci", + .driver_data = (kernel_ulong_t)NULL, + }, { + .name = "exynos4-sdhci", + .driver_data = EXYNOS4_SDHCI_DRV_DATA, + }, + { } +}; +MODULE_DEVICE_TABLE(platform, sdhci_s3c_driver_ids); + static struct platform_driver sdhci_s3c_driver = { .probe = sdhci_s3c_probe, .remove = __devexit_p(sdhci_s3c_remove), + .id_table = sdhci_s3c_driver_ids, .driver = { .owner = THIS_MODULE, .name = "s3c-sdhci", -- cgit v1.2.3 From 0d22c77089c86416324d0d87e7ef8cfa931e53cd Mon Sep 17 00:00:00 2001 From: Thomas Abraham Date: Sat, 31 Mar 2012 23:29:45 -0400 Subject: mmc: sdhci-s3c: derive transfer width host cap from max_width in platdata max_width member in platform data can be used to derive the mmc bus transfer width that can be supported by the controller. Signed-off-by: Thomas Abraham Signed-off-by: Kukjin Kim Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci-s3c.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index 5fce14385910..dab1a770cb8a 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -562,6 +562,14 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) if (pdata->cd_type == S3C_SDHCI_CD_PERMANENT) host->mmc->caps = MMC_CAP_NONREMOVABLE; + switch (pdata->max_width) { + case 8: + host->mmc->caps |= MMC_CAP_8_BIT_DATA; + case 4: + host->mmc->caps |= MMC_CAP_4_BIT_DATA; + break; + } + if (pdata->pm_caps) host->mmc->pm_caps |= pdata->pm_caps; -- cgit v1.2.3 From 1d4dc338bb7cbbadcb5a527b1b0e897b5cde1701 Mon Sep 17 00:00:00 2001 From: Thomas Abraham Date: Thu, 16 Feb 2012 22:23:59 +0900 Subject: mmc: sdhci-s3c: Keep a copy of platform data and use it The platform data is copied into driver's private data and the copy is used for all access to the platform data. This simpifies the addition of device tree support for the sdhci-s3c driver. Signed-off-by: Thomas Abraham Signed-off-by: Kukjin Kim Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci-s3c.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index dab1a770cb8a..e81a0339ab5c 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -424,7 +424,7 @@ static inline struct sdhci_s3c_drv_data *sdhci_s3c_get_driver_data( static int __devinit sdhci_s3c_probe(struct platform_device *pdev) { - struct s3c_sdhci_platdata *pdata = pdev->dev.platform_data; + struct s3c_sdhci_platdata *pdata; struct sdhci_s3c_drv_data *drv_data; struct device *dev = &pdev->dev; struct sdhci_host *host; @@ -432,7 +432,7 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) struct resource *res; int ret, irq, ptr, clks; - if (!pdata) { + if (!pdev->dev.platform_data) { dev_err(dev, "no device data specified\n"); return -ENOENT; } @@ -455,6 +455,13 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) return PTR_ERR(host); } + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + ret = -ENOMEM; + goto err_io_clk; + } + memcpy(pdata, pdev->dev.platform_data, sizeof(*pdata)); + drv_data = sdhci_s3c_get_driver_data(pdev); sc = sdhci_priv(host); -- cgit v1.2.3 From 9bda6da7ff7d35ef757e235aae559e679d3a9493 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Thu, 8 Mar 2012 23:24:53 -0500 Subject: mmc: sdhci-s3c: use devm_ functions The various devm_ functions allocate memory that is released when a driver detaches. This patch uses these functions for data that is allocated in the probe function of a platform device and is only freed in the remove function. By using devm_ioremap, it also removes a potential memory leak, because there was no call to iounmap in the probe function. The call to platform_get_resource was moved just to make it closer to the place where its result it used. Signed-off-by: Julia Lawall Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci-s3c.c | 27 +++------------------------ 1 file changed, 3 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index e81a0339ab5c..c3144cb21325 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -443,12 +443,6 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) return irq; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "no memory specified\n"); - return -ENOENT; - } - host = sdhci_alloc_host(dev, sizeof(struct sdhci_s3c)); if (IS_ERR(host)) { dev_err(dev, "sdhci_alloc_host() failed\n"); @@ -513,15 +507,8 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) goto err_no_busclks; } - sc->ioarea = request_mem_region(res->start, resource_size(res), - mmc_hostname(host->mmc)); - if (!sc->ioarea) { - dev_err(dev, "failed to reserve register area\n"); - ret = -ENXIO; - goto err_req_regs; - } - - host->ioaddr = ioremap_nocache(res->start, resource_size(res)); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + host->ioaddr = devm_request_and_ioremap(&pdev->dev, res); if (!host->ioaddr) { dev_err(dev, "failed to map registers\n"); ret = -ENXIO; @@ -606,7 +593,7 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) ret = sdhci_add_host(host); if (ret) { dev_err(dev, "sdhci_add_host() failed\n"); - goto err_add_host; + goto err_req_regs; } /* The following two methods of card detection might call @@ -620,10 +607,6 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) return 0; - err_add_host: - release_resource(sc->ioarea); - kfree(sc->ioarea); - err_req_regs: for (ptr = 0; ptr < MAX_BUS_CLK; ptr++) { if (sc->clk_bus[ptr]) { @@ -669,10 +652,6 @@ static int __devexit sdhci_s3c_remove(struct platform_device *pdev) clk_disable(sc->clk_io); clk_put(sc->clk_io); - iounmap(host->ioaddr); - release_resource(sc->ioarea); - kfree(sc->ioarea); - sdhci_free_host(host); platform_set_drvdata(pdev, NULL); -- cgit v1.2.3 From d5e9c02cab60920d5ac16a8244bb6085dc27564f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 3 Mar 2012 00:46:41 +0000 Subject: mmc: sdhci-s3c: Use CONFIG_PM_SLEEP to ifdef system suspend This matches current best practice as one can have runtime PM enabled without system sleep and CONFIG_PM is defined for both. Signed-off-by: Mark Brown Acked-by: Jaehoon Chung Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci-s3c.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index c3144cb21325..2ea3e6b8bd6a 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -20,6 +20,9 @@ #include #include #include +#include +#include +#include #include @@ -658,8 +661,7 @@ static int __devexit sdhci_s3c_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM - +#ifdef CONFIG_PM_SLEEP static int sdhci_s3c_suspend(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); @@ -673,10 +675,11 @@ static int sdhci_s3c_resume(struct device *dev) return sdhci_resume_host(host); } +#endif +#ifdef CONFIG_PM static const struct dev_pm_ops sdhci_s3c_pmops = { - .suspend = sdhci_s3c_suspend, - .resume = sdhci_s3c_resume, + SET_SYSTEM_SLEEP_PM_OPS(sdhci_s3c_suspend, sdhci_s3c_resume) }; #define SDHCI_S3C_PMOPS (&sdhci_s3c_pmops) -- cgit v1.2.3 From 9f4e8151dbbc4ca4d5dd7792666a50c137102204 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 31 Mar 2012 23:31:55 -0400 Subject: mmc: sdhci-s3c: Enable runtime power management Since most of the work is already done by the core we just need to add runtime suspend methods and tell the PM core that runtime PM is enabled for this device. Signed-off-by: Mark Brown Acked-by: Jaehoon Chung Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci-s3c.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index 2ea3e6b8bd6a..55a164fcaa15 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -593,9 +594,16 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) if (pdata->host_caps2) host->mmc->caps2 |= pdata->host_caps2; + pm_runtime_enable(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, 50); + pm_runtime_use_autosuspend(&pdev->dev); + pm_suspend_ignore_children(&pdev->dev, 1); + ret = sdhci_add_host(host); if (ret) { dev_err(dev, "sdhci_add_host() failed\n"); + pm_runtime_forbid(&pdev->dev); + pm_runtime_get_noresume(&pdev->dev); goto err_req_regs; } @@ -646,6 +654,8 @@ static int __devexit sdhci_s3c_remove(struct platform_device *pdev) sdhci_remove_host(host, 1); + pm_runtime_disable(&pdev->dev); + for (ptr = 0; ptr < 3; ptr++) { if (sc->clk_bus[ptr]) { clk_disable(sc->clk_bus[ptr]); @@ -677,9 +687,27 @@ static int sdhci_s3c_resume(struct device *dev) } #endif +#ifdef CONFIG_PM_RUNTIME +static int sdhci_s3c_runtime_suspend(struct device *dev) +{ + struct sdhci_host *host = dev_get_drvdata(dev); + + return sdhci_runtime_suspend_host(host); +} + +static int sdhci_s3c_runtime_resume(struct device *dev) +{ + struct sdhci_host *host = dev_get_drvdata(dev); + + return sdhci_runtime_resume_host(host); +} +#endif + #ifdef CONFIG_PM static const struct dev_pm_ops sdhci_s3c_pmops = { SET_SYSTEM_SLEEP_PM_OPS(sdhci_s3c_suspend, sdhci_s3c_resume) + SET_RUNTIME_PM_OPS(sdhci_s3c_runtime_suspend, sdhci_s3c_runtime_resume, + NULL) }; #define SDHCI_S3C_PMOPS (&sdhci_s3c_pmops) -- cgit v1.2.3 From 66292ad92c6d3f2f1c137a1c826b331ca8595dfd Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Wed, 28 Mar 2012 12:28:33 +0200 Subject: mmc: atmel-mci: correct data timeout computation The HSMCI operates at a rate of up to Master Clock divided by two. Moreover previous calculation can cause overflows and so wrong timeouts. Signed-off-by: Ludovic Desroches Acked-by: Nicolas Ferre Cc: Signed-off-by: Chris Ball --- drivers/mmc/host/atmel-mci.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 9819dc09ce08..34080f590f69 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -482,7 +482,14 @@ err: static inline unsigned int atmci_ns_to_clocks(struct atmel_mci *host, unsigned int ns) { - return (ns * (host->bus_hz / 1000000) + 999) / 1000; + /* + * It is easier here to use us instead of ns for the timeout, + * it prevents from overflows during calculation. + */ + unsigned int us = DIV_ROUND_UP(ns, 1000); + + /* Maximum clock frequency is host->bus_hz/2 */ + return us * (DIV_ROUND_UP(host->bus_hz, 2000000)); } static void atmci_set_timeout(struct atmel_mci *host, -- cgit v1.2.3 From 33ab4bbbdf6c60a8c196b5a28215a93aa2a4ed2e Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Wed, 21 Mar 2012 16:41:22 +0100 Subject: mmc: atmel-mci: r/w proof capability only available since v2xx Signed-off-by: Ludovic Desroches Acked-by: Nicolas Ferre Signed-off-by: Chris Ball --- drivers/mmc/host/atmel-mci.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 34080f590f69..c56edc4a8e26 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -2023,6 +2023,8 @@ static void __init atmci_get_cap(struct atmel_mci *host) /* keep only major version number */ switch (version & 0xf00) { case 0x100: + host->caps.has_pdc = 1; + break; case 0x200: host->caps.has_pdc = 1; host->caps.has_rwproof = 1; -- cgit v1.2.3 From faf8180b20882b52145b96d6d4ed082d41908f90 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Wed, 21 Mar 2012 16:41:23 +0100 Subject: mmc: atmel-mci: add support for odd clock dividers Add an odd clock divider capability available from v5xx. It also involves changing the clock divider calculation, and changing the switch-case statement to use top-down fallthrough. Signed-off-by: Ludovic Desroches Acked-by: Nicolas Ferre Signed-off-by: Chris Ball --- drivers/mmc/host/atmel-mci-regs.h | 1 + drivers/mmc/host/atmel-mci.c | 48 +++++++++++++++++++++++---------------- 2 files changed, 30 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/atmel-mci-regs.h b/drivers/mmc/host/atmel-mci-regs.h index 000b3ad0f5ca..787aba1682bb 100644 --- a/drivers/mmc/host/atmel-mci-regs.h +++ b/drivers/mmc/host/atmel-mci-regs.h @@ -31,6 +31,7 @@ # define ATMCI_MR_PDCFBYTE ( 1 << 13) /* Force Byte Transfer */ # define ATMCI_MR_PDCPADV ( 1 << 14) /* Padding Value */ # define ATMCI_MR_PDCMODE ( 1 << 15) /* PDC-oriented Mode */ +# define ATMCI_MR_CLKODD(x) ((x) << 16) /* LSB of Clock Divider */ #define ATMCI_DTOR 0x0008 /* Data Timeout */ # define ATMCI_DTOCYC(x) ((x) << 0) /* Data Timeout Cycles */ # define ATMCI_DTOMUL(x) ((x) << 4) /* Data Timeout Multiplier */ diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index c56edc4a8e26..e94476beca18 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -77,6 +77,7 @@ struct atmel_mci_caps { bool has_cstor_reg; bool has_highspeed; bool has_rwproof; + bool has_odd_clk_div; }; struct atmel_mci_dma { @@ -1134,16 +1135,27 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) } /* Calculate clock divider */ - clkdiv = DIV_ROUND_UP(host->bus_hz, 2 * clock_min) - 1; - if (clkdiv > 255) { - dev_warn(&mmc->class_dev, - "clock %u too slow; using %lu\n", - clock_min, host->bus_hz / (2 * 256)); - clkdiv = 255; + if (host->caps.has_odd_clk_div) { + clkdiv = DIV_ROUND_UP(host->bus_hz, clock_min) - 2; + if (clkdiv > 511) { + dev_warn(&mmc->class_dev, + "clock %u too slow; using %lu\n", + clock_min, host->bus_hz / (511 + 2)); + clkdiv = 511; + } + host->mode_reg = ATMCI_MR_CLKDIV(clkdiv >> 1) + | ATMCI_MR_CLKODD(clkdiv & 1); + } else { + clkdiv = DIV_ROUND_UP(host->bus_hz, 2 * clock_min) - 1; + if (clkdiv > 255) { + dev_warn(&mmc->class_dev, + "clock %u too slow; using %lu\n", + clock_min, host->bus_hz / (2 * 256)); + clkdiv = 255; + } + host->mode_reg = ATMCI_MR_CLKDIV(clkdiv); } - host->mode_reg = ATMCI_MR_CLKDIV(clkdiv); - /* * WRPROOF and RDPROOF prevent overruns/underruns by * stopping the clock when the FIFO is full/empty. @@ -2014,37 +2026,35 @@ static void __init atmci_get_cap(struct atmel_mci *host) "version: 0x%x\n", version); host->caps.has_dma = 0; - host->caps.has_pdc = 0; + host->caps.has_pdc = 1; host->caps.has_cfg_reg = 0; host->caps.has_cstor_reg = 0; host->caps.has_highspeed = 0; host->caps.has_rwproof = 0; + host->caps.has_odd_clk_div = 0; /* keep only major version number */ switch (version & 0xf00) { - case 0x100: - host->caps.has_pdc = 1; - break; - case 0x200: - host->caps.has_pdc = 1; - host->caps.has_rwproof = 1; - break; - case 0x300: - case 0x400: case 0x500: + host->caps.has_odd_clk_div = 1; + case 0x400: + case 0x300: #ifdef CONFIG_AT_HDMAC host->caps.has_dma = 1; #else - host->caps.has_dma = 0; dev_info(&host->pdev->dev, "has dma capability but dma engine is not selected, then use pio\n"); #endif + host->caps.has_pdc = 0; host->caps.has_cfg_reg = 1; host->caps.has_cstor_reg = 1; host->caps.has_highspeed = 1; + case 0x200: host->caps.has_rwproof = 1; + case 0x100: break; default: + host->caps.has_pdc = 0; dev_warn(&host->pdev->dev, "Unmanaged mci version, set minimum capabilities\n"); break; -- cgit v1.2.3 From 5865f2876baa5c68fd0d50029dd220ce19f3d2af Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 22 Mar 2012 11:47:26 +0100 Subject: mmc: block: Remove use of mmc_blk_set_blksize According to the specifications for SD and (e)MMC default blocksize (named BLOCKLEN in Spec.) must always be 512 bytes. Since we hardcoded to always use 512 bytes, we do not explicitly have to set it. Future improvements should potentially make it possible to use a greater blocksize than 512 bytes, but until then let's skip this. Signed-off-by: Ulf Hansson Reviewed-by: Subhash Jadavani Signed-off-by: Chris Ball --- drivers/mmc/card/block.c | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index eed213a5c8cb..b1809650b7aa 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -1623,24 +1623,6 @@ static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md) return ret; } -static int -mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card) -{ - int err; - - mmc_claim_host(card->host); - err = mmc_set_blocklen(card, 512); - mmc_release_host(card->host); - - if (err) { - pr_err("%s: unable to set block size to 512: %d\n", - md->disk->disk_name, err); - return -EINVAL; - } - - return 0; -} - static void mmc_blk_remove_req(struct mmc_blk_data *md) { struct mmc_card *card; @@ -1768,7 +1750,6 @@ static const struct mmc_fixup blk_fixups[] = static int mmc_blk_probe(struct mmc_card *card) { struct mmc_blk_data *md, *part_md; - int err; char cap_str[10]; /* @@ -1781,10 +1762,6 @@ static int mmc_blk_probe(struct mmc_card *card) if (IS_ERR(md)) return PTR_ERR(md); - err = mmc_blk_set_blksize(md, card); - if (err) - goto out; - string_get_size((u64)get_capacity(md->disk) << 9, STRING_UNITS_2, cap_str, sizeof(cap_str)); pr_info("%s: %s %s %s %s\n", @@ -1809,7 +1786,7 @@ static int mmc_blk_probe(struct mmc_card *card) out: mmc_blk_remove_parts(card, md); mmc_blk_remove_req(md); - return err; + return 0; } static void mmc_blk_remove(struct mmc_card *card) @@ -1845,8 +1822,6 @@ static int mmc_blk_resume(struct mmc_card *card) struct mmc_blk_data *md = mmc_get_drvdata(card); if (md) { - mmc_blk_set_blksize(md, card); - /* * Resume involves the card going into idle state, * so current partition is always the main one. -- cgit v1.2.3 From f93882570496aa02ba8a47bfaf81cce43046b978 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Wed, 28 Mar 2012 18:01:09 +0900 Subject: mmc: sh_mmcif: double clock speed Correct an off-by one error when calculating the clock divisor in cases where the host clock is a power of two of the target clock. Previously the divisor was one greater than the correct value in these cases leading to the clock being set at half the desired speed. Thanks to Guennadi Liakhovetski for working with me on the logic for this change. Tested-by: Cao Minh Hiep Acked-by: Guennadi Liakhovetski Signed-off-by: Simon Horman Signed-off-by: Chris Ball --- drivers/mmc/host/sh_mmcif.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index aafaf0b6eb1c..d79c6430c164 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -454,7 +454,8 @@ static void sh_mmcif_clock_control(struct sh_mmcif_host *host, unsigned int clk) sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_SUP_PCLK); else sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR & - ((fls(host->clk / clk) - 1) << 16)); + ((fls(DIV_ROUND_UP(host->clk, + clk) - 1) - 1) << 16)); sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_ENABLE); } -- cgit v1.2.3 From 930f152cc9998388031af577843baae572ac8ab6 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Wed, 28 Mar 2012 18:01:10 +0900 Subject: mmc: sh_mmcif: mmc->f_max should be half of the bus clock mmc->f_max should be half of the bus clock. And now that mmc->f_max is not equal to the bus clock the latter should be used directly to calculate mmc->f_min. Cc: Magnus Damm Tested-by: Cao Minh Hiep Acked-by: Guennadi Liakhovetski Signed-off-by: Simon Horman Signed-off-by: Chris Ball --- drivers/mmc/host/sh_mmcif.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index d79c6430c164..4bb999ed335d 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -1298,14 +1298,14 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev) spin_lock_init(&host->lock); mmc->ops = &sh_mmcif_ops; - mmc->f_max = host->clk; + mmc->f_max = host->clk / 2; /* close to 400KHz */ - if (mmc->f_max < 51200000) - mmc->f_min = mmc->f_max / 128; - else if (mmc->f_max < 102400000) - mmc->f_min = mmc->f_max / 256; + if (host->clk < 51200000) + mmc->f_min = host->clk / 128; + else if (host->clk < 102400000) + mmc->f_min = host->clk / 256; else - mmc->f_min = mmc->f_max / 512; + mmc->f_min = host->clk / 512; if (pd->ocr) mmc->ocr_avail = pd->ocr; mmc->caps = MMC_CAP_MMC_HIGHSPEED; -- cgit v1.2.3 From eb91b9118db8c05a5a1257b594b021d32b491254 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Wed, 28 Mar 2012 18:01:11 +0900 Subject: mmc: sh_mmcif: Simplify calculation of mmc->f_min There is no need to tune mmc->f_min to a value near 400kHz as the MMC core begins testing frequencies at 400kHz regardless of the value of mmc->f_min. As suggested by Guennadi Liakhovetski. Cc: Magnus Damm Acked-by: Guennadi Liakhovetski Tested-by: Cao Minh Hiep Signed-off-by: Simon Horman Signed-off-by: Chris Ball --- drivers/mmc/host/sh_mmcif.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 4bb999ed335d..724b35e85a26 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -1299,13 +1299,7 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev) mmc->ops = &sh_mmcif_ops; mmc->f_max = host->clk / 2; - /* close to 400KHz */ - if (host->clk < 51200000) - mmc->f_min = host->clk / 128; - else if (host->clk < 102400000) - mmc->f_min = host->clk / 256; - else - mmc->f_min = host->clk / 512; + mmc->f_min = host->clk / 512; if (pd->ocr) mmc->ocr_avail = pd->ocr; mmc->caps = MMC_CAP_MMC_HIGHSPEED; -- cgit v1.2.3 From 210b7d28598e402548b0164ca2f543e15aab8c6e Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Thu, 29 Mar 2012 19:05:04 +0200 Subject: mmc: sdhci-pci: add quirks for broken MSI on O2Micro controllers MSI on my O2Micro OZ600 SD card reader is broken. This patch adds a quirk to disable MSI on these controllers. Signed-off-by: Manuel Lauss Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci-pci.c | 4 +++- include/linux/mmc/sdhci.h | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index fbbebe251e01..9303f7fc1e68 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -561,6 +561,7 @@ static int jmicron_resume(struct sdhci_pci_chip *chip) static const struct sdhci_pci_fixes sdhci_o2 = { .probe = o2_probe, + .quirks2 = SDHCI_QUIRK2_BROKEN_MSI, }; static const struct sdhci_pci_fixes sdhci_jmicron = { @@ -1418,7 +1419,8 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev, slots = chip->num_slots; /* Quirk may have changed this */ - pci_enable_msi(pdev); + if (!(chip->quirks2 & SDHCI_QUIRK2_BROKEN_MSI)) + pci_enable_msi(pdev); for (i = 0; i < slots; i++) { slot = sdhci_pci_probe_slot(pdev, chip, first_bar, i); diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h index e9051e1cb1ce..9752fe434ae9 100644 --- a/include/linux/mmc/sdhci.h +++ b/include/linux/mmc/sdhci.h @@ -91,6 +91,8 @@ struct sdhci_host { unsigned int quirks2; /* More deviations from spec. */ #define SDHCI_QUIRK2_HOST_OFF_CARD_ON (1<<0) +/* broken MSI Interrupts */ +#define SDHCI_QUIRK2_BROKEN_MSI (1<<1) int irq; /* Device IRQ */ void __iomem *ioaddr; /* Mapped address */ -- cgit v1.2.3 From 6500c8ed957ac7b1ff37045ba6a2ad39ab2a8dbc Mon Sep 17 00:00:00 2001 From: Subhash Jadavani Date: Fri, 30 Mar 2012 12:10:18 +0530 Subject: mmc: bus: print bus speed mode of UHS-I card When UHS-I card is detected also print the bus speed mode in which UHS-I card will be running. Signed-off-by: Subhash Jadavani Reviewed-by: Namjae Jeon Acked-by: Aaron Lu Signed-off-by: Chris Ball --- drivers/mmc/core/bus.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 5d011a39dfff..3f606068d552 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -267,6 +267,15 @@ int mmc_add_card(struct mmc_card *card) { int ret; const char *type; + const char *uhs_bus_speed_mode = ""; + static const char *const uhs_speeds[] = { + [UHS_SDR12_BUS_SPEED] = "SDR12 ", + [UHS_SDR25_BUS_SPEED] = "SDR25 ", + [UHS_SDR50_BUS_SPEED] = "SDR50 ", + [UHS_SDR104_BUS_SPEED] = "SDR104 ", + [UHS_DDR50_BUS_SPEED] = "DDR50 ", + }; + dev_set_name(&card->dev, "%s:%04x", mmc_hostname(card->host), card->rca); @@ -296,6 +305,10 @@ int mmc_add_card(struct mmc_card *card) break; } + if (mmc_sd_card_uhs(card) && + (card->sd_bus_speed < ARRAY_SIZE(uhs_speeds))) + uhs_bus_speed_mode = uhs_speeds[card->sd_bus_speed]; + if (mmc_host_is_spi(card->host)) { pr_info("%s: new %s%s%s card on SPI\n", mmc_hostname(card->host), @@ -303,13 +316,13 @@ int mmc_add_card(struct mmc_card *card) mmc_card_ddr_mode(card) ? "DDR " : "", type); } else { - pr_info("%s: new %s%s%s%s card at address %04x\n", + pr_info("%s: new %s%s%s%s%s card at address %04x\n", mmc_hostname(card->host), mmc_card_uhs(card) ? "ultra high speed " : (mmc_card_highspeed(card) ? "high speed " : ""), (mmc_card_hs200(card) ? "HS200 " : ""), mmc_card_ddr_mode(card) ? "DDR " : "", - type, card->rca); + uhs_bus_speed_mode, type, card->rca); } #ifdef CONFIG_DEBUG_FS -- cgit v1.2.3 From e841a7c69b708eeaf784fd517978006e8319b03a Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 1 Apr 2012 00:34:58 -0400 Subject: mmc: sdio: Use empty system suspend/resume callbacks at the bus level Neil Brown reports that commit 35cd133c PM: Run the driver callback directly if the subsystem one is not there breaks suspend for his libertas wifi, because SDIO has a protocol where the suspend method can return -ENOSYS and this means "There is no point in suspending, just turn me off". Moreover, the suspend methods provided by SDIO drivers are not supposed to be called by the PM core or bus-level suspend routines (which aren't presend for SDIO). Instead, when the SDIO core gets to suspend the device's ancestor, it calls the device driver's suspend function, catches the ENOSYS, and turns the device off. The commit above breaks the SDIO core's assumption that the device drivers' callbacks won't be executed if it doesn't provide any bus-level callbacks. If fact, however, this assumption has never been really satisfied, because device class or device type suspend might very well use the driver's callback even without that commit. The simplest way to address this problem is to make the SDIO core tell the PM core to ignore driver callbacks, for example by providing no-operation suspend/resume callbacks at the bus level for it, which is implemented by this change. Reported-and-tested-by: Neil Brown Signed-off-by: Rafael J. Wysocki [stable: please apply to 3.3-stable only] Cc: Signed-off-by: Chris Ball --- drivers/mmc/core/sdio_bus.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 40989e6bb53a..236842ec955a 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -192,9 +192,15 @@ static int sdio_bus_remove(struct device *dev) return ret; } -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM + +static int pm_no_operation(struct device *dev) +{ + return 0; +} static const struct dev_pm_ops sdio_bus_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_no_operation, pm_no_operation) SET_RUNTIME_PM_OPS( pm_generic_runtime_suspend, pm_generic_runtime_resume, @@ -204,11 +210,11 @@ static const struct dev_pm_ops sdio_bus_pm_ops = { #define SDIO_PM_OPS_PTR (&sdio_bus_pm_ops) -#else /* !CONFIG_PM_RUNTIME */ +#else /* !CONFIG_PM */ #define SDIO_PM_OPS_PTR NULL -#endif /* !CONFIG_PM_RUNTIME */ +#endif /* !CONFIG_PM */ static struct bus_type sdio_bus_type = { .name = "sdio", -- cgit v1.2.3 From d59d77ed1e0cdd254f99260013b27d64dc1dffac Mon Sep 17 00:00:00 2001 From: Balaji T K Date: Fri, 24 Feb 2012 21:14:33 +0530 Subject: mmc: omap_hsmmc: use runtime put sync in probe error patch pm_runtime_put_sync instead of autosuspend pm runtime API because iounmap(host->base) follows immediately. Reported-by: Rajendra Nayak Signed-off-by: Balaji T K Signed-off-by: Venkatraman S Cc: Signed-off-by: Chris Ball --- drivers/mmc/host/omap_hsmmc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 47adb161d3ad..f15b04b9da27 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -2018,8 +2018,7 @@ err_reg: err_irq_cd_init: free_irq(host->irq, host); err_irq: - pm_runtime_mark_last_busy(host->dev); - pm_runtime_put_autosuspend(host->dev); + pm_runtime_put_sync(host->dev); pm_runtime_disable(host->dev); clk_put(host->fclk); if (host->got_dbclk) { -- cgit v1.2.3 From 92a3aebf06bdef849cc53aba99f963a9ae397e9d Mon Sep 17 00:00:00 2001 From: Balaji T K Date: Fri, 24 Feb 2012 21:14:34 +0530 Subject: mmc: omap_hsmmc: context save after enabling runtime pm Call context save api after enabling runtime pm to make sure that register access in context save api happens with clk enabled. Signed-off-by: Balaji T K Signed-off-by: Venkatraman S Cc: Signed-off-by: Chris Ball --- drivers/mmc/host/omap_hsmmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index f15b04b9da27..4ee1570d18d6 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1875,8 +1875,6 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev) goto err1; } - omap_hsmmc_context_save(host); - if (host->pdata->controller_flags & OMAP_HSMMC_BROKEN_MULTIBLOCK_READ) { dev_info(&pdev->dev, "multiblock reads disabled due to 35xx erratum 2.1.1.128; MMC read performance may suffer\n"); mmc->caps2 |= MMC_CAP2_NO_MULTI_READ; @@ -1887,6 +1885,8 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev) pm_runtime_set_autosuspend_delay(host->dev, MMC_AUTOSUSPEND_DELAY); pm_runtime_use_autosuspend(host->dev); + omap_hsmmc_context_save(host); + if (cpu_is_omap2430()) { host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck"); /* -- cgit v1.2.3 From 927ce944aebdcac0fa757d4e6448a6972184db8c Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 14 Mar 2012 11:18:27 +0200 Subject: mmc: omap_hsmmc: trivial cleanups A bunch of non-functional cleanups to the omap_hsmmc driver. It basically decreases indentation level, drop unneded dereferences and drop unneded accesses to the platform_device structure. Signed-off-by: Felipe Balbi Signed-off-by: Venkatraman S Signed-off-by: Chris Ball --- drivers/mmc/host/omap_hsmmc.c | 147 ++++++++++++++++++++---------------------- 1 file changed, 70 insertions(+), 77 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 4ee1570d18d6..920964ac3214 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -2041,30 +2041,28 @@ static int omap_hsmmc_remove(struct platform_device *pdev) struct omap_hsmmc_host *host = platform_get_drvdata(pdev); struct resource *res; - if (host) { - pm_runtime_get_sync(host->dev); - mmc_remove_host(host->mmc); - if (host->use_reg) - omap_hsmmc_reg_put(host); - if (host->pdata->cleanup) - host->pdata->cleanup(&pdev->dev); - free_irq(host->irq, host); - if (mmc_slot(host).card_detect_irq) - free_irq(mmc_slot(host).card_detect_irq, host); - - pm_runtime_put_sync(host->dev); - pm_runtime_disable(host->dev); - clk_put(host->fclk); - if (host->got_dbclk) { - clk_disable(host->dbclk); - clk_put(host->dbclk); - } + pm_runtime_get_sync(host->dev); + mmc_remove_host(host->mmc); + if (host->use_reg) + omap_hsmmc_reg_put(host); + if (host->pdata->cleanup) + host->pdata->cleanup(&pdev->dev); + free_irq(host->irq, host); + if (mmc_slot(host).card_detect_irq) + free_irq(mmc_slot(host).card_detect_irq, host); - mmc_free_host(host->mmc); - iounmap(host->base); - omap_hsmmc_gpio_free(pdev->dev.platform_data); + pm_runtime_put_sync(host->dev); + pm_runtime_disable(host->dev); + clk_put(host->fclk); + if (host->got_dbclk) { + clk_disable(host->dbclk); + clk_put(host->dbclk); } + mmc_free_host(host->mmc); + iounmap(host->base); + omap_hsmmc_gpio_free(pdev->dev.platform_data); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res) release_mem_region(res->start, resource_size(res)); @@ -2077,49 +2075,45 @@ static int omap_hsmmc_remove(struct platform_device *pdev) static int omap_hsmmc_suspend(struct device *dev) { int ret = 0; - struct platform_device *pdev = to_platform_device(dev); - struct omap_hsmmc_host *host = platform_get_drvdata(pdev); + struct omap_hsmmc_host *host = dev_get_drvdata(dev); - if (host && host->suspended) + if (!host) return 0; - if (host) { - pm_runtime_get_sync(host->dev); - host->suspended = 1; - if (host->pdata->suspend) { - ret = host->pdata->suspend(&pdev->dev, - host->slot_id); - if (ret) { - dev_dbg(mmc_dev(host->mmc), - "Unable to handle MMC board" - " level suspend\n"); - host->suspended = 0; - return ret; - } - } - ret = mmc_suspend_host(host->mmc); + if (host && host->suspended) + return 0; + pm_runtime_get_sync(host->dev); + host->suspended = 1; + if (host->pdata->suspend) { + ret = host->pdata->suspend(dev, host->slot_id); if (ret) { + dev_dbg(dev, "Unable to handle MMC board" + " level suspend\n"); host->suspended = 0; - if (host->pdata->resume) { - ret = host->pdata->resume(&pdev->dev, - host->slot_id); - if (ret) - dev_dbg(mmc_dev(host->mmc), - "Unmask interrupt failed\n"); - } - goto err; + return ret; } + } + ret = mmc_suspend_host(host->mmc); - if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER)) { - omap_hsmmc_disable_irq(host); - OMAP_HSMMC_WRITE(host->base, HCTL, - OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP); + if (ret) { + host->suspended = 0; + if (host->pdata->resume) { + ret = host->pdata->resume(dev, host->slot_id); + if (ret) + dev_dbg(dev, "Unmask interrupt failed\n"); } - if (host->got_dbclk) - clk_disable(host->dbclk); + goto err; + } + if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER)) { + omap_hsmmc_disable_irq(host); + OMAP_HSMMC_WRITE(host->base, HCTL, + OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP); } + + if (host->got_dbclk) + clk_disable(host->dbclk); err: pm_runtime_put_sync(host->dev); return ret; @@ -2129,38 +2123,37 @@ err: static int omap_hsmmc_resume(struct device *dev) { int ret = 0; - struct platform_device *pdev = to_platform_device(dev); - struct omap_hsmmc_host *host = platform_get_drvdata(pdev); + struct omap_hsmmc_host *host = dev_get_drvdata(dev); + + if (!host) + return 0; if (host && !host->suspended) return 0; - if (host) { - pm_runtime_get_sync(host->dev); + pm_runtime_get_sync(host->dev); - if (host->got_dbclk) - clk_enable(host->dbclk); + if (host->got_dbclk) + clk_enable(host->dbclk); - if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER)) - omap_hsmmc_conf_bus_power(host); + if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER)) + omap_hsmmc_conf_bus_power(host); - if (host->pdata->resume) { - ret = host->pdata->resume(&pdev->dev, host->slot_id); - if (ret) - dev_dbg(mmc_dev(host->mmc), - "Unmask interrupt failed\n"); - } + if (host->pdata->resume) { + ret = host->pdata->resume(dev, host->slot_id); + if (ret) + dev_dbg(dev, "Unmask interrupt failed\n"); + } - omap_hsmmc_protect_card(host); + omap_hsmmc_protect_card(host); - /* Notify the core to resume the host */ - ret = mmc_resume_host(host->mmc); - if (ret == 0) - host->suspended = 0; + /* Notify the core to resume the host */ + ret = mmc_resume_host(host->mmc); + if (ret == 0) + host->suspended = 0; - pm_runtime_mark_last_busy(host->dev); - pm_runtime_put_autosuspend(host->dev); - } + pm_runtime_mark_last_busy(host->dev); + pm_runtime_put_autosuspend(host->dev); return ret; @@ -2177,7 +2170,7 @@ static int omap_hsmmc_runtime_suspend(struct device *dev) host = platform_get_drvdata(to_platform_device(dev)); omap_hsmmc_context_save(host); - dev_dbg(mmc_dev(host->mmc), "disabled\n"); + dev_dbg(dev, "disabled\n"); return 0; } @@ -2188,7 +2181,7 @@ static int omap_hsmmc_runtime_resume(struct device *dev) host = platform_get_drvdata(to_platform_device(dev)); omap_hsmmc_context_restore(host); - dev_dbg(mmc_dev(host->mmc), "enabled\n"); + dev_dbg(dev, "enabled\n"); return 0; } -- cgit v1.2.3 From efa25fd3a33275861aa74ff03a512423873a8805 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 14 Mar 2012 11:18:28 +0200 Subject: mmc: omap_hsmmc: make it behave well as a module If we put probe() on __init section, that will never work for multiple module insertions/removals. In order to make it work properly, move probe to __devinit section and use platform_driver_register() instead of platform_driver_probe(). Signed-off-by: Felipe Balbi Signed-off-by: Venkatraman S Signed-off-by: Chris Ball --- drivers/mmc/host/omap_hsmmc.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 920964ac3214..2aa963dcbdbd 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1785,7 +1785,7 @@ static inline struct omap_mmc_platform_data } #endif -static int __init omap_hsmmc_probe(struct platform_device *pdev) +static int __devinit omap_hsmmc_probe(struct platform_device *pdev) { struct omap_mmc_platform_data *pdata = pdev->dev.platform_data; struct mmc_host *mmc; @@ -2036,7 +2036,7 @@ err: return ret; } -static int omap_hsmmc_remove(struct platform_device *pdev) +static int __devexit omap_hsmmc_remove(struct platform_device *pdev) { struct omap_hsmmc_host *host = platform_get_drvdata(pdev); struct resource *res; @@ -2194,7 +2194,8 @@ static struct dev_pm_ops omap_hsmmc_dev_pm_ops = { }; static struct platform_driver omap_hsmmc_driver = { - .remove = omap_hsmmc_remove, + .probe = omap_hsmmc_probe, + .remove = __devexit_p(omap_hsmmc_remove), .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, @@ -2206,7 +2207,7 @@ static struct platform_driver omap_hsmmc_driver = { static int __init omap_hsmmc_init(void) { /* Register the MMC driver */ - return platform_driver_probe(&omap_hsmmc_driver, omap_hsmmc_probe); + return platform_driver_register(&omap_hsmmc_driver); } static void __exit omap_hsmmc_cleanup(void) -- cgit v1.2.3 From b796450b4590dbaee2d31c85b04791cafacff9b4 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 14 Mar 2012 11:18:32 +0200 Subject: mmc: omap_hsmmc: convert to module_platform_driver This will delete some boilerplate code, no functional changes. Signed-off-by: Felipe Balbi Signed-off-by: Venkatraman S Signed-off-by: Chris Ball --- drivers/mmc/host/omap_hsmmc.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 2aa963dcbdbd..b4c59eac348f 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -2204,21 +2204,7 @@ static struct platform_driver omap_hsmmc_driver = { }, }; -static int __init omap_hsmmc_init(void) -{ - /* Register the MMC driver */ - return platform_driver_register(&omap_hsmmc_driver); -} - -static void __exit omap_hsmmc_cleanup(void) -{ - /* Unregister MMC driver */ - platform_driver_unregister(&omap_hsmmc_driver); -} - -module_init(omap_hsmmc_init); -module_exit(omap_hsmmc_cleanup); - +module_platform_driver(omap_hsmmc_driver); MODULE_DESCRIPTION("OMAP High Speed Multimedia Card driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:" DRIVER_NAME); -- cgit v1.2.3 From fc307df88f0d77505c19756d95be66c981c421ea Mon Sep 17 00:00:00 2001 From: Balaji T K Date: Mon, 2 Apr 2012 12:26:47 +0530 Subject: mmc: omap_hsmmc: fix module re-insertion OMAP4 and OMAP3 HSMMC IP registers differ by 0x100 offset. Adding the offset to platform_device resource structure increments the start address for every insmod operation. MMC command fails on re-insertion as module due to incorrect register base. Fix this by updating the ioremap base address only. Signed-off-by: Balaji T K Signed-off-by: Venkatraman S Signed-off-by: Chris Ball --- drivers/mmc/host/omap_hsmmc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index b4c59eac348f..5c2b1c10af9c 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1818,8 +1818,6 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev) if (res == NULL || irq < 0) return -ENXIO; - res->start += pdata->reg_offset; - res->end += pdata->reg_offset; res = request_mem_region(res->start, resource_size(res), pdev->name); if (res == NULL) return -EBUSY; @@ -1843,7 +1841,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev) host->dma_ch = -1; host->irq = irq; host->slot_id = 0; - host->mapbase = res->start; + host->mapbase = res->start + pdata->reg_offset; host->base = ioremap(host->mapbase, SZ_4K); host->power_mode = MMC_POWER_OFF; host->next_data.cookie = 1; -- cgit v1.2.3 From 93fc5a47f25c41125b30c0bf4f243bf3204a1a0a Mon Sep 17 00:00:00 2001 From: Subhash Jadavani Date: Tue, 3 Apr 2012 12:25:58 +0530 Subject: mmc: core: fix power class selection mmc_select_powerclass() function returns error if eMMC VDD level supported by host is between 2.7v to 3.2v. According to eMMC specification, valid voltage for high voltage cards is 2.7v to 3.6v. This patch ensures that 2.7v to 3.6v VDD range is treated as valid range. Also, failure to set the power class shouldn't be treated as fatal error because even if setting the power class fails, card can still work in default power class. If mmc_select_powerclass() returns error, just print the warning message and go ahead with rest of the card initialization. Signed-off-by: Subhash Jadavani Acked-by: Girish K S Reviewed-by: Namjae Jeon Signed-off-by: Chris Ball --- drivers/mmc/core/mmc.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 02914d609a91..54df5adc0413 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -695,6 +695,11 @@ static int mmc_select_powerclass(struct mmc_card *card, else if (host->ios.clock <= 200000000) index = EXT_CSD_PWR_CL_200_195; break; + case MMC_VDD_27_28: + case MMC_VDD_28_29: + case MMC_VDD_29_30: + case MMC_VDD_30_31: + case MMC_VDD_31_32: case MMC_VDD_32_33: case MMC_VDD_33_34: case MMC_VDD_34_35: @@ -1111,11 +1116,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ? EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4; err = mmc_select_powerclass(card, ext_csd_bits, ext_csd); - if (err) { - pr_err("%s: power class selection to bus width %d failed\n", - mmc_hostname(card->host), 1 << bus_width); - goto err; - } + if (err) + pr_warning("%s: power class selection to bus width %d" + " failed\n", mmc_hostname(card->host), + 1 << bus_width); } /* @@ -1147,10 +1151,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, err = mmc_select_powerclass(card, ext_csd_bits[idx][0], ext_csd); if (err) - pr_err("%s: power class selection to " - "bus width %d failed\n", - mmc_hostname(card->host), - 1 << bus_width); + pr_warning("%s: power class selection to " + "bus width %d failed\n", + mmc_hostname(card->host), + 1 << bus_width); err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, @@ -1178,10 +1182,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, err = mmc_select_powerclass(card, ext_csd_bits[idx][1], ext_csd); if (err) - pr_err("%s: power class selection to " - "bus width %d ddr %d failed\n", - mmc_hostname(card->host), - 1 << bus_width, ddr); + pr_warning("%s: power class selection to " + "bus width %d ddr %d failed\n", + mmc_hostname(card->host), + 1 << bus_width, ddr); err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, -- cgit v1.2.3 From 84e41d2d56fbacfd888ab1382e94e752da176582 Mon Sep 17 00:00:00 2001 From: Chris Ball Date: Tue, 3 Apr 2012 16:47:55 -0400 Subject: Revert "mmc: sdhci-pci: add quirks for broken MSI on O2Micro controllers" This reverts commit c16e981b2fd9455af670a69a84f4c8cf07e12658, because it's no longer useful once MSI support is reverted. Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci-pci.c | 4 +--- include/linux/mmc/sdhci.h | 2 -- 2 files changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 9303f7fc1e68..fbbebe251e01 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -561,7 +561,6 @@ static int jmicron_resume(struct sdhci_pci_chip *chip) static const struct sdhci_pci_fixes sdhci_o2 = { .probe = o2_probe, - .quirks2 = SDHCI_QUIRK2_BROKEN_MSI, }; static const struct sdhci_pci_fixes sdhci_jmicron = { @@ -1419,8 +1418,7 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev, slots = chip->num_slots; /* Quirk may have changed this */ - if (!(chip->quirks2 & SDHCI_QUIRK2_BROKEN_MSI)) - pci_enable_msi(pdev); + pci_enable_msi(pdev); for (i = 0; i < slots; i++) { slot = sdhci_pci_probe_slot(pdev, chip, first_bar, i); diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h index 9752fe434ae9..e9051e1cb1ce 100644 --- a/include/linux/mmc/sdhci.h +++ b/include/linux/mmc/sdhci.h @@ -91,8 +91,6 @@ struct sdhci_host { unsigned int quirks2; /* More deviations from spec. */ #define SDHCI_QUIRK2_HOST_OFF_CARD_ON (1<<0) -/* broken MSI Interrupts */ -#define SDHCI_QUIRK2_BROKEN_MSI (1<<1) int irq; /* Device IRQ */ void __iomem *ioaddr; /* Mapped address */ -- cgit v1.2.3 From 79263f33b0f3abe26d74a66824b457b94bdbef9f Mon Sep 17 00:00:00 2001 From: Chris Ball Date: Tue, 3 Apr 2012 16:48:32 -0400 Subject: Revert "mmc: sdhci-pci: Add MSI support" This reverts commit e6039832bed9a9b967796d7021f17f25b625b616. There are reports of MSI breaking SDHCI on multiple chipsets (JMicron and O2Micro, at least), so this should be reverted until we come up with a whitelist or something. Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci-pci.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index fbbebe251e01..69ef0beae104 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -1418,8 +1418,6 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev, slots = chip->num_slots; /* Quirk may have changed this */ - pci_enable_msi(pdev); - for (i = 0; i < slots; i++) { slot = sdhci_pci_probe_slot(pdev, chip, first_bar, i); if (IS_ERR(slot)) { @@ -1438,8 +1436,6 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev, return 0; free: - pci_disable_msi(pdev); - pci_set_drvdata(pdev, NULL); kfree(chip); @@ -1462,8 +1458,6 @@ static void __devexit sdhci_pci_remove(struct pci_dev *pdev) for (i = 0; i < chip->num_slots; i++) sdhci_pci_remove_slot(chip->slots[i]); - pci_disable_msi(pdev); - pci_set_drvdata(pdev, NULL); kfree(chip); } -- cgit v1.2.3 From 4188bba0e9e7ba58d231b528df495666f2742b74 Mon Sep 17 00:00:00 2001 From: Al Cooper Date: Fri, 16 Mar 2012 15:54:17 -0400 Subject: mmc: Prevent 1.8V switch for SD hosts that don't support UHS modes. The driver should not try to switch to 1.8V when the SD 3.0 host controller does not have any UHS capabilities bits set (SDR50, DDR50 or SDR104). See page 72 of "SD Specifications Part A2 SD Host Controller Simplified Specification Version 3.00" under "1.8V Signaling Enable". Instead of setting SDR12 and SDR25 in the host capabilities data structure for all V3.0 host controllers, only set them if SDR104, SDR50 or DDR50 is set in the host capabilities register. This will prevent the switch to 1.8V later. Signed-off-by: Al Cooper Acked-by: Arindam Nath Acked-by: Philip Rakity Acked-by: Girish K S Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 8262cadfdab7..9aa77f3f04a8 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2782,8 +2782,9 @@ int sdhci_add_host(struct sdhci_host *host) mmc_card_is_removable(mmc)) mmc->caps |= MMC_CAP_NEEDS_POLL; - /* UHS-I mode(s) supported by the host controller. */ - if (host->version >= SDHCI_SPEC_300) + /* Any UHS-I mode in caps implies SDR12 and SDR25 support. */ + if (caps[1] & (SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 | + SDHCI_SUPPORT_DDR50)) mmc->caps |= MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25; /* SDR104 supports also implies SDR50 support */ -- cgit v1.2.3 From 8c2fc8e413ecc2c96b696e28d4eb1bc6cee8dc84 Mon Sep 17 00:00:00 2001 From: Alf Høgemark Date: Wed, 4 Apr 2012 12:27:09 -0400 Subject: mmc: sdhci-dove: Fix compile error by including module.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch fixes a compile error in drivers/mmc/host/sdhci-dove.c by including the linux/module.h file. Signed-off-by: Alf Høgemark Cc: Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci-dove.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-dove.c b/drivers/mmc/host/sdhci-dove.c index 46fd1fd1b605..177f697b5835 100644 --- a/drivers/mmc/host/sdhci-dove.c +++ b/drivers/mmc/host/sdhci-dove.c @@ -20,6 +20,7 @@ */ #include +#include #include #include "sdhci-pltfm.h" -- cgit v1.2.3 From 3bdc9ba892d6a294d16e9e6e0c4041926aa3d58c Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Mon, 12 Mar 2012 04:58:00 -0600 Subject: mmc: use really long write timeout to deal with crappy cards Several people have noticed that crappy SD cards take much longer to complete multiple block writes than the 300ms that Linux specifies. Try to work around this by using a three second write timeout instead. This is a generalized version of a patch from Chase Maupin , whose patch description said: * With certain SD cards timeouts like the following have been seen due to an improper calculation of the dto value: mmcblk0: error -110 transferring data, sector 4126233, nr 8, card status 0xc00 * By removing the dto calculation and setting the timeout value to the maximum specified by the SD card specification part A2 section 2.2.15 these timeouts can be avoided. * This change has been used by beagleboard users as well as the Texas Instruments SDK without a negative impact. * There are multiple discussion threads about this but the most relevant ones are: * http://talk.maemo.org/showthread.php?p=1000707#post1000707 * http://www.mail-archive.com/linux-omap@vger.kernel.org/msg42213.html * Original proposal for this fix was done by Sukumar Ghoral of Texas Instruments * Tested using a Texas Instruments AM335x EVM Signed-off-by: Paul Walmsley Tested-by: Tony Lindgren Signed-off-by: Chris Ball --- drivers/mmc/core/core.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 14f262e9246d..7474c47b9c08 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -527,10 +527,14 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card) if (data->flags & MMC_DATA_WRITE) /* - * The limit is really 250 ms, but that is - * insufficient for some crappy cards. + * The MMC spec "It is strongly recommended + * for hosts to implement more than 500ms + * timeout value even if the card indicates + * the 250ms maximum busy length." Even the + * previous value of 300ms is known to be + * insufficient for some cards. */ - limit_us = 300000; + limit_us = 3000000; else limit_us = 100000; -- cgit v1.2.3 From e95ae5a4939c52ccab02a49238d5d15d492b2598 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Tue, 27 Mar 2012 19:31:08 +0200 Subject: xen: only check xen_platform_pci_unplug if hvm commit b9136d207f08 xen: initialize platform-pci even if xen_emul_unplug=never breaks blkfront/netfront by not loading them because of xen_platform_pci_unplug=0 and it is never set for PV guest. Signed-off-by: Andrew Jones Signed-off-by: Igor Mammedov Signed-off-by: Konrad Rzeszutek Wilk --- drivers/block/xen-blkfront.c | 2 +- drivers/net/xen-netfront.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 4276ab035e00..19b6005a323e 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -1452,7 +1452,7 @@ static int __init xlblk_init(void) if (!xen_domain()) return -ENODEV; - if (!xen_platform_pci_unplug) + if (xen_hvm_domain() && !xen_platform_pci_unplug) return -ENODEV; if (register_blkdev(XENVBD_MAJOR, DEV_NAME)) { diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 8cc0914b9f92..ccba19c72a36 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -1957,7 +1957,7 @@ static int __init netif_init(void) if (xen_initial_domain()) return 0; - if (!xen_platform_pci_unplug) + if (xen_hvm_domain() && !xen_platform_pci_unplug) return -ENODEV; printk(KERN_INFO "Initialising Xen virtual ethernet driver.\n"); -- cgit v1.2.3 From 0ee46eca0476faf0e93c1387b1597b861b79711f Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Mon, 2 Apr 2012 15:32:22 +0100 Subject: xen/pciback: fix XEN_PCI_OP_enable_msix result Prior to 2.6.19 and as of 2.6.31, pci_enable_msix() can return a positive value to indicate the number of vectors (less than the amount requested) that can be set up for a given device. Returning this as an operation value (secondary result) is fine, but (primary) operation results are expected to be negative (error) or zero (success) according to the protocol. With the frontend fixed to match the XenoLinux behavior, the backend can now validly return zero (success) here, passing the upper limit on the number of vectors in op->value. Signed-off-by: Jan Beulich Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/xen-pciback/pciback_ops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/xen/xen-pciback/pciback_ops.c b/drivers/xen/xen-pciback/pciback_ops.c index 63616d7453e6..97f5d264c31e 100644 --- a/drivers/xen/xen-pciback/pciback_ops.c +++ b/drivers/xen/xen-pciback/pciback_ops.c @@ -234,7 +234,7 @@ int xen_pcibk_enable_msix(struct xen_pcibk_device *pdev, if (dev_data) dev_data->ack_intr = 0; - return result; + return result > 0 ? 0 : result; } static -- cgit v1.2.3 From f09d8432e39797abf39531f41ac8a46a3fbf442a Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Mon, 2 Apr 2012 15:22:39 +0100 Subject: xen/pcifront: avoid pci_frontend_enable_msix() falsely returning success The original XenoLinux code has always had things this way, and for compatibility reasons (in particular with a subsequent pciback adjustment) upstream Linux should behave the same way (allowing for two distinct error indications to be returned by the backend). Signed-off-by: Jan Beulich Signed-off-by: Konrad Rzeszutek Wilk --- drivers/pci/xen-pcifront.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c index 7cf3d2fcf56a..c18fab289ad5 100644 --- a/drivers/pci/xen-pcifront.c +++ b/drivers/pci/xen-pcifront.c @@ -290,6 +290,7 @@ static int pci_frontend_enable_msix(struct pci_dev *dev, } else { printk(KERN_DEBUG "enable msix get value %x\n", op.value); + err = op.value; } } else { dev_err(&dev->dev, "enable msix get err %x\n", err); -- cgit v1.2.3 From ee01e663373343c63e0e3d364d09f6155378dbcc Mon Sep 17 00:00:00 2001 From: Toshi Kani Date: Sat, 31 Mar 2012 21:37:02 -0600 Subject: cpuidle: Fix panic in CPU off-lining with no idle driver Fix a NULL pointer dereference panic in cpuidle_play_dead() during CPU off-lining when no cpuidle driver is registered. A cpuidle driver may be registered at boot-time based on CPU type. This patch allows an off-lined CPU to enter HLT-based idle in this condition. Signed-off-by: Toshi Kani Cc: Boris Ostrovsky Reviewed-by: Srivatsa S. Bhat Tested-by: Srivatsa S. Bhat Signed-off-by: Len Brown --- drivers/cpuidle/cpuidle.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 3e146b2ada4a..a71376a45d8e 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -74,7 +74,7 @@ static cpuidle_enter_t cpuidle_enter_ops; /** * cpuidle_play_dead - cpu off-lining * - * Only returns in case of an error + * Returns in case of an error or no driver */ int cpuidle_play_dead(void) { @@ -83,6 +83,9 @@ int cpuidle_play_dead(void) int i, dead_state = -1; int power_usage = -1; + if (!drv) + return -ENODEV; + /* Find lowest-power state that supports long-term idle */ for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) { struct cpuidle_state *s = &drv->states[i]; -- cgit v1.2.3 From e1c4038282c7586c3544542b37872c434669d3ac Mon Sep 17 00:00:00 2001 From: Mark Rustad Date: Tue, 3 Apr 2012 10:24:41 -0700 Subject: tcm_fc: Add abort flag for gracefully handling exchange timeout Add abort flag and use it to terminate processing when an exchange is timed out or is reset. The abort flag is used in place of the transport_generic_free_cmd function call in the reset and timeout cases, because calling that function in that context would free memory that was in use. The aborted flag allows the lifetime to be managed in a more normal way, while truncating the processing. This change eliminates a source of memory corruption which manifested in a variety of ugly ways. (nab: Drop unused struct fc_exch *ep in ft_recv_seq) Signed-off-by: Mark Rustad Acked-by: Kiran Patil Cc: Signed-off-by: Nicholas Bellinger --- drivers/target/tcm_fc/tcm_fc.h | 1 + drivers/target/tcm_fc/tfc_cmd.c | 10 ++++++++-- drivers/target/tcm_fc/tfc_io.c | 2 ++ 3 files changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/target/tcm_fc/tcm_fc.h b/drivers/target/tcm_fc/tcm_fc.h index 830657908db8..c5eb3c33c3db 100644 --- a/drivers/target/tcm_fc/tcm_fc.h +++ b/drivers/target/tcm_fc/tcm_fc.h @@ -122,6 +122,7 @@ struct ft_cmd { /* Local sense buffer */ unsigned char ft_sense_buffer[TRANSPORT_SENSE_BUFFER]; u32 was_ddp_setup:1; /* Set only if ddp is setup */ + u32 aborted:1; /* Set if aborted by reset or timeout */ struct scatterlist *sg; /* Set only if DDP is setup */ u32 sg_cnt; /* No. of item in scatterlist */ }; diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c index 62dec9715ce5..a375f257aabc 100644 --- a/drivers/target/tcm_fc/tfc_cmd.c +++ b/drivers/target/tcm_fc/tfc_cmd.c @@ -121,6 +121,8 @@ int ft_queue_status(struct se_cmd *se_cmd) struct fc_exch *ep; size_t len; + if (cmd->aborted) + return 0; ft_dump_cmd(cmd, __func__); ep = fc_seq_exch(cmd->seq); lport = ep->lp; @@ -187,6 +189,8 @@ int ft_write_pending(struct se_cmd *se_cmd) ft_dump_cmd(cmd, __func__); + if (cmd->aborted) + return 0; ep = fc_seq_exch(cmd->seq); lport = ep->lp; fp = fc_frame_alloc(lport, sizeof(*txrdy)); @@ -252,10 +256,10 @@ static void ft_recv_seq(struct fc_seq *sp, struct fc_frame *fp, void *arg) struct ft_cmd *cmd = arg; struct fc_frame_header *fh; - if (IS_ERR(fp)) { + if (unlikely(IS_ERR(fp))) { /* XXX need to find cmd if queued */ cmd->seq = NULL; - transport_generic_free_cmd(&cmd->se_cmd, 0); + cmd->aborted = true; return; } @@ -399,6 +403,8 @@ int ft_queue_tm_resp(struct se_cmd *se_cmd) struct se_tmr_req *tmr = se_cmd->se_tmr_req; enum fcp_resp_rsp_codes code; + if (cmd->aborted) + return 0; switch (tmr->response) { case TMR_FUNCTION_COMPLETE: code = FCP_TMF_CMPL; diff --git a/drivers/target/tcm_fc/tfc_io.c b/drivers/target/tcm_fc/tfc_io.c index 2b693eefac55..dc7c0db26e20 100644 --- a/drivers/target/tcm_fc/tfc_io.c +++ b/drivers/target/tcm_fc/tfc_io.c @@ -81,6 +81,8 @@ int ft_queue_data_in(struct se_cmd *se_cmd) void *from; void *to = NULL; + if (cmd->aborted) + return 0; ep = fc_seq_exch(cmd->seq); lport = ep->lp; cmd->seq = lport->tt.seq_start_next(cmd->seq); -- cgit v1.2.3 From 06383f10c49f507220594a455c6491ca6f8c94ab Mon Sep 17 00:00:00 2001 From: Mark Rustad Date: Tue, 3 Apr 2012 10:24:52 -0700 Subject: tcm_fc: Do not free tpg structure during wq allocation failure Avoid freeing a registered tpg structure if an alloc_workqueue call fails. This fixes a bug where the failure was leaking memory associated with se_portal_group setup during the original core_tpg_register() call. Signed-off-by: Mark Rustad Acked-by: Kiran Patil Cc: Signed-off-by: Nicholas Bellinger --- drivers/target/tcm_fc/tfc_conf.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c index f357039349ba..2948dc944619 100644 --- a/drivers/target/tcm_fc/tfc_conf.c +++ b/drivers/target/tcm_fc/tfc_conf.c @@ -300,6 +300,7 @@ static struct se_portal_group *ft_add_tpg( { struct ft_lport_acl *lacl; struct ft_tpg *tpg; + struct workqueue_struct *wq; unsigned long index; int ret; @@ -321,18 +322,20 @@ static struct se_portal_group *ft_add_tpg( tpg->lport_acl = lacl; INIT_LIST_HEAD(&tpg->lun_list); - ret = core_tpg_register(&ft_configfs->tf_ops, wwn, &tpg->se_tpg, - tpg, TRANSPORT_TPG_TYPE_NORMAL); - if (ret < 0) { + wq = alloc_workqueue("tcm_fc", 0, 1); + if (!wq) { kfree(tpg); return NULL; } - tpg->workqueue = alloc_workqueue("tcm_fc", 0, 1); - if (!tpg->workqueue) { + ret = core_tpg_register(&ft_configfs->tf_ops, wwn, &tpg->se_tpg, + tpg, TRANSPORT_TPG_TYPE_NORMAL); + if (ret < 0) { + destroy_workqueue(wq); kfree(tpg); return NULL; } + tpg->workqueue = wq; mutex_lock(&ft_lport_lock); list_add_tail(&tpg->list, &lacl->tpg_list); -- cgit v1.2.3