diff options
Diffstat (limited to 'drivers')
114 files changed, 2388 insertions, 693 deletions
diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index bfd55b085ae..9f029595f45 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -44,6 +44,7 @@ #include <linux/device.h> #include <scsi/scsi_host.h> #include <linux/libata.h> +#include <linux/dmi.h> #define DRV_NAME "sata_sil" #define DRV_VERSION "2.4" diff --git a/drivers/base/core.c b/drivers/base/core.c index 55e530942ab..f3eae630e58 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -1280,7 +1280,7 @@ EXPORT_SYMBOL_GPL(__root_device_register); /** * root_device_unregister - unregister and free a root device - * @root: device going away. + * @dev: device going away * * This function unregisters and cleans up a device that was created by * root_device_register(). diff --git a/drivers/char/selection.c b/drivers/char/selection.c index f29fbe9b8ed..cb8ca569896 100644 --- a/drivers/char/selection.c +++ b/drivers/char/selection.c @@ -268,7 +268,7 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t /* Allocate a new buffer before freeing the old one ... */ multiplier = use_unicode ? 3 : 1; /* chars can take up to 3 bytes */ - bp = kmalloc((sel_end-sel_start)/2*multiplier+1, GFP_KERNEL); + bp = kmalloc(((sel_end-sel_start)/2+1)*multiplier, GFP_KERNEL); if (!bp) { printk(KERN_WARNING "selection: kmalloc() failed\n"); clear_selection(); diff --git a/drivers/firewire/fw-card.c b/drivers/firewire/fw-card.c index 6bd91a15d5e..7be2cf3514e 100644 --- a/drivers/firewire/fw-card.c +++ b/drivers/firewire/fw-card.c @@ -232,7 +232,7 @@ fw_card_bm_work(struct work_struct *work) root_id = root_node->node_id; grace = time_after(jiffies, card->reset_jiffies + DIV_ROUND_UP(HZ, 10)); - if (card->bm_generation + 1 == generation || + if (is_next_generation(generation, card->bm_generation) || (card->bm_generation != generation && grace)) { /* * This first step is to figure out who is IRM and @@ -512,7 +512,7 @@ fw_core_remove_card(struct fw_card *card) fw_core_initiate_bus_reset(card, 1); mutex_lock(&card_mutex); - list_del(&card->link); + list_del_init(&card->link); mutex_unlock(&card_mutex); /* Set up the dummy driver. */ diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c index 2af5a8d1e01..bf53acb4565 100644 --- a/drivers/firewire/fw-device.c +++ b/drivers/firewire/fw-device.c @@ -25,6 +25,7 @@ #include <linux/device.h> #include <linux/delay.h> #include <linux/idr.h> +#include <linux/jiffies.h> #include <linux/string.h> #include <linux/rwsem.h> #include <linux/semaphore.h> @@ -634,12 +635,39 @@ struct fw_device *fw_device_get_by_devt(dev_t devt) return device; } +/* + * These defines control the retry behavior for reading the config + * rom. It shouldn't be necessary to tweak these; if the device + * doesn't respond to a config rom read within 10 seconds, it's not + * going to respond at all. As for the initial delay, a lot of + * devices will be able to respond within half a second after bus + * reset. On the other hand, it's not really worth being more + * aggressive than that, since it scales pretty well; if 10 devices + * are plugged in, they're all getting read within one second. + */ + +#define MAX_RETRIES 10 +#define RETRY_DELAY (3 * HZ) +#define INITIAL_DELAY (HZ / 2) +#define SHUTDOWN_DELAY (2 * HZ) + static void fw_device_shutdown(struct work_struct *work) { struct fw_device *device = container_of(work, struct fw_device, work.work); int minor = MINOR(device->device.devt); + if (time_is_after_jiffies(device->card->reset_jiffies + SHUTDOWN_DELAY) + && !list_empty(&device->card->link)) { + schedule_delayed_work(&device->work, SHUTDOWN_DELAY); + return; + } + + if (atomic_cmpxchg(&device->state, + FW_DEVICE_GONE, + FW_DEVICE_SHUTDOWN) != FW_DEVICE_GONE) + return; + fw_device_cdev_remove(device); device_for_each_child(&device->device, NULL, shutdown_unit); device_unregister(&device->device); @@ -647,6 +675,7 @@ static void fw_device_shutdown(struct work_struct *work) down_write(&fw_device_rwsem); idr_remove(&fw_device_idr, minor); up_write(&fw_device_rwsem); + fw_device_put(device); } @@ -654,25 +683,63 @@ static struct device_type fw_device_type = { .release = fw_device_release, }; +static void fw_device_update(struct work_struct *work); + /* - * These defines control the retry behavior for reading the config - * rom. It shouldn't be necessary to tweak these; if the device - * doesn't respond to a config rom read within 10 seconds, it's not - * going to respond at all. As for the initial delay, a lot of - * devices will be able to respond within half a second after bus - * reset. On the other hand, it's not really worth being more - * aggressive than that, since it scales pretty well; if 10 devices - * are plugged in, they're all getting read within one second. + * If a device was pending for deletion because its node went away but its + * bus info block and root directory header matches that of a newly discovered + * device, revive the existing fw_device. + * The newly allocated fw_device becomes obsolete instead. */ +static int lookup_existing_device(struct device *dev, void *data) +{ + struct fw_device *old = fw_device(dev); + struct fw_device *new = data; + struct fw_card *card = new->card; + int match = 0; + + down_read(&fw_device_rwsem); /* serialize config_rom access */ + spin_lock_irq(&card->lock); /* serialize node access */ + + if (memcmp(old->config_rom, new->config_rom, 6 * 4) == 0 && + atomic_cmpxchg(&old->state, + FW_DEVICE_GONE, + FW_DEVICE_RUNNING) == FW_DEVICE_GONE) { + struct fw_node *current_node = new->node; + struct fw_node *obsolete_node = old->node; + + new->node = obsolete_node; + new->node->data = new; + old->node = current_node; + old->node->data = old; + + old->max_speed = new->max_speed; + old->node_id = current_node->node_id; + smp_wmb(); /* update node_id before generation */ + old->generation = card->generation; + old->config_rom_retries = 0; + fw_notify("rediscovered device %s\n", dev_name(dev)); -#define MAX_RETRIES 10 -#define RETRY_DELAY (3 * HZ) -#define INITIAL_DELAY (HZ / 2) + PREPARE_DELAYED_WORK(&old->work, fw_device_update); + schedule_delayed_work(&old->work, 0); + + if (current_node == card->root_node) + fw_schedule_bm_work(card, 0); + + match = 1; + } + + spin_unlock_irq(&card->lock); + up_read(&fw_device_rwsem); + + return match; +} static void fw_device_init(struct work_struct *work) { struct fw_device *device = container_of(work, struct fw_device, work.work); + struct device *revived_dev; int minor, err; /* @@ -696,6 +763,15 @@ static void fw_device_init(struct work_struct *work) return; } + revived_dev = device_find_child(device->card->device, + device, lookup_existing_device); + if (revived_dev) { + put_device(revived_dev); + fw_device_release(&device->device); + + return; + } + device_initialize(&device->device); fw_device_get(device); @@ -734,9 +810,10 @@ static void fw_device_init(struct work_struct *work) * fw_node_event(). */ if (atomic_cmpxchg(&device->state, - FW_DEVICE_INITIALIZING, - FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN) { - fw_device_shutdown(work); + FW_DEVICE_INITIALIZING, + FW_DEVICE_RUNNING) == FW_DEVICE_GONE) { + PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown); + schedule_delayed_work(&device->work, SHUTDOWN_DELAY); } else { if (device->config_rom_retries) fw_notify("created device %s: GUID %08x%08x, S%d00, " @@ -847,8 +924,8 @@ static void fw_device_refresh(struct work_struct *work) case REREAD_BIB_UNCHANGED: if (atomic_cmpxchg(&device->state, - FW_DEVICE_INITIALIZING, - FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN) + FW_DEVICE_INITIALIZING, + FW_DEVICE_RUNNING) == FW_DEVICE_GONE) goto gone; fw_device_update(work); @@ -879,8 +956,8 @@ static void fw_device_refresh(struct work_struct *work) create_units(device); if (atomic_cmpxchg(&device->state, - FW_DEVICE_INITIALIZING, - FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN) + FW_DEVICE_INITIALIZING, + FW_DEVICE_RUNNING) == FW_DEVICE_GONE) goto gone; fw_notify("refreshed device %s\n", dev_name(&device->device)); @@ -890,8 +967,9 @@ static void fw_device_refresh(struct work_struct *work) give_up: fw_notify("giving up on refresh of device %s\n", dev_name(&device->device)); gone: - atomic_set(&device->state, FW_DEVICE_SHUTDOWN); - fw_device_shutdown(work); + atomic_set(&device->state, FW_DEVICE_GONE); + PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown); + schedule_delayed_work(&device->work, SHUTDOWN_DELAY); out: if (node_id == card->root_node->node_id) fw_schedule_bm_work(card, 0); @@ -995,9 +1073,10 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event) */ device = node->data; if (atomic_xchg(&device->state, - FW_DEVICE_SHUTDOWN) == FW_DEVICE_RUNNING) { + FW_DEVICE_GONE) == FW_DEVICE_RUNNING) { PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown); - schedule_delayed_work(&device->work, 0); + schedule_delayed_work(&device->work, + list_empty(&card->link) ? 0 : SHUTDOWN_DELAY); } break; } diff --git a/drivers/firewire/fw-device.h b/drivers/firewire/fw-device.h index df51732608d..8ef6ec2ca21 100644 --- a/drivers/firewire/fw-device.h +++ b/drivers/firewire/fw-device.h @@ -28,6 +28,7 @@ enum fw_device_state { FW_DEVICE_INITIALIZING, FW_DEVICE_RUNNING, + FW_DEVICE_GONE, FW_DEVICE_SHUTDOWN, }; diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c index ab9c01e462e..6d19828a93a 100644 --- a/drivers/firewire/fw-ohci.c +++ b/drivers/firewire/fw-ohci.c @@ -226,7 +226,7 @@ static inline struct fw_ohci *fw_ohci(struct fw_card *card) #define CONTEXT_DEAD 0x0800 #define CONTEXT_ACTIVE 0x0400 -#define OHCI1394_MAX_AT_REQ_RETRIES 0x2 +#define OHCI1394_MAX_AT_REQ_RETRIES 0xf #define OHCI1394_MAX_AT_RESP_RETRIES 0x2 #define OHCI1394_MAX_PHYS_RESP_RETRIES 0x8 @@ -896,11 +896,11 @@ static void context_stop(struct context *ctx) for (i = 0; i < 10; i++) { reg = reg_read(ctx->ohci, CONTROL_SET(ctx->regs)); if ((reg & CONTEXT_ACTIVE) == 0) - break; + return; - fw_notify("context_stop: still active (0x%08x)\n", reg); mdelay(1); } + fw_error("Error: DMA context still active (0x%08x)\n", reg); } struct driver_data { diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c index e88d5067448..c71c4419d9e 100644 --- a/drivers/firewire/fw-sbp2.c +++ b/drivers/firewire/fw-sbp2.c @@ -168,6 +168,7 @@ struct sbp2_target { int address_high; unsigned int workarounds; unsigned int mgt_orb_timeout; + unsigned int max_payload; int dont_block; /* counter for each logical unit */ int blocked; /* ditto */ @@ -310,14 +311,16 @@ struct sbp2_command_orb { dma_addr_t page_table_bus; }; +#define SBP2_ROM_VALUE_WILDCARD ~0 /* match all */ +#define SBP2_ROM_VALUE_MISSING 0xff000000 /* not present in the unit dir. */ + /* * List of devices with known bugs. * * The firmware_revision field, masked with 0xffff00, is the best * indicator for the type of bridge chip of a device. It yields a few * false positives but this did not break correctly behaving devices - * so far. We use ~0 as a wildcard, since the 24 bit values we get - * from the config rom can never match that. + * so far. */ static const struct { u32 firmware_revision; @@ -339,33 +342,35 @@ static const struct { }, /* Initio bridges, actually only needed for some older ones */ { .firmware_revision = 0x000200, - .model = ~0, + .model = SBP2_ROM_VALUE_WILDCARD, .workarounds = SBP2_WORKAROUND_INQUIRY_36, }, /* PL-3507 bridge with Prolific firmware */ { .firmware_revision = 0x012800, - .model = ~0, + .model = SBP2_ROM_VALUE_WILDCARD, .workarounds = SBP2_WORKAROUND_POWER_CONDITION, }, /* Symbios bridge */ { .firmware_revision = 0xa0b800, - .model = ~0, + .model = SBP2_ROM_VALUE_WILDCARD, .workarounds = SBP2_WORKAROUND_128K_MAX_TRANS, }, /* Datafab MD2-FW2 with Symbios/LSILogic SYM13FW500 bridge */ { .firmware_revision = 0x002600, - .model = ~0, + .model = SBP2_ROM_VALUE_WILDCARD, .workarounds = SBP2_WORKAROUND_128K_MAX_TRANS, }, - /* - * There are iPods (2nd gen, 3rd gen) with model_id == 0, but - * these iPods do not feature the read_capacity bug according - * to one report. Read_capacity behaviour as well as model_id - * could change due to Apple-supplied firmware updates though. + * iPod 2nd generation: needs 128k max transfer size workaround + * iPod 3rd generation: needs fix capacity workaround */ - - /* iPod 4th generation. */ { + { + .firmware_revision = 0x0a2700, + .model = 0x000000, + .workarounds = SBP2_WORKAROUND_128K_MAX_TRANS | + SBP2_WORKAROUND_FIX_CAPACITY, + }, + /* iPod 4th generation */ { .firmware_revision = 0x0a2700, .model = 0x000021, .workarounds = SBP2_WORKAROUND_FIX_CAPACITY, @@ -1092,7 +1097,7 @@ static void sbp2_init_workarounds(struct sbp2_target *tgt, u32 model, continue; if (sbp2_workarounds_table[i].model != model && - sbp2_workarounds_table[i].model != ~0) + sbp2_workarounds_table[i].model != SBP2_ROM_VALUE_WILDCARD) continue; w |= sbp2_workarounds_table[i].workarounds; @@ -1142,20 +1147,28 @@ static int sbp2_probe(struct device *dev) fw_device_get(device); fw_unit_get(unit); - /* Initialize to values that won't match anything in our table. */ - firmware_revision = 0xff000000; - model = 0xff000000; - /* implicit directory ID */ tgt->directory_id = ((unit->directory - device->config_rom) * 4 + CSR_CONFIG_ROM) & 0xffffff; + firmware_revision = SBP2_ROM_VALUE_MISSING; + model = SBP2_ROM_VALUE_MISSING; + if (sbp2_scan_unit_dir(tgt, unit->directory, &model, &firmware_revision) < 0) goto fail_tgt_put; sbp2_init_workarounds(tgt, model, firmware_revision); + /* + * At S100 we can do 512 bytes per packet, at S200 1024 bytes, + * and so on up to 4096 bytes. The SBP-2 max_payload field + * specifies the max payload size as 2 ^ (max_payload + 2), so + * if we set this to max_speed + 7, we get the right value. + */ + tgt->max_payload = min(device->max_speed + 7, 10U); + tgt->max_payload = min(tgt->max_payload, device->card->max_receive - 1); + /* Do the login in a workqueue so we can easily reschedule retries. */ list_for_each_entry(lu, &tgt->lu_list, link) sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5)); @@ -1273,6 +1286,19 @@ static struct fw_driver sbp2_driver = { .id_table = sbp2_id_table, }; +static void sbp2_unmap_scatterlist(struct device *card_device, + struct sbp2_command_orb *orb) +{ + if (scsi_sg_count(orb->cmd)) + dma_unmap_sg(card_device, scsi_sglist(orb->cmd), + scsi_sg_count(orb->cmd), + orb->cmd->sc_data_direction); + + if (orb->request.misc & cpu_to_be32(COMMAND_ORB_PAGE_TABLE_PRESENT)) + dma_unmap_single(card_device, orb->page_table_bus, + sizeof(orb->page_table), DMA_TO_DEVICE); +} + static unsigned int sbp2_status_to_sense_data(u8 *sbp2_status, u8 *sense_data) { @@ -1352,15 +1378,7 @@ complete_command_orb(struct sbp2_orb *base_orb, struct sbp2_status *status) dma_unmap_single(device->card->device, orb->base.request_bus, sizeof(orb->request), DMA_TO_DEVICE); - - if (scsi_sg_count(orb->cmd) > 0) - dma_unmap_sg(device->card->device, scsi_sglist(orb->cmd), - scsi_sg_count(orb->cmd), - orb->cmd->sc_data_direction); - - if (orb->page_table_bus != 0) - dma_unmap_single(device->card->device, orb->page_table_bus, - sizeof(orb->page_table), DMA_TO_DEVICE); + sbp2_unmap_scatterlist(device->card->device, orb); orb->cmd->result = result; orb->done(orb->cmd); @@ -1434,7 +1452,6 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done) struct sbp2_logical_unit *lu = cmd->device->hostdata; struct fw_device *device = fw_device(lu->tgt->unit->device.parent); struct sbp2_command_orb *orb; - unsigned int max_payload; int generation, retval = SCSI_MLQUEUE_HOST_BUSY; /* @@ -1462,17 +1479,9 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done) orb->done = done; orb->cmd = cmd; - orb->request.next.high = cpu_to_be32(SBP2_ORB_NULL); - /* - * At speed 100 we can do 512 bytes per packet, at speed 200, - * 1024 bytes per packet etc. The SBP-2 max_payload field - * specifies the max payload size as 2 ^ (max_payload + 2), so - * if we set this to max_speed + 7, we get the right value. - */ - max_payload = min(device->max_speed + 7, - device->card->max_receive - 1); + orb->request.next.high = cpu_to_be32(SBP2_ORB_NULL); orb->request.misc = cpu_to_be32( - COMMAND_ORB_MAX_PAYLOAD(max_payload) | + COMMAND_ORB_MAX_PAYLOAD(lu->tgt->max_payload) | COMMAND_ORB_SPEED(device->max_speed) | COMMAND_ORB_NOTIFY); @@ -1491,8 +1500,10 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done) orb->base.request_bus = dma_map_single(device->card->device, &orb->request, sizeof(orb->request), DMA_TO_DEVICE); - if (dma_mapping_error(device->card->device, orb->base.request_bus)) + if (dma_mapping_error(device->card->device, orb->base.request_bus)) { + sbp2_unmap_scatterlist(device->card->device, orb); goto out; + } sbp2_send_orb(&orb->base, lu, lu->tgt->node_id, generation, lu->command_block_agent_address + SBP2_ORB_POINTER); diff --git a/drivers/firewire/fw-topology.c b/drivers/firewire/fw-topology.c index c9be6e6948c..8dd6703b55c 100644 --- a/drivers/firewire/fw-topology.c +++ b/drivers/firewire/fw-topology.c @@ -518,6 +518,18 @@ fw_core_handle_bus_reset(struct fw_card *card, struct fw_node *local_node; unsigned long flags; + /* + * If the selfID buffer is not the immediate successor of the + * previously processed one, we cannot reliably compare the + * old and new topologies. + */ + if (!is_next_generation(generation, card->generation) && + card->local_node != NULL) { + fw_notify("skipped bus generations, destroying all nodes\n"); + fw_destroy_nodes(card); + card->bm_retries = 0; + } + spin_lock_irqsave(&card->lock, flags); card->node_id = node_id; diff --git a/drivers/firewire/fw-transaction.h b/drivers/firewire/fw-transaction.h index c9ab12a15f6..1d78e9cc594 100644 --- a/drivers/firewire/fw-transaction.h +++ b/drivers/firewire/fw-transaction.h @@ -276,6 +276,15 @@ static inline void fw_card_put(struct fw_card *card) extern void fw_schedule_bm_work(struct fw_card *card, unsigned long delay); /* + * Check whether new_generation is the immediate successor of old_generation. + * Take counter roll-over at 255 (as per to OHCI) into account. + */ +static inline bool is_next_generation(int new_generation, int old_generation) +{ + return (new_generation & 0xff) == ((old_generation + 1) & 0xff); +} + +/* * The iso packet format allows for an immediate header/payload part * stored in 'header' immediately after the packet info plus an * indirect payload part that is pointer to by the 'payload' field. diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 35e7aea4222..42fb2fd24c0 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -789,6 +789,7 @@ int gpio_request(unsigned gpio, const char *label) } else { status = -EBUSY; module_put(chip->owner); + goto done; } if (chip->request) { diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 9da58145287..6915fb82d0b 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -136,7 +136,7 @@ drm_gem_object_alloc(struct drm_device *dev, size_t size) obj = kcalloc(1, sizeof(*obj), GFP_KERNEL); obj->dev = dev; - obj->filp = shmem_file_setup("drm mm object", size, 0); + obj->filp = shmem_file_setup("drm mm object", size, VM_NORESERVE); if (IS_ERR(obj->filp)) { kfree(obj); return NULL; diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 6b1148fc2cb..b36a5214d8d 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -311,7 +311,7 @@ static int intel_lvds_get_modes(struct drm_connector *connector) if (dev_priv->panel_fixed_mode != NULL) { struct drm_display_mode *mode; - mutex_unlock(&dev->mode_config.mutex); + mutex_lock(&dev->mode_config.mutex); mode = drm_mode_duplicate(dev, dev_priv->panel_fixed_mode); drm_mode_probed_add(connector, mode); mutex_unlock(&dev->mode_config.mutex); diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 5d7640e49dc..6cad69ed21c 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1218,6 +1218,7 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask) } EXPORT_SYMBOL_GPL(hid_connect); +/* a list of devices for which there is a specialized driver on HID bus */ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) }, { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) }, @@ -1476,6 +1477,7 @@ static struct bus_type hid_bus_type = { .uevent = hid_uevent, }; +/* a list of devices that shouldn't be handled by HID core at all */ static const struct hid_device_id hid_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR) }, { HID_USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302) }, @@ -1606,6 +1608,8 @@ static const struct hid_device_id hid_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_SOUNDGRAPH, USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD) }, { HID_USB_DEVICE(USB_VENDOR_ID_SOUNDGRAPH, USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD2) }, { HID_USB_DEVICE(USB_VENDOR_ID_SOUNDGRAPH, USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD3) }, + { HID_USB_DEVICE(USB_VENDOR_ID_SOUNDGRAPH, USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD4) }, + { HID_USB_DEVICE(USB_VENDOR_ID_SOUNDGRAPH, USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD5) }, { HID_USB_DEVICE(USB_VENDOR_ID_TENX, USB_DEVICE_ID_TENX_IBUDDY1) }, { HID_USB_DEVICE(USB_VENDOR_ID_TENX, USB_DEVICE_ID_TENX_IBUDDY2) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index acc1abc834a..e899f510ebe 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -362,6 +362,8 @@ #define USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD 0x0038 #define USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD2 0x0036 #define USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD3 0x0034 +#define USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD4 0x0044 +#define USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD5 0x0045 #define USB_VENDOR_ID_SUN 0x0430 #define USB_DEVICE_ID_RARITAN_KVM_DONGLE 0xcdab diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c index d718b1607d0..25b10dcad90 100644 --- a/drivers/hid/hid-microsoft.c +++ b/drivers/hid/hid-microsoft.c @@ -30,7 +30,7 @@ #define MS_NOGET 0x10 /* - * Microsoft Wireless Desktop Receiver (Model 1028) has several + * Microsoft Wireless Desktop Receiver (Model 1028) has * 'Usage Min/Max' where it ought to have 'Physical Min/Max' */ static void ms_report_fixup(struct hid_device *hdev, __u8 *rdesc, @@ -38,17 +38,12 @@ static void ms_report_fixup(struct hid_device *hdev, __u8 *rdesc, { unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); - if ((quirks & MS_RDESC) && rsize == 571 && rdesc[284] == 0x19 && - rdesc[286] == 0x2a && rdesc[304] == 0x19 && - rdesc[306] == 0x29 && rdesc[352] == 0x1a && - rdesc[355] == 0x2a && rdesc[557] == 0x19 && + if ((quirks & MS_RDESC) && rsize == 571 && rdesc[557] == 0x19 && rdesc[559] == 0x29) { dev_info(&hdev->dev, "fixing up Microsoft Wireless Receiver " "Model 1028 report descriptor\n"); - rdesc[284] = rdesc[304] = rdesc[557] = 0x35; - rdesc[352] = 0x36; - rdesc[286] = rdesc[355] = 0x46; - rdesc[306] = rdesc[559] = 0x45; + rdesc[557] = 0x35; + rdesc[559] = 0x45; } } diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index d73eea382ab..4940e4d70c2 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -656,7 +656,7 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case HIDIOCGSTRING: mutex_lock(&hiddev->existancelock); - if (!hiddev->exist) + if (hiddev->exist) r = hiddev_ioctl_string(hiddev, cmd, user_arg); else r = -ENODEV; diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c index e3018623658..678e34b01e5 100644 --- a/drivers/hwmon/applesmc.c +++ b/drivers/hwmon/applesmc.c @@ -83,7 +83,7 @@ /* * Temperature sensors keys (sp78 - 2 bytes). */ -static const char* temperature_sensors_sets[][36] = { +static const char *temperature_sensors_sets[][41] = { /* Set 0: Macbook Pro */ { "TA0P", "TB0T", "TC0D", "TC0P", "TG0H", "TG0P", "TG0T", "Th0H", "Th1H", "Tm0P", "Ts0P", "Ts1P", NULL }, @@ -135,6 +135,13 @@ static const char* temperature_sensors_sets[][36] = { { "TB0T", "TB1S", "TB1T", "TB2S", "TB2T", "TC0D", "TN0D", "TTF0", "TV0P", "TVFP", "TW0P", "Th0P", "Tp0P", "Tp1P", "TpFP", "Ts0P", "Ts0S", NULL }, +/* Set 16: Mac Pro 3,1 (2 x Quad-Core) */ + { "TA0P", "TCAG", "TCAH", "TCBG", "TCBH", "TC0C", "TC0D", "TC0P", + "TC1C", "TC1D", "TC2C", "TC2D", "TC3C", "TC3D", "TH0P", "TH1P", + "TH2P", "TH3P", "TMAP", "TMAS", "TMBS", "TM0P", "TM0S", "TM1P", + "TM1S", "TM2P", "TM2S", "TM3S", "TM8P", "TM8S", "TM9P", "TM9S", + "TN0C", "TN0D", "TN0H", "TS0C", "Tp0C", "Tp1C", "Tv0S", "Tv1S", + NULL }, }; /* List of keys used to read/write fan speeds */ @@ -1153,6 +1160,16 @@ static SENSOR_DEVICE_ATTR(temp34_input, S_IRUGO, applesmc_show_temperature, NULL, 33); static SENSOR_DEVICE_ATTR(temp35_input, S_IRUGO, applesmc_show_temperature, NULL, 34); +static SENSOR_DEVICE_ATTR(temp36_input, S_IRUGO, + applesmc_show_temperature, NULL, 35); +static SENSOR_DEVICE_ATTR(temp37_input, S_IRUGO, + applesmc_show_temperature, NULL, 36); +static SENSOR_DEVICE_ATTR(temp38_input, S_IRUGO, + applesmc_show_temperature, NULL, 37); +static SENSOR_DEVICE_ATTR(temp39_input, S_IRUGO, + applesmc_show_temperature, NULL, 38); +static SENSOR_DEVICE_ATTR(temp40_input, S_IRUGO, + applesmc_show_temperature, NULL, 39); static struct attribute *temperature_attributes[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, @@ -1190,6 +1207,11 @@ static struct attribute *temperature_attributes[] = { &sensor_dev_attr_temp33_input.dev_attr.attr, &sensor_dev_attr_temp34_input.dev_attr.attr, &sensor_dev_attr_temp35_input.dev_attr.attr, + &sensor_dev_attr_temp36_input.dev_attr.attr, + &sensor_dev_attr_temp37_input.dev_attr.attr, + &sensor_dev_attr_temp38_input.dev_attr.attr, + &sensor_dev_attr_temp39_input.dev_attr.attr, + &sensor_dev_attr_temp40_input.dev_attr.attr, NULL }; @@ -1312,6 +1334,8 @@ static __initdata struct dmi_match_data applesmc_dmi_data[] = { { .accelerometer = 0, .light = 0, .temperature_set = 14 }, /* MacBook Air 2,1: accelerometer, backlight and temperature set 15 */ { .accelerometer = 1, .light = 1, .temperature_set = 15 }, +/* MacPro3,1: temperature set 16 */ + { .accelerometer = 0, .light = 0, .temperature_set = 16 }, }; /* Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1". @@ -1369,6 +1393,10 @@ static __initdata struct dmi_system_id applesmc_whitelist[] = { DMI_MATCH(DMI_BOARD_VENDOR,"Apple"), DMI_MATCH(DMI_PRODUCT_NAME,"MacPro2") }, &applesmc_dmi_data[4]}, + { applesmc_dmi_match, "Apple MacPro3", { + DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), + DMI_MATCH(DMI_PRODUCT_NAME, "MacPro3") }, + &applesmc_dmi_data[16]}, { applesmc_dmi_match, "Apple MacPro", { DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), DMI_MATCH(DMI_PRODUCT_NAME, "MacPro") }, diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index b1c6f68d98c..3dad2299d9c 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -465,6 +465,16 @@ config BLK_DEV_CS5535 It is safe to say Y to this question. +config BLK_DEV_CS5536 + tristate "CS5536 chipset support" + depends on X86_32 + select BLK_DEV_IDEDMA_PCI + help + This option enables support for the AMD CS5536 + companion chip used with the Geode LX processor family. + + If unsure, say N. + config BLK_DEV_HPT366 tristate "HPT36X/37X chipset support" select BLK_DEV_IDEDMA_PCI diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile index c2b9c93f009..d0e3d7d5b46 100644 --- a/drivers/ide/Makefile +++ b/drivers/ide/Makefile @@ -43,6 +43,7 @@ obj-$(CONFIG_BLK_DEV_CMD64X) += cmd64x.o obj-$(CONFIG_BLK_DEV_CS5520) += cs5520.o obj-$(CONFIG_BLK_DEV_CS5530) += cs5530.o obj-$(CONFIG_BLK_DEV_CS5535) += cs5535.o +obj-$(CONFIG_BLK_DEV_CS5536) += cs5536.o obj-$(CONFIG_BLK_DEV_SC1200) += sc1200.o obj-$(CONFIG_BLK_DEV_CY82C693) += cy82c693.o obj-$(CONFIG_BLK_DEV_DELKIN) += delkin_cb.o diff --git a/drivers/ide/cs5536.c b/drivers/ide/cs5536.c new file mode 100644 index 00000000000..7a62db719a4 --- /dev/null +++ b/drivers/ide/cs5536.c @@ -0,0 +1,308 @@ +/* + * CS5536 PATA support + * (C) 2007 Martin K. Petersen <mkp@mkp.net> + * (C) 2009 Bartlomiej Zolnierkiewicz + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Documentation: + * Available from AMD web site. + * + * The IDE timing registers for the CS5536 live in the Geode Machine + * Specific Register file and not PCI config space. Most BIOSes + * virtualize the PCI registers so the chip looks like a standard IDE + * controller. Unfortunately not all implementations get this right. + * In particular some have problems with unaligned accesses to the + * virtualized PCI registers. This driver always does full dword + * writes to work around the issue. Also, in case of a bad BIOS this + * driver can be loaded with the "msr=1" parameter which forces using + * the Machine Specific Registers to configure the device. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/ide.h> +#include <asm/msr.h> + +#define DRV_NAME "cs5536" + +enum { + MSR_IDE_CFG = 0x51300010, + PCI_IDE_CFG = 0x40, + + CFG = 0, + DTC = 2, + CAST = 3, + ETC = 4, + + IDE_CFG_CHANEN = (1 << 1), + IDE_CFG_CABLE = (1 << 17) | (1 << 16), + + IDE_D0_SHIFT = 24, + IDE_D1_SHIFT = 16, + IDE_DRV_MASK = 0xff, + + IDE_CAST_D0_SHIFT = 6, + IDE_CAST_D1_SHIFT = 4, + IDE_CAST_DRV_MASK = 0x3, + + IDE_CAST_CMD_SHIFT = 24, + IDE_CAST_CMD_MASK = 0xff, + + IDE_ETC_UDMA_MASK = 0xc0, +}; + +static int use_msr; + +static int cs5536_read(struct pci_dev *pdev, int reg, u32 *val) +{ + if (unlikely(use_msr)) { + u32 dummy; + + rdmsr(MSR_IDE_CFG + reg, *val, dummy); + return 0; + } + + return pci_read_config_dword(pdev, PCI_IDE_CFG + reg * 4, val); +} + +static int cs5536_write(struct pci_dev *pdev, int reg, int val) +{ + if (unlikely(use_msr)) { + wrmsr(MSR_IDE_CFG + reg, val, 0); + return 0; + } + + return pci_write_config_dword(pdev, PCI_IDE_CFG + reg * 4, val); +} + +static void cs5536_program_dtc(ide_drive_t *drive, u8 tim) +{ + struct pci_dev *pdev = to_pci_dev(drive->hwif->dev); + int dshift = (drive->dn & 1) ? IDE_D1_SHIFT : IDE_D0_SHIFT; + u32 dtc; + + cs5536_read(pdev, DTC, &dtc); + dtc &= ~(IDE_DRV_MASK << dshift); + dtc |= tim << dshift; + cs5536_write(pdev, DTC, dtc); +} + +/** + * cs5536_cable_detect - detect cable type + * @hwif: Port to detect on + * + * Perform cable detection for ATA66 capable cable. + * + * Returns a cable type. + */ + +static u8 cs5536_cable_detect(ide_hwif_t *hwif) +{ + struct pci_dev *pdev = to_pci_dev(hwif->dev); + u32 cfg; + + cs5536_read(pdev, CFG, &cfg); + + if (cfg & IDE_CFG_CABLE) + return ATA_CBL_PATA80; + else + return ATA_CBL_PATA40; +} + +/** + * cs5536_set_pio_mode - PIO timing setup + * @drive: ATA device + * @pio: PIO mode number + */ + +static void cs5536_set_pio_mode(ide_drive_t *drive, const u8 pio) +{ + static const u8 drv_timings[5] = { + 0x98, 0x55, 0x32, 0x21, 0x20, + }; + + static const u8 addr_timings[5] = { + 0x2, 0x1, 0x0, 0x0, 0x0, + }; + + static const u8 cmd_timings[5] = { + 0x99, 0x92, 0x90, 0x22, 0x20, + }; + + struct pci_dev *pdev = to_pci_dev(drive->hwif->dev); + ide_drive_t *pair = ide_get_pair_dev(drive); + int cshift = (drive->dn & 1) ? IDE_CAST_D1_SHIFT : IDE_CAST_D0_SHIFT; + u32 cast; + u8 cmd_pio = pio; + + if (pair) + cmd_pio = min(pio, ide_get_best_pio_mode(pair, 255, 4)); + + drive->drive_data &= (IDE_DRV_MASK << 8); + drive->drive_data |= drv_timings[pio]; + + cs5536_program_dtc(drive, drv_timings[pio]); + + cs5536_read(pdev, CAST, &cast); + + cast &= ~(IDE_CAST_DRV_MASK << cshift); + cast |= addr_timings[pio] << cshift; + + cast &= ~(IDE_CAST_CMD_MASK << IDE_CAST_CMD_SHIFT); + cast |= cmd_timings[cmd_pio] << IDE_CAST_CMD_SHIFT; + + cs5536_write(pdev, CAST, cast); +} + +/** + * cs5536_set_dma_mode - DMA timing setup + * @drive: ATA device + * @mode: DMA mode + */ + +static void cs5536_set_dma_mode(ide_drive_t *drive, const u8 mode) +{ + static const u8 udma_timings[6] = { + 0xc2, 0xc1, 0xc0, 0xc4, 0xc5, 0xc6, + }; + + static const u8 mwdma_timings[3] = { + 0x67, 0x21, 0x20, + }; + + struct pci_dev *pdev = to_pci_dev(drive->hwif->dev); + int dshift = (drive->dn & 1) ? IDE_D1_SHIFT : IDE_D0_SHIFT; + u32 etc; + + cs5536_read(pdev, ETC, &etc); + + if (mode >= XFER_UDMA_0) { + etc &= ~(IDE_DRV_MASK << dshift); + etc |= udma_timings[mode - XFER_UDMA_0] << dshift; + } else { /* MWDMA */ + etc &= ~(IDE_ETC_UDMA_MASK << dshift); + drive->drive_data &= IDE_DRV_MASK; + drive->drive_data |= mwdma_timings[mode - XFER_MW_DMA_0] << 8; + } + + cs5536_write(pdev, ETC, etc); +} + +static void cs5536_dma_start(ide_drive_t *drive) +{ + if (drive->current_speed < XFER_UDMA_0 && + (drive->drive_data >> 8) != (drive->drive_data & IDE_DRV_MASK)) + cs5536_program_dtc(drive, drive->drive_data >> 8); + + ide_dma_start(drive); +} + +static int cs5536_dma_end(ide_drive_t *drive) +{ + int ret = ide_dma_end(drive); + + if (drive->current_speed < XFER_UDMA_0 && + (drive->drive_data >> 8) != (drive->drive_data & IDE_DRV_MASK)) + cs5536_program_dtc(drive, drive->drive_data & IDE_DRV_MASK); + + return ret; +} + +static const struct ide_port_ops cs5536_port_ops = { + .set_pio_mode = cs5536_set_pio_mode, + .set_dma_mode = cs5536_set_dma_mode, + .cable_detect = cs5536_cable_detect, +}; + +static const struct ide_dma_ops cs5536_dma_ops = { + .dma_host_set = ide_dma_host_set, + .dma_setup = ide_dma_setup, + .dma_exec_cmd = ide_dma_exec_cmd, + .dma_start = cs5536_dma_start, + .dma_end = cs5536_dma_end, + .dma_test_irq = ide_dma_test_irq, + .dma_lost_irq = ide_dma_lost_irq, + .dma_timeout = ide_dma_timeout, +}; + +static const struct ide_port_info cs5536_info = { + .name = DRV_NAME, + .port_ops = &cs5536_port_ops, + .dma_ops = &cs5536_dma_ops, + .host_flags = IDE_HFLAG_SINGLE, + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA5, +}; + +/** + * cs5536_init_one + * @dev: PCI device + * @id: Entry in match table + */ + +static int cs5536_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + u32 cfg; + + if (use_msr) + printk(KERN_INFO DRV_NAME ": Using MSR regs instead of PCI\n"); + + cs5536_read(dev, CFG, &cfg); + + if ((cfg & IDE_CFG_CHANEN) == 0) { + printk(KERN_ERR DRV_NAME ": disabled by BIOS\n"); + return -ENODEV; + } + + return ide_pci_init_one(dev, &cs5536_info, NULL); +} + +static const struct pci_device_id cs5536_pci_tbl[] = { + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_IDE), }, + { }, +}; + +static struct pci_driver cs5536_pci_driver = { + .name = DRV_NAME, + .id_table = cs5536_pci_tbl, + .probe = cs5536_init_one, + .remove = ide_pci_remove, + .suspend = ide_pci_suspend, + .resume = ide_pci_resume, +}; + +static int __init cs5536_init(void) +{ + return pci_register_driver(&cs5536_pci_driver); +} + +static void __exit cs5536_exit(void) +{ + pci_unregister_driver(&cs5536_pci_driver); +} + +MODULE_AUTHOR("Martin K. Petersen, Bartlomiej Zolnierkiewicz"); +MODULE_DESCRIPTION("low-level driver for the CS5536 IDE controller"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, cs5536_pci_tbl); + +module_param_named(msr, use_msr, int, 0644); +MODULE_PARM_DESC(msr, "Force using MSR to configure IDE function (Default: 0)"); + +module_init(cs5536_init); +module_exit(cs5536_exit); diff --git a/drivers/ide/icside.c b/drivers/ide/icside.c index 97a35c667ae..415d7e24f2b 100644 --- a/drivers/ide/icside.c +++ b/drivers/ide/icside.c @@ -534,7 +534,7 @@ icside_register_v6(struct icside_state *state, struct expansion_card *ec) d.dma_ops = NULL; } - ret = ide_host_register(host, NULL, hws); + ret = ide_host_register(host, &d, hws); if (ret) goto err_free; diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c index d8f295bdad7..ec7d07fa570 100644 --- a/drivers/ide/ide-acpi.c +++ b/drivers/ide/ide-acpi.c @@ -282,7 +282,7 @@ static int do_drive_get_GTF(ide_drive_t *drive, port = hwif->channel ? drive->dn - 2: drive->dn; DEBPRINT("ENTER: %s at %s, port#: %d, hard_port#: %d\n", - hwif->name, dev->bus_id, port, hwif->channel); + hwif->name, dev_name(dev), port, hwif->channel); if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0) { DEBPRINT("%s drive %d:%d not present\n", diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index cae69372cf4..0bfeb0c79d6 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -787,6 +787,9 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) if (blk_fs_request(rq)) { ide_end_request(drive, 1, rq->nr_sectors); return ide_stopped; + } else if (rq->cmd_type == REQ_TYPE_ATA_PC && !rq->bio) { + ide_end_request(drive, 1, 1); + return ide_stopped; } goto end_request; } diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index cc163319dfb..9ee51adf567 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -418,11 +418,14 @@ void ide_map_sg(ide_drive_t *drive, struct request *rq) ide_hwif_t *hwif = drive->hwif; struct scatterlist *sg = hwif->sg_table; - if (rq->cmd_type != REQ_TYPE_ATA_TASKFILE) { - hwif->sg_nents = blk_rq_map_sg(drive->queue, rq, sg); - } else { + if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) { sg_init_one(sg, rq->buffer, rq->nr_sectors * SECTOR_SIZE); hwif->sg_nents = 1; + } else if (!rq->bio) { + sg_init_one(sg, rq->data, rq->data_len); + hwif->sg_nents = 1; + } else { + hwif->sg_nents = blk_rq_map_sg(drive->queue, rq, sg); } } diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 0db1ed9f5fc..ce0818a993f 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -1467,6 +1467,30 @@ struct ide_host *ide_host_alloc(const struct ide_port_info *d, hw_regs_t **hws) } EXPORT_SYMBOL_GPL(ide_host_alloc); +static void ide_port_free(ide_hwif_t *hwif) +{ + ide_port_free_devices(hwif); + ide_free_port_slot(hwif->index); + kfree(hwif); +} + +static void ide_disable_port(ide_hwif_t *hwif) +{ + struct ide_host *host = hwif->host; + int i; + + printk(KERN_INFO "%s: disabling port\n", hwif->name); + + for (i = 0; i < MAX_HOST_PORTS; i++) { + if (host->ports[i] == hwif) { + host->ports[i] = NULL; + host->n_ports--; + } + } + + ide_port_free(hwif); +} + int ide_host_register(struct ide_host *host, const struct ide_port_info *d, hw_regs_t **hws) { @@ -1507,8 +1531,12 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d, hwif->present = 1; if (hwif->chipset != ide_4drives || !hwif->mate || - !hwif->mate->present) - ide_register_port(hwif); + !hwif->mate->present) { + if (ide_register_port(hwif)) { + ide_disable_port(hwif); + continue; + } + } if (hwif->present) ide_port_tune_devices(hwif); @@ -1521,7 +1549,8 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d, if (hwif_init(hwif) == 0) { printk(KERN_INFO "%s: failed to initialize IDE " "interface\n", hwif->name); - hwif->present = 0; + device_unregister(&hwif->gendev); + ide_disable_port(hwif); continue; } @@ -1660,12 +1689,8 @@ void ide_host_free(struct ide_host *host) int i; ide_host_for_each_port(i, hwif, host) { - if (hwif == NULL) - continue; - - ide_port_free_devices(hwif); - ide_free_port_slot(hwif->index); - kfree(hwif); + if (hwif) + ide_port_free(hwif); } kfree(host); diff --git a/drivers/ide/tx4939ide.c b/drivers/ide/tx4939ide.c index 882f6f07c47..40b0812a045 100644 --- a/drivers/ide/tx4939ide.c +++ b/drivers/ide/tx4939ide.c @@ -261,9 +261,9 @@ static int tx4939ide_build_dmatable(ide_drive_t *drive, struct request *rq) bcount = cur_len; /* * This workaround for zero count seems required. - * (standard ide_build_dmatable do it too) + * (standard ide_build_dmatable does it too) */ - if ((bcount & 0xffff) == 0x0000) + if (bcount == 0x10000) bcount = 0x8000; *table++ = bcount & 0xffff; *table++ = cur_addr; diff --git a/drivers/ide/via82cxxx.c b/drivers/ide/via82cxxx.c index 703c3eeb20a..6092fe3f409 100644 --- a/drivers/ide/via82cxxx.c +++ b/drivers/ide/via82cxxx.c @@ -448,6 +448,11 @@ static int __devinit via_init_one(struct pci_dev *dev, const struct pci_device_i d.host_flags |= IDE_HFLAG_FORCE_LEGACY_IRQS; #endif +#ifdef CONFIG_AMIGAONE + if (machine_is(amigaone)) + d.host_flags |= IDE_HFLAG_FORCE_LEGACY_IRQS; +#endif + d.udma_mask = via_config->udma_mask; vdev = kzalloc(sizeof(*vdev), GFP_KERNEL); diff --git a/drivers/ieee1394/ieee1394.h b/drivers/ieee1394/ieee1394.h index e0ae0d3d747..af320e2c507 100644 --- a/drivers/ieee1394/ieee1394.h +++ b/drivers/ieee1394/ieee1394.h @@ -54,9 +54,7 @@ #define IEEE1394_SPEED_800 0x03 #define IEEE1394_SPEED_1600 0x04 #define IEEE1394_SPEED_3200 0x05 - -/* The current highest tested speed supported by the subsystem */ -#define IEEE1394_SPEED_MAX IEEE1394_SPEED_800 +#define IEEE1394_SPEED_MAX IEEE1394_SPEED_3200 /* Maps speed values above to a string representation */ extern const char *hpsb_speedto_str[]; diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c index dcdb71a7718..2beb8d94f7b 100644 --- a/drivers/ieee1394/ieee1394_core.c +++ b/drivers/ieee1394/ieee1394_core.c @@ -338,6 +338,7 @@ static void build_speed_map(struct hpsb_host *host, int nodecount) u8 cldcnt[nodecount]; u8 *map = host->speed_map; u8 *speedcap = host->speed; + u8 local_link_speed = host->csr.lnk_spd; struct selfid *sid; struct ext_selfid *esid; int i, j, n; @@ -373,8 +374,8 @@ static void build_speed_map(struct hpsb_host *host, int nodecount) if (sid->port2 == SELFID_PORT_CHILD) cldcnt[n]++; speedcap[n] = sid->speed; - if (speedcap[n] > host->csr.lnk_spd) - speedcap[n] = host->csr.lnk_spd; + if (speedcap[n] > local_link_speed) + speedcap[n] = local_link_speed; n--; } } @@ -407,12 +408,11 @@ static void build_speed_map(struct hpsb_host *host, int nodecount) } } -#if SELFID_SPEED_UNKNOWN != IEEE1394_SPEED_MAX - /* assume maximum speed for 1394b PHYs, nodemgr will correct it */ - for (n = 0; n < nodecount; n++) - if (speedcap[n] == SELFID_SPEED_UNKNOWN) - speedcap[n] = IEEE1394_SPEED_MAX; -#endif + /* assume a maximum speed for 1394b PHYs, nodemgr will correct it */ + if (local_link_speed > SELFID_SPEED_UNKNOWN) + for (i = 0; i < nodecount; i++) + if (speedcap[i] == SELFID_SPEED_UNKNOWN) + speedcap[i] = local_link_speed; } diff --git a/drivers/ieee1394/ohci1394.h b/drivers/ieee1394/ohci1394.h index 4320bf01049..7fb8ab9780a 100644 --- a/drivers/ieee1394/ohci1394.h +++ b/drivers/ieee1394/ohci1394.h @@ -26,7 +26,7 @@ #define OHCI1394_DRIVER_NAME "ohci1394" -#define OHCI1394_MAX_AT_REQ_RETRIES 0x2 +#define OHCI1394_MAX_AT_REQ_RETRIES 0xf #define OHCI1394_MAX_AT_RESP_RETRIES 0x2 #define OHCI1394_MAX_PHYS_RESP_RETRIES 0x8 #define OHCI1394_MAX_SELF_ID_ERRORS 16 diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c index ab1034ccb7f..f3fd8657ce4 100644 --- a/drivers/ieee1394/sbp2.c +++ b/drivers/ieee1394/sbp2.c @@ -115,8 +115,8 @@ */ static int sbp2_max_speed = IEEE1394_SPEED_MAX; module_param_named(max_speed, sbp2_max_speed, int, 0644); -MODULE_PARM_DESC(max_speed, "Force max speed " - "(3 = 800Mb/s, 2 = 400Mb/s, 1 = 200Mb/s, 0 = 100Mb/s)"); +MODULE_PARM_DESC(max_speed, "Limit data transfer speed (5 <= 3200, " + "4 <= 1600, 3 <= 800, 2 <= 400, 1 <= 200, 0 = 100 Mb/s)"); /* * Set serialize_io to 0 or N to use dynamically appended lists of command ORBs. @@ -256,7 +256,7 @@ static int sbp2_set_busy_timeout(struct sbp2_lu *); static int sbp2_max_speed_and_size(struct sbp2_lu *); -static const u8 sbp2_speedto_max_payload[] = { 0x7, 0x8, 0x9, 0xA, 0xB, 0xC }; +static const u8 sbp2_speedto_max_payload[] = { 0x7, 0x8, 0x9, 0xa, 0xa, 0xa }; static DEFINE_RWLOCK(sbp2_hi_logical_units_lock); @@ -347,8 +347,8 @@ static struct scsi_host_template sbp2_shost_template = { .sdev_attrs = sbp2_sysfs_sdev_attrs, }; -/* for match-all entries in sbp2_workarounds_table */ -#define SBP2_ROM_VALUE_WILDCARD 0x1000000 +#define SBP2_ROM_VALUE_WILDCARD ~0 /* match all */ +#define SBP2_ROM_VALUE_MISSING 0xff000000 /* not present in the unit dir. */ /* * List of devices with known bugs. @@ -359,60 +359,70 @@ static struct scsi_host_template sbp2_shost_template = { */ static const struct { u32 firmware_revision; - u32 model_id; + u32 model; unsigned workarounds; } sbp2_workarounds_table[] = { /* DViCO Momobay CX-1 with TSB42AA9 bridge */ { .firmware_revision = 0x002800, - .model_id = 0x001010, + .model = 0x001010, .workarounds = SBP2_WORKAROUND_INQUIRY_36 | SBP2_WORKAROUND_MODE_SENSE_8 | SBP2_WORKAROUND_POWER_CONDITION, }, /* DViCO Momobay FX-3A with TSB42AA9A bridge */ { .firmware_revision = 0x002800, - .model_id = 0x000000, + .model = 0x000000, .workarounds = SBP2_WORKAROUND_DELAY_INQUIRY | SBP2_WORKAROUND_POWER_CONDITION, }, /* Initio bridges, actually only needed for some older ones */ { .firmware_revision = 0x000200, - .model_id = SBP2_ROM_VALUE_WILDCARD, + .model = SBP2_ROM_VALUE_WILDCARD, .workarounds = SBP2_WORKAROUND_INQUIRY_36, }, /* PL-3507 bridge with Prolific firmware */ { .firmware_revision = 0x012800, - .model_id = SBP2_ROM_VALUE_WILDCARD, + .model = SBP2_ROM_VALUE_WILDCARD, .workarounds = SBP2_WORKAROUND_POWER_CONDITION, }, /* Symbios bridge */ { .firmware_revision = 0xa0b800, - .model_id = SBP2_ROM_VALUE_WILDCARD, + .model = SBP2_ROM_VALUE_WILDCARD, .workarounds = SBP2_WORKAROUND_128K_MAX_TRANS, }, /* Datafab MD2-FW2 with Symbios/LSILogic SYM13FW500 bridge */ { .firmware_revision = 0x002600, - .model_id = SBP2_ROM_VALUE_WILDCARD, + .model = SBP2_ROM_VALUE_WILDCARD, .workarounds = SBP2_WORKAROUND_128K_MAX_TRANS, }, + /* + * iPod 2nd generation: needs 128k max transfer size workaround + * iPod 3rd generation: needs fix capacity workaround + */ + { + .firmware_revision = 0x0a2700, + .model = 0x000000, + .workarounds = SBP2_WORKAROUND_128K_MAX_TRANS | + SBP2_WORKAROUND_FIX_CAPACITY, + }, /* iPod 4th generation */ { .firmware_revision = 0x0a2700, - .model_id = 0x000021, + .model = 0x000021, .workarounds = SBP2_WORKAROUND_FIX_CAPACITY, }, /* iPod mini */ { .firmware_revision = 0x0a2700, - .model_id = 0x000022, + .model = 0x000022, .workarounds = SBP2_WORKAROUND_FIX_CAPACITY, }, /* iPod mini */ { .firmware_revision = 0x0a2700, - .model_id = 0x000023, + .model = 0x000023, .workarounds = SBP2_WORKAROUND_FIX_CAPACITY, }, /* iPod Photo */ { .firmware_revision = 0x0a2700, - .model_id = 0x00007e, + .model = 0x00007e, .workarounds = SBP2_WORKAROUND_FIX_CAPACITY, } }; @@ -1341,13 +1351,15 @@ static void sbp2_parse_unit_directory(struct sbp2_lu *lu, struct csr1212_keyval *kv; struct csr1212_dentry *dentry; u64 management_agent_addr; - u32 unit_characteristics, firmware_revision; + u32 unit_characteristics, firmware_revision, model; unsigned workarounds; int i; management_agent_addr = 0; unit_characteristics = 0; - firmware_revision = 0; + firmware_revision = SBP2_ROM_VALUE_MISSING; + model = ud->flags & UNIT_DIRECTORY_MODEL_ID ? + ud->model_id : SBP2_ROM_VALUE_MISSING; csr1212_for_each_dir_entry(ud->ne->csr, kv, ud->ud_kv, dentry) { switch (kv->key.id) { @@ -1388,9 +1400,9 @@ static void sbp2_parse_unit_directory(struct sbp2_lu *lu, sbp2_workarounds_table[i].firmware_revision != (firmware_revision & 0xffff00)) continue; - if (sbp2_workarounds_table[i].model_id != + if (sbp2_workarounds_table[i].model != SBP2_ROM_VALUE_WILDCARD && - sbp2_workarounds_table[i].model_id != ud->model_id) + sbp2_workarounds_table[i].model != model) continue; workarounds |= sbp2_workarounds_table[i].workarounds; break; @@ -1403,7 +1415,7 @@ static void sbp2_parse_unit_directory(struct sbp2_lu *lu, NODE_BUS_ARGS(ud->ne->host, ud->ne->nodeid), workarounds, firmware_revision, ud->vendor_id ? ud->vendor_id : ud->ne->vendor_id, - ud->model_id); + model); /* We would need one SCSI host template for each target to adjust * max_sectors on the fly, therefore warn only. */ diff --git a/drivers/lguest/core.c b/drivers/lguest/core.c index 90663e01a56..60156dfdc60 100644 --- a/drivers/lguest/core.c +++ b/drivers/lguest/core.c @@ -224,7 +224,7 @@ int run_guest(struct lg_cpu *cpu, unsigned long __user *user) break; /* If the Guest asked to be stopped, we sleep. The Guest's - * clock timer or LHCALL_BREAK from the Waker will wake us. */ + * clock timer or LHREQ_BREAK from the Waker will wake us. */ if (cpu->halted) { set_current_state(TASK_INTERRUPTIBLE); schedule(); diff --git a/drivers/lguest/lguest_user.c b/drivers/lguest/lguest_user.c index 34bc017b8b3..b8ee103eed5 100644 --- a/drivers/lguest/lguest_user.c +++ b/drivers/lguest/lguest_user.c @@ -307,9 +307,8 @@ static int close(struct inode *inode, struct file *file) * kmalloc()ed string, either of which is ok to hand to kfree(). */ if (!IS_ERR(lg->dead)) kfree(lg->dead); - /* We clear the entire structure, which also marks it as free for the - * next user. */ - memset(lg, 0, sizeof(*lg)); + /* Free the memory allocated to the lguest_struct */ + kfree(lg); /* Release lock and exit. */ mutex_unlock(&lguest_lock); diff --git a/drivers/misc/hpilo.c b/drivers/misc/hpilo.c index 05e29828923..10c421b73ea 100644 --- a/drivers/misc/hpilo.c +++ b/drivers/misc/hpilo.c @@ -758,7 +758,7 @@ static void __exit ilo_exit(void) class_destroy(ilo_class); } -MODULE_VERSION("0.05"); +MODULE_VERSION("0.06"); MODULE_ALIAS(ILO_NAME); MODULE_DESCRIPTION(ILO_NAME); MODULE_AUTHOR("David Altobelli <david.altobelli@hp.com>"); diff --git a/drivers/misc/sgi-xp/xpc_channel.c b/drivers/misc/sgi-xp/xpc_channel.c index 9cd2ebe2a3b..45fd653dbe3 100644 --- a/drivers/misc/sgi-xp/xpc_channel.c +++ b/drivers/misc/sgi-xp/xpc_channel.c @@ -49,9 +49,6 @@ xpc_process_connect(struct xpc_channel *ch, unsigned long *irq_flags) if (ch->flags & (XPC_C_CONNECTED | XPC_C_DISCONNECTING)) return; - - DBUG_ON(ch->local_msgqueue == NULL); - DBUG_ON(ch->remote_msgqueue == NULL); } if (!(ch->flags & XPC_C_OPENREPLY)) { diff --git a/drivers/misc/sgi-xp/xpc_sn2.c b/drivers/misc/sgi-xp/xpc_sn2.c index 82fb9958f22..2e975762c32 100644 --- a/drivers/misc/sgi-xp/xpc_sn2.c +++ b/drivers/misc/sgi-xp/xpc_sn2.c @@ -1106,8 +1106,6 @@ xpc_process_activate_IRQ_rcvd_sn2(void) int n_IRQs_expected; int n_IRQs_detected; - DBUG_ON(xpc_activate_IRQ_rcvd == 0); - spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags); n_IRQs_expected = xpc_activate_IRQ_rcvd; xpc_activate_IRQ_rcvd = 0; @@ -1726,6 +1724,7 @@ xpc_clear_local_msgqueue_flags_sn2(struct xpc_channel *ch) msg = (struct xpc_msg_sn2 *)((u64)ch_sn2->local_msgqueue + (get % ch->local_nentries) * ch->entry_size); + DBUG_ON(!(msg->flags & XPC_M_SN2_READY)); msg->flags = 0; } while (++get < ch_sn2->remote_GP.get); } @@ -1740,11 +1739,18 @@ xpc_clear_remote_msgqueue_flags_sn2(struct xpc_channel *ch) struct xpc_msg_sn2 *msg; s64 put; - put = ch_sn2->w_remote_GP.put; + /* flags are zeroed when the buffer is allocated */ + if (ch_sn2->remote_GP.put < ch->remote_nentries) + return; + + put = max(ch_sn2->w_remote_GP.put, ch->remote_nentries); do { msg = (struct xpc_msg_sn2 *)((u64)ch_sn2->remote_msgqueue + (put % ch->remote_nentries) * ch->entry_size); + DBUG_ON(!(msg->flags & XPC_M_SN2_READY)); + DBUG_ON(!(msg->flags & XPC_M_SN2_DONE)); + DBUG_ON(msg->number != put - ch->remote_nentries); msg->flags = 0; } while (++put < ch_sn2->remote_GP.put); } @@ -1836,6 +1842,7 @@ xpc_process_msg_chctl_flags_sn2(struct xpc_partition *part, int ch_number) */ xpc_clear_remote_msgqueue_flags_sn2(ch); + smp_wmb(); /* ensure flags have been cleared before bte_copy */ ch_sn2->w_remote_GP.put = ch_sn2->remote_GP.put; dev_dbg(xpc_chan, "w_remote_GP.put changed to %ld, partid=%d, " @@ -1934,7 +1941,7 @@ xpc_get_deliverable_payload_sn2(struct xpc_channel *ch) break; get = ch_sn2->w_local_GP.get; - rmb(); /* guarantee that .get loads before .put */ + smp_rmb(); /* guarantee that .get loads before .put */ if (get == ch_sn2->w_remote_GP.put) break; @@ -1956,11 +1963,13 @@ xpc_get_deliverable_payload_sn2(struct xpc_channel *ch) msg = xpc_pull_remote_msg_sn2(ch, get); - DBUG_ON(msg != NULL && msg->number != get); - DBUG_ON(msg != NULL && (msg->flags & XPC_M_SN2_DONE)); - DBUG_ON(msg != NULL && !(msg->flags & XPC_M_SN2_READY)); + if (msg != NULL) { + DBUG_ON(msg->number != get); + DBUG_ON(msg->flags & XPC_M_SN2_DONE); + DBUG_ON(!(msg->flags & XPC_M_SN2_READY)); - payload = &msg->payload; + payload = &msg->payload; + } break; } @@ -2053,7 +2062,7 @@ xpc_allocate_msg_sn2(struct xpc_channel *ch, u32 flags, while (1) { put = ch_sn2->w_local_GP.put; - rmb(); /* guarantee that .put loads before .get */ + smp_rmb(); /* guarantee that .put loads before .get */ if (put - ch_sn2->w_remote_GP.get < ch->local_nentries) { /* There are available message entries. We need to try @@ -2186,7 +2195,7 @@ xpc_send_payload_sn2(struct xpc_channel *ch, u32 flags, void *payload, * The preceding store of msg->flags must occur before the following * load of local_GP->put. */ - mb(); + smp_mb(); /* see if the message is next in line to be sent, if so send it */ @@ -2277,8 +2286,9 @@ xpc_received_payload_sn2(struct xpc_channel *ch, void *payload) dev_dbg(xpc_chan, "msg=0x%p, msg_number=%ld, partid=%d, channel=%d\n", (void *)msg, msg_number, ch->partid, ch->number); - DBUG_ON((((u64)msg - (u64)ch->remote_msgqueue) / ch->entry_size) != + DBUG_ON((((u64)msg - (u64)ch->sn.sn2.remote_msgqueue) / ch->entry_size) != msg_number % ch->remote_nentries); + DBUG_ON(!(msg->flags & XPC_M_SN2_READY)); DBUG_ON(msg->flags & XPC_M_SN2_DONE); msg->flags |= XPC_M_SN2_DONE; @@ -2287,7 +2297,7 @@ xpc_received_payload_sn2(struct xpc_channel *ch, void *payload) * The preceding store of msg->flags must occur before the following * load of local_GP->get. */ - mb(); + smp_mb(); /* * See if this message is next in line to be acknowledged as having diff --git a/drivers/misc/sgi-xp/xpc_uv.c b/drivers/misc/sgi-xp/xpc_uv.c index 91a55b1b103..f17f7d40ea2 100644 --- a/drivers/misc/sgi-xp/xpc_uv.c +++ b/drivers/misc/sgi-xp/xpc_uv.c @@ -1423,7 +1423,7 @@ xpc_send_payload_uv(struct xpc_channel *ch, u32 flags, void *payload, atomic_inc(&ch->n_to_notify); msg_slot->key = key; - wmb(); /* a non-NULL func must hit memory after the key */ + smp_wmb(); /* a non-NULL func must hit memory after the key */ msg_slot->func = func; if (ch->flags & XPC_C_DISCONNECTING) { diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 0efa390978b..99d4b28d52e 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -145,6 +145,16 @@ config MMC_IMX If unsure, say N. +config MMC_MXC + tristate "Freescale i.MX2/3 Multimedia Card Interface support" + depends on ARCH_MXC + help + This selects the Freescale i.MX2/3 Multimedia card Interface. + If you have a i.MX platform with a Multimedia Card slot, + say Y or M here. + + If unsure, say N. + config MMC_TIFM_SD tristate "TI Flash Media MMC/SD Interface support (EXPERIMENTAL)" depends on EXPERIMENTAL && PCI diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 98cab84829b..dedec55861d 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -9,6 +9,7 @@ endif obj-$(CONFIG_MMC_ARMMMCI) += mmci.o obj-$(CONFIG_MMC_PXA) += pxamci.o obj-$(CONFIG_MMC_IMX) += imxmmc.o +obj-$(CONFIG_MMC_MXC) += mxcmmc.o obj-$(CONFIG_MMC_SDHCI) += sdhci.o obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o obj-$(CONFIG_MMC_RICOH_MMC) += ricoh_mmc.o diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 1bcbdd6763a..2909bbc8ad0 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -430,6 +430,8 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) clk = 255; host->cclk = host->mclk / (2 * (clk + 1)); } + if (host->hw_designer == 0x80) + clk |= MCI_FCEN; /* Bug fix in ST IP block */ clk |= MCI_CLK_ENABLE; } @@ -440,15 +442,27 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) case MMC_POWER_OFF: break; case MMC_POWER_UP: - pwr |= MCI_PWR_UP; - break; + /* The ST version does not have this, fall through to POWER_ON */ + if (host->hw_designer != 0x80) { + pwr |= MCI_PWR_UP; + break; + } case MMC_POWER_ON: pwr |= MCI_PWR_ON; break; } - if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) - pwr |= MCI_ROD; + if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) { + if (host->hw_designer != 0x80) + pwr |= MCI_ROD; + else { + /* + * The ST Micro variant use the ROD bit for something + * else and only has OD (Open Drain). + */ + pwr |= MCI_OD; + } + } writel(clk, host->base + MMCICLOCK); @@ -500,6 +514,12 @@ static int mmci_probe(struct amba_device *dev, void *id) } host = mmc_priv(mmc); + /* Bits 12 thru 19 is the designer */ + host->hw_designer = (dev->periphid >> 12) & 0xff; + /* Bits 20 thru 23 is the revison */ + host->hw_revision = (dev->periphid >> 20) & 0xf; + DBG(host, "designer ID = 0x%02x\n", host->hw_designer); + DBG(host, "revision = 0x%01x\n", host->hw_revision); host->clk = clk_get(&dev->dev, NULL); if (IS_ERR(host->clk)) { ret = PTR_ERR(host->clk); @@ -693,6 +713,15 @@ static struct amba_id mmci_ids[] = { .id = 0x00041181, .mask = 0x000fffff, }, + /* ST Micro variants */ + { + .id = 0x00180180, + .mask = 0x00ffffff, + }, + { + .id = 0x00280180, + .mask = 0x00ffffff, + }, { 0, 0 }, }; diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index 0f39c490f02..0441bac1c0e 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -11,13 +11,23 @@ #define MCI_PWR_OFF 0x00 #define MCI_PWR_UP 0x02 #define MCI_PWR_ON 0x03 +#define MCI_DATA2DIREN (1 << 2) +#define MCI_CMDDIREN (1 << 3) +#define MCI_DATA0DIREN (1 << 4) +#define MCI_DATA31DIREN (1 << 5) #define MCI_OD (1 << 6) #define MCI_ROD (1 << 7) +/* The ST Micro version does not have ROD */ +#define MCI_FBCLKEN (1 << 7) +#define MCI_DATA74DIREN (1 << 8) #define MMCICLOCK 0x004 #define MCI_CLK_ENABLE (1 << 8) #define MCI_CLK_PWRSAVE (1 << 9) #define MCI_CLK_BYPASS (1 << 10) +#define MCI_WIDE_BUS (1 << 11) +/* HW flow control on the ST Micro version */ +#define MCI_FCEN (1 << 13) #define MMCIARGUMENT 0x008 #define MMCICOMMAND 0x00c @@ -26,6 +36,10 @@ #define MCI_CPSM_INTERRUPT (1 << 8) #define MCI_CPSM_PENDING (1 << 9) #define MCI_CPSM_ENABLE (1 << 10) +#define MCI_SDIO_SUSP (1 << 11) +#define MCI_ENCMD_COMPL (1 << 12) +#define MCI_NIEN (1 << 13) +#define MCI_CE_ATACMD (1 << 14) #define MMCIRESPCMD 0x010 #define MMCIRESPONSE0 0x014 @@ -39,6 +53,11 @@ #define MCI_DPSM_DIRECTION (1 << 1) #define MCI_DPSM_MODE (1 << 2) #define MCI_DPSM_DMAENABLE (1 << 3) +#define MCI_DPSM_BLOCKSIZE (1 << 4) +#define MCI_DPSM_RWSTART (1 << 8) +#define MCI_DPSM_RWSTOP (1 << 9) +#define MCI_DPSM_RWMOD (1 << 10) +#define MCI_DPSM_SDIOEN (1 << 11) #define MMCIDATACNT 0x030 #define MMCISTATUS 0x034 @@ -63,6 +82,8 @@ #define MCI_RXFIFOEMPTY (1 << 19) #define MCI_TXDATAAVLBL (1 << 20) #define MCI_RXDATAAVLBL (1 << 21) +#define MCI_SDIOIT (1 << 22) +#define MCI_CEATAEND (1 << 23) #define MMCICLEAR 0x038 #define MCI_CMDCRCFAILCLR (1 << 0) @@ -75,6 +96,8 @@ #define MCI_CMDSENTCLR (1 << 7) #define MCI_DATAENDCLR (1 << 8) #define MCI_DATABLOCKENDCLR (1 << 10) +#define MCI_SDIOITC (1 << 22) +#define MCI_CEATAENDC (1 << 23) #define MMCIMASK0 0x03c #define MCI_CMDCRCFAILMASK (1 << 0) @@ -98,6 +121,8 @@ #define MCI_RXFIFOEMPTYMASK (1 << 19) #define MCI_TXDATAAVLBLMASK (1 << 20) #define MCI_RXDATAAVLBLMASK (1 << 21) +#define MCI_SDIOITMASK (1 << 22) +#define MCI_CEATAENDMASK (1 << 23) #define MMCIMASK1 0x040 #define MMCIFIFOCNT 0x048 @@ -136,6 +161,9 @@ struct mmci_host { u32 pwr; struct mmc_platform_data *plat; + u8 hw_designer; + u8 hw_revision:4; + struct timer_list timer; unsigned int oldstat; diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c new file mode 100644 index 00000000000..dda0be4e25d --- /dev/null +++ b/drivers/mmc/host/mxcmmc.c @@ -0,0 +1,880 @@ +/* + * linux/drivers/mmc/host/mxcmmc.c - Freescale i.MX MMCI driver + * + * This is a driver for the SDHC controller found in Freescale MX2/MX3 + * SoCs. It is basically the same hardware as found on MX1 (imxmmc.c). + * Unlike the hardware found on MX1, this hardware just works and does + * not need all the quirks found in imxmmc.c, hence the seperate driver. + * + * Copyright (C) 2008 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de> + * Copyright (C) 2006 Pavel Pisa, PiKRON <ppisa@pikron.com> + * + * derived from pxamci.c by Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/blkdev.h> +#include <linux/dma-mapping.h> +#include <linux/mmc/host.h> +#include <linux/mmc/card.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/gpio.h> + +#include <asm/dma.h> +#include <asm/irq.h> +#include <asm/sizes.h> +#include <mach/mmc.h> + +#ifdef CONFIG_ARCH_MX2 +#include <mach/dma-mx1-mx2.h> +#define HAS_DMA +#endif + +#define DRIVER_NAME "imx-mmc" + +#define MMC_REG_STR_STP_CLK 0x00 +#define MMC_REG_STATUS 0x04 +#define MMC_REG_CLK_RATE 0x08 +#define MMC_REG_CMD_DAT_CONT 0x0C +#define MMC_REG_RES_TO 0x10 +#define MMC_REG_READ_TO 0x14 +#define MMC_REG_BLK_LEN 0x18 +#define MMC_REG_NOB 0x1C +#define MMC_REG_REV_NO 0x20 +#define MMC_REG_INT_CNTR 0x24 +#define MMC_REG_CMD 0x28 +#define MMC_REG_ARG 0x2C +#define MMC_REG_RES_FIFO 0x34 +#define MMC_REG_BUFFER_ACCESS 0x38 + +#define STR_STP_CLK_RESET (1 << 3) +#define STR_STP_CLK_START_CLK (1 << 1) +#define STR_STP_CLK_STOP_CLK (1 << 0) + +#define STATUS_CARD_INSERTION (1 << 31) +#define STATUS_CARD_REMOVAL (1 << 30) +#define STATUS_YBUF_EMPTY (1 << 29) +#define STATUS_XBUF_EMPTY (1 << 28) +#define STATUS_YBUF_FULL (1 << 27) +#define STATUS_XBUF_FULL (1 << 26) +#define STATUS_BUF_UND_RUN (1 << 25) +#define STATUS_BUF_OVFL (1 << 24) +#define STATUS_SDIO_INT_ACTIVE (1 << 14) +#define STATUS_END_CMD_RESP (1 << 13) +#define STATUS_WRITE_OP_DONE (1 << 12) +#define STATUS_DATA_TRANS_DONE (1 << 11) +#define STATUS_READ_OP_DONE (1 << 11) +#define STATUS_WR_CRC_ERROR_CODE_MASK (3 << 10) +#define STATUS_CARD_BUS_CLK_RUN (1 << 8) +#define STATUS_BUF_READ_RDY (1 << 7) +#define STATUS_BUF_WRITE_RDY (1 << 6) +#define STATUS_RESP_CRC_ERR (1 << 5) +#define STATUS_CRC_READ_ERR (1 << 3) +#define STATUS_CRC_WRITE_ERR (1 << 2) +#define STATUS_TIME_OUT_RESP (1 << 1) +#define STATUS_TIME_OUT_READ (1 << 0) +#define STATUS_ERR_MASK 0x2f + +#define CMD_DAT_CONT_CMD_RESP_LONG_OFF (1 << 12) +#define CMD_DAT_CONT_STOP_READWAIT (1 << 11) +#define CMD_DAT_CONT_START_READWAIT (1 << 10) +#define CMD_DAT_CONT_BUS_WIDTH_4 (2 << 8) +#define CMD_DAT_CONT_INIT (1 << 7) +#define CMD_DAT_CONT_WRITE (1 << 4) +#define CMD_DAT_CONT_DATA_ENABLE (1 << 3) +#define CMD_DAT_CONT_RESPONSE_48BIT_CRC (1 << 0) +#define CMD_DAT_CONT_RESPONSE_136BIT (2 << 0) +#define CMD_DAT_CONT_RESPONSE_48BIT (3 << 0) + +#define INT_SDIO_INT_WKP_EN (1 << 18) +#define INT_CARD_INSERTION_WKP_EN (1 << 17) +#define INT_CARD_REMOVAL_WKP_EN (1 << 16) +#define INT_CARD_INSERTION_EN (1 << 15) +#define INT_CARD_REMOVAL_EN (1 << 14) +#define INT_SDIO_IRQ_EN (1 << 13) +#define INT_DAT0_EN (1 << 12) +#define INT_BUF_READ_EN (1 << 4) +#define INT_BUF_WRITE_EN (1 << 3) +#define INT_END_CMD_RES_EN (1 << 2) +#define INT_WRITE_OP_DONE_EN (1 << 1) +#define INT_READ_OP_EN (1 << 0) + +struct mxcmci_host { + struct mmc_host *mmc; + struct resource *res; + void __iomem *base; + int irq; + int detect_irq; + int dma; + int do_dma; + unsigned int power_mode; + struct imxmmc_platform_data *pdata; + + struct mmc_request *req; + struct mmc_command *cmd; + struct mmc_data *data; + + unsigned int dma_nents; + unsigned int datasize; + unsigned int dma_dir; + + u16 rev_no; + unsigned int cmdat; + + struct clk *clk; + + int clock; + + struct work_struct datawork; +}; + +static inline int mxcmci_use_dma(struct mxcmci_host *host) +{ + return host->do_dma; +} + +static void mxcmci_softreset(struct mxcmci_host *host) +{ + int i; + + /* reset sequence */ + writew(STR_STP_CLK_RESET, host->base + MMC_REG_STR_STP_CLK); + writew(STR_STP_CLK_RESET | STR_STP_CLK_START_CLK, + host->base + MMC_REG_STR_STP_CLK); + + for (i = 0; i < 8; i++) + writew(STR_STP_CLK_START_CLK, host->base + MMC_REG_STR_STP_CLK); + + writew(0xff, host->base + MMC_REG_RES_TO); +} + +static void mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data) +{ + unsigned int nob = data->blocks; + unsigned int blksz = data->blksz; + unsigned int datasize = nob * blksz; +#ifdef HAS_DMA + struct scatterlist *sg; + int i; +#endif + if (data->flags & MMC_DATA_STREAM) + nob = 0xffff; + + host->data = data; + data->bytes_xfered = 0; + + writew(nob, host->base + MMC_REG_NOB); + writew(blksz, host->base + MMC_REG_BLK_LEN); + host->datasize = datasize; + +#ifdef HAS_DMA + for_each_sg(data->sg, sg, data->sg_len, i) { + if (sg->offset & 3 || sg->length & 3) { + host->do_dma = 0; + return; + } + } + + if (data->flags & MMC_DATA_READ) { + host->dma_dir = DMA_FROM_DEVICE; + host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg, + data->sg_len, host->dma_dir); + + imx_dma_setup_sg(host->dma, data->sg, host->dma_nents, datasize, + host->res->start + MMC_REG_BUFFER_ACCESS, + DMA_MODE_READ); + } else { + host->dma_dir = DMA_TO_DEVICE; + host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg, + data->sg_len, host->dma_dir); + + imx_dma_setup_sg(host->dma, data->sg, host->dma_nents, datasize, + host->res->start + MMC_REG_BUFFER_ACCESS, + DMA_MODE_WRITE); + } + + wmb(); + + imx_dma_enable(host->dma); +#endif /* HAS_DMA */ +} + +static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd, + unsigned int cmdat) +{ + WARN_ON(host->cmd != NULL); + host->cmd = cmd; + + switch (mmc_resp_type(cmd)) { + case MMC_RSP_R1: /* short CRC, OPCODE */ + case MMC_RSP_R1B:/* short CRC, OPCODE, BUSY */ + cmdat |= CMD_DAT_CONT_RESPONSE_48BIT_CRC; + break; + case MMC_RSP_R2: /* long 136 bit + CRC */ + cmdat |= CMD_DAT_CONT_RESPONSE_136BIT; + break; + case MMC_RSP_R3: /* short */ + cmdat |= CMD_DAT_CONT_RESPONSE_48BIT; + break; + case MMC_RSP_NONE: + break; + default: + dev_err(mmc_dev(host->mmc), "unhandled response type 0x%x\n", + mmc_resp_type(cmd)); + cmd->error = -EINVAL; + return -EINVAL; + } + + if (mxcmci_use_dma(host)) + writel(INT_READ_OP_EN | INT_WRITE_OP_DONE_EN | + INT_END_CMD_RES_EN, + host->base + MMC_REG_INT_CNTR); + else + writel(INT_END_CMD_RES_EN, host->base + MMC_REG_INT_CNTR); + + writew(cmd->opcode, host->base + MMC_REG_CMD); + writel(cmd->arg, host->base + MMC_REG_ARG); + writew(cmdat, host->base + MMC_REG_CMD_DAT_CONT); + + return 0; +} + +static void mxcmci_finish_request(struct mxcmci_host *host, + struct mmc_request *req) +{ + writel(0, host->base + MMC_REG_INT_CNTR); + + host->req = NULL; + host->cmd = NULL; + host->data = NULL; + + mmc_request_done(host->mmc, req); +} + +static int mxcmci_finish_data(struct mxcmci_host *host, unsigned int stat) +{ + struct mmc_data *data = host->data; + int data_error; + +#ifdef HAS_DMA + if (mxcmci_use_dma(host)) { + imx_dma_disable(host->dma); + dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_nents, + host->dma_dir); + } +#endif + + if (stat & STATUS_ERR_MASK) { + dev_dbg(mmc_dev(host->mmc), "request failed. status: 0x%08x\n", + stat); + if (stat & STATUS_CRC_READ_ERR) { + data->error = -EILSEQ; + } else if (stat & STATUS_CRC_WRITE_ERR) { + u32 err_code = (stat >> 9) & 0x3; + if (err_code == 2) /* No CRC response */ + data->error = -ETIMEDOUT; + else + data->error = -EILSEQ; + } else if (stat & STATUS_TIME_OUT_READ) { + data->error = -ETIMEDOUT; + } else { + data->error = -EIO; + } + } else { + data->bytes_xfered = host->datasize; + } + + data_error = data->error; + + host->data = NULL; + + return data_error; +} + +static void mxcmci_read_response(struct mxcmci_host *host, unsigned int stat) +{ + struct mmc_command *cmd = host->cmd; + int i; + u32 a, b, c; + + if (!cmd) + return; + + if (stat & STATUS_TIME_OUT_RESP) { + dev_dbg(mmc_dev(host->mmc), "CMD TIMEOUT\n"); + cmd->error = -ETIMEDOUT; + } else if (stat & STATUS_RESP_CRC_ERR && cmd->flags & MMC_RSP_CRC) { + dev_dbg(mmc_dev(host->mmc), "cmd crc error\n"); + cmd->error = -EILSEQ; + } + + if (cmd->flags & MMC_RSP_PRESENT) { + if (cmd->flags & MMC_RSP_136) { + for (i = 0; i < 4; i++) { + a = readw(host->base + MMC_REG_RES_FIFO); + b = readw(host->base + MMC_REG_RES_FIFO); + cmd->resp[i] = a << 16 | b; + } + } else { + a = readw(host->base + MMC_REG_RES_FIFO); + b = readw(host->base + MMC_REG_RES_FIFO); + c = readw(host->base + MMC_REG_RES_FIFO); + cmd->resp[0] = a << 24 | b << 8 | c >> 8; + } + } +} + +static int mxcmci_poll_status(struct mxcmci_host *host, u32 mask) +{ + u32 stat; + unsigned long timeout = jiffies + HZ; + + do { + stat = readl(host->base + MMC_REG_STATUS); + if (stat & STATUS_ERR_MASK) + return stat; + if (time_after(jiffies, timeout)) + return STATUS_TIME_OUT_READ; + if (stat & mask) + return 0; + cpu_relax(); + } while (1); +} + +static int mxcmci_pull(struct mxcmci_host *host, void *_buf, int bytes) +{ + unsigned int stat; + u32 *buf = _buf; + + while (bytes > 3) { + stat = mxcmci_poll_status(host, + STATUS_BUF_READ_RDY | STATUS_READ_OP_DONE); + if (stat) + return stat; + *buf++ = readl(host->base + MMC_REG_BUFFER_ACCESS); + bytes -= 4; + } + + if (bytes) { + u8 *b = (u8 *)buf; + u32 tmp; + + stat = mxcmci_poll_status(host, + STATUS_BUF_READ_RDY | STATUS_READ_OP_DONE); + if (stat) + return stat; + tmp = readl(host->base + MMC_REG_BUFFER_ACCESS); + memcpy(b, &tmp, bytes); + } + + return 0; +} + +static int mxcmci_push(struct mxcmci_host *host, void *_buf, int bytes) +{ + unsigned int stat; + u32 *buf = _buf; + + while (bytes > 3) { + stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY); + if (stat) + return stat; + writel(*buf++, host->base + MMC_REG_BUFFER_ACCESS); + bytes -= 4; + } + + if (bytes) { + u8 *b = (u8 *)buf; + u32 tmp; + + stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY); + if (stat) + return stat; + + memcpy(&tmp, b, bytes); + writel(tmp, host->base + MMC_REG_BUFFER_ACCESS); + } + + stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY); + if (stat) + return stat; + + return 0; +} + +static int mxcmci_transfer_data(struct mxcmci_host *host) +{ + struct mmc_data *data = host->req->data; + struct scatterlist *sg; + int stat, i; + + host->datasize = 0; + + host->data = data; + host->datasize = 0; + + if (data->flags & MMC_DATA_READ) { + for_each_sg(data->sg, sg, data->sg_len, i) { + stat = mxcmci_pull(host, sg_virt(sg), sg->length); + if (stat) + return stat; + host->datasize += sg->length; + } + } else { + for_each_sg(data->sg, sg, data->sg_len, i) { + stat = mxcmci_push(host, sg_virt(sg), sg->length); + if (stat) + return stat; + host->datasize += sg->length; + } + stat = mxcmci_poll_status(host, STATUS_WRITE_OP_DONE); + if (stat) + return stat; + } + return 0; +} + +static void mxcmci_datawork(struct work_struct *work) +{ + struct mxcmci_host *host = container_of(work, struct mxcmci_host, + datawork); + int datastat = mxcmci_transfer_data(host); + mxcmci_finish_data(host, datastat); + + if (host->req->stop) { + if (mxcmci_start_cmd(host, host->req->stop, 0)) { + mxcmci_finish_request(host, host->req); + return; + } + } else { + mxcmci_finish_request(host, host->req); + } +} + +#ifdef HAS_DMA +static void mxcmci_data_done(struct mxcmci_host *host, unsigned int stat) +{ + struct mmc_data *data = host->data; + int data_error; + + if (!data) + return; + + data_error = mxcmci_finish_data(host, stat); + + mxcmci_read_response(host, stat); + host->cmd = NULL; + + if (host->req->stop) { + if (mxcmci_start_cmd(host, host->req->stop, 0)) { + mxcmci_finish_request(host, host->req); + return; + } + } else { + mxcmci_finish_request(host, host->req); + } +} +#endif /* HAS_DMA */ + +static void mxcmci_cmd_done(struct mxcmci_host *host, unsigned int stat) +{ + mxcmci_read_response(host, stat); + host->cmd = NULL; + + if (!host->data && host->req) { + mxcmci_finish_request(host, host->req); + return; + } + + /* For the DMA case the DMA engine handles the data transfer + * automatically. For non DMA we have to to it ourselves. + * Don't do it in interrupt context though. + */ + if (!mxcmci_use_dma(host) && host->data) + schedule_work(&host->datawork); + +} + +static irqreturn_t mxcmci_irq(int irq, void *devid) +{ + struct mxcmci_host *host = devid; + u32 stat; + + stat = readl(host->base + MMC_REG_STATUS); + writel(stat, host->base + MMC_REG_STATUS); + + dev_dbg(mmc_dev(host->mmc), "%s: 0x%08x\n", __func__, stat); + + if (stat & STATUS_END_CMD_RESP) + mxcmci_cmd_done(host, stat); +#ifdef HAS_DMA + if (mxcmci_use_dma(host) && + (stat & (STATUS_DATA_TRANS_DONE | STATUS_WRITE_OP_DONE))) + mxcmci_data_done(host, stat); +#endif + return IRQ_HANDLED; +} + +static void mxcmci_request(struct mmc_host *mmc, struct mmc_request *req) +{ + struct mxcmci_host *host = mmc_priv(mmc); + unsigned int cmdat = host->cmdat; + + WARN_ON(host->req != NULL); + + host->req = req; + host->cmdat &= ~CMD_DAT_CONT_INIT; +#ifdef HAS_DMA + host->do_dma = 1; +#endif + if (req->data) { + mxcmci_setup_data(host, req->data); + + cmdat |= CMD_DAT_CONT_DATA_ENABLE; + + if (req->data->flags & MMC_DATA_WRITE) + cmdat |= CMD_DAT_CONT_WRITE; + } + + if (mxcmci_start_cmd(host, req->cmd, cmdat)) + mxcmci_finish_request(host, req); +} + +static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios) +{ + unsigned int divider; + int prescaler = 0; + unsigned int clk_in = clk_get_rate(host->clk); + + while (prescaler <= 0x800) { + for (divider = 1; divider <= 0xF; divider++) { + int x; + + x = (clk_in / (divider + 1)); + + if (prescaler) + x /= (prescaler * 2); + + if (x <= clk_ios) + break; + } + if (divider < 0x10) + break; + + if (prescaler == 0) + prescaler = 1; + else + prescaler <<= 1; + } + + writew((prescaler << 4) | divider, host->base + MMC_REG_CLK_RATE); + + dev_dbg(mmc_dev(host->mmc), "scaler: %d divider: %d in: %d out: %d\n", + prescaler, divider, clk_in, clk_ios); +} + +static void mxcmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct mxcmci_host *host = mmc_priv(mmc); +#ifdef HAS_DMA + unsigned int blen; + /* + * use burstlen of 64 in 4 bit mode (--> reg value 0) + * use burstlen of 16 in 1 bit mode (--> reg value 16) + */ + if (ios->bus_width == MMC_BUS_WIDTH_4) + blen = 0; + else + blen = 16; + + imx_dma_config_burstlen(host->dma, blen); +#endif + if (ios->bus_width == MMC_BUS_WIDTH_4) + host->cmdat |= CMD_DAT_CONT_BUS_WIDTH_4; + else + host->cmdat &= ~CMD_DAT_CONT_BUS_WIDTH_4; + + if (host->power_mode != ios->power_mode) { + if (host->pdata && host->pdata->setpower) + host->pdata->setpower(mmc_dev(mmc), ios->vdd); + host->power_mode = ios->power_mode; + if (ios->power_mode == MMC_POWER_ON) + host->cmdat |= CMD_DAT_CONT_INIT; + } + + if (ios->clock) { + mxcmci_set_clk_rate(host, ios->clock); + writew(STR_STP_CLK_START_CLK, host->base + MMC_REG_STR_STP_CLK); + } else { + writew(STR_STP_CLK_STOP_CLK, host->base + MMC_REG_STR_STP_CLK); + } + + host->clock = ios->clock; +} + +static irqreturn_t mxcmci_detect_irq(int irq, void *data) +{ + struct mmc_host *mmc = data; + + dev_dbg(mmc_dev(mmc), "%s\n", __func__); + + mmc_detect_change(mmc, msecs_to_jiffies(250)); + return IRQ_HANDLED; +} + +static int mxcmci_get_ro(struct mmc_host *mmc) +{ + struct mxcmci_host *host = mmc_priv(mmc); + + if (host->pdata && host->pdata->get_ro) + return !!host->pdata->get_ro(mmc_dev(mmc)); + /* + * Board doesn't support read only detection; let the mmc core + * decide what to do. + */ + return -ENOSYS; +} + + +static const struct mmc_host_ops mxcmci_ops = { + .request = mxcmci_request, + .set_ios = mxcmci_set_ios, + .get_ro = mxcmci_get_ro, +}; + +static int mxcmci_probe(struct platform_device *pdev) +{ + struct mmc_host *mmc; + struct mxcmci_host *host = NULL; + struct resource *r; + int ret = 0, irq; + + printk(KERN_INFO "i.MX SDHC driver\n"); + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + irq = platform_get_irq(pdev, 0); + if (!r || irq < 0) + return -EINVAL; + + r = request_mem_region(r->start, resource_size(r), pdev->name); + if (!r) + return -EBUSY; + + mmc = mmc_alloc_host(sizeof(struct mxcmci_host), &pdev->dev); + if (!mmc) { + ret = -ENOMEM; + goto out_release_mem; + } + + mmc->ops = &mxcmci_ops; + mmc->caps = MMC_CAP_4_BIT_DATA; + + /* MMC core transfer sizes tunable parameters */ + mmc->max_hw_segs = 64; + mmc->max_phys_segs = 64; + mmc->max_blk_size = 2048; + mmc->max_blk_count = 65535; + mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; + mmc->max_seg_size = mmc->max_seg_size; + + host = mmc_priv(mmc); + host->base = ioremap(r->start, resource_size(r)); + if (!host->base) { + ret = -ENOMEM; + goto out_free; + } + + host->mmc = mmc; + host->pdata = pdev->dev.platform_data; + + if (host->pdata && host->pdata->ocr_avail) + mmc->ocr_avail = host->pdata->ocr_avail; + else + mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; + + host->res = r; + host->irq = irq; + + host->clk = clk_get(&pdev->dev, "sdhc_clk"); + if (IS_ERR(host->clk)) { + ret = PTR_ERR(host->clk); + goto out_iounmap; + } + clk_enable(host->clk); + + mxcmci_softreset(host); + + host->rev_no = readw(host->base + MMC_REG_REV_NO); + if (host->rev_no != 0x400) { + ret = -ENODEV; + dev_err(mmc_dev(host->mmc), "wrong rev.no. 0x%08x. aborting.\n", + host->rev_no); + goto out_clk_put; + } + + mmc->f_min = clk_get_rate(host->clk) >> 7; + mmc->f_max = clk_get_rate(host->clk) >> 1; + + /* recommended in data sheet */ + writew(0x2db4, host->base + MMC_REG_READ_TO); + + writel(0, host->base + MMC_REG_INT_CNTR); + +#ifdef HAS_DMA + host->dma = imx_dma_request_by_prio(DRIVER_NAME, DMA_PRIO_LOW); + if (host->dma < 0) { + dev_err(mmc_dev(host->mmc), "imx_dma_request_by_prio failed\n"); + ret = -EBUSY; + goto out_clk_put; + } + + r = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (!r) { + ret = -EINVAL; + goto out_free_dma; + } + + ret = imx_dma_config_channel(host->dma, + IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_FIFO, + IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR, + r->start, 0); + if (ret) { + dev_err(mmc_dev(host->mmc), "failed to config DMA channel\n"); + goto out_free_dma; + } +#endif + INIT_WORK(&host->datawork, mxcmci_datawork); + + ret = request_irq(host->irq, mxcmci_irq, 0, DRIVER_NAME, host); + if (ret) + goto out_free_dma; + + platform_set_drvdata(pdev, mmc); + + if (host->pdata && host->pdata->init) { + ret = host->pdata->init(&pdev->dev, mxcmci_detect_irq, + host->mmc); + if (ret) + goto out_free_irq; + } + + mmc_add_host(mmc); + + return 0; + +out_free_irq: + free_irq(host->irq, host); +out_free_dma: +#ifdef HAS_DMA + imx_dma_free(host->dma); +#endif +out_clk_put: + clk_disable(host->clk); + clk_put(host->clk); +out_iounmap: + iounmap(host->base); +out_free: + mmc_free_host(mmc); +out_release_mem: + release_mem_region(host->res->start, resource_size(host->res)); + return ret; +} + +static int mxcmci_remove(struct platform_device *pdev) +{ + struct mmc_host *mmc = platform_get_drvdata(pdev); + struct mxcmci_host *host = mmc_priv(mmc); + + platform_set_drvdata(pdev, NULL); + + mmc_remove_host(mmc); + + if (host->pdata && host->pdata->exit) + host->pdata->exit(&pdev->dev, mmc); + + free_irq(host->irq, host); + iounmap(host->base); +#ifdef HAS_DMA + imx_dma_free(host->dma); +#endif + clk_disable(host->clk); + clk_put(host->clk); + + release_mem_region(host->res->start, resource_size(host->res)); + release_resource(host->res); + + mmc_free_host(mmc); + + return 0; +} + +#ifdef CONFIG_PM +static int mxcmci_suspend(struct platform_device *dev, pm_message_t state) +{ + struct mmc_host *mmc = platform_get_drvdata(dev); + int ret = 0; + + if (mmc) + ret = mmc_suspend_host(mmc, state); + + return ret; +} + +static int mxcmci_resume(struct platform_device *dev) +{ + struct mmc_host *mmc = platform_get_drvdata(dev); + struct mxcmci_host *host; + int ret = 0; + + if (mmc) { + host = mmc_priv(mmc); + ret = mmc_resume_host(mmc); + } + + return ret; +} +#else +#define mxcmci_suspend NULL +#define mxcmci_resume NULL +#endif /* CONFIG_PM */ + +static struct platform_driver mxcmci_driver = { + .probe = mxcmci_probe, + .remove = mxcmci_remove, + .suspend = mxcmci_suspend, + .resume = mxcmci_resume, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + } +}; + +static int __init mxcmci_init(void) +{ + return platform_driver_register(&mxcmci_driver); +} + +static void __exit mxcmci_exit(void) +{ + platform_driver_unregister(&mxcmci_driver); +} + +module_init(mxcmci_init); +module_exit(mxcmci_exit); + +MODULE_DESCRIPTION("i.MX Multimedia Card Interface Driver"); +MODULE_AUTHOR("Sascha Hauer, Pengutronix"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:imx-mmc"); diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index 3c5483b75da..9702ad3774c 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -180,7 +180,15 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data) else DALGN &= ~(1 << host->dma); DDADR(host->dma) = host->sg_dma; - DCSR(host->dma) = DCSR_RUN; + + /* + * workaround for erratum #91: + * only start DMA now if we are doing a read, + * otherwise we wait until CMD/RESP has finished + * before starting DMA. + */ + if (!cpu_is_pxa27x() || data->flags & MMC_DATA_READ) + DCSR(host->dma) = DCSR_RUN; } static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, unsigned int cmdat) @@ -251,23 +259,28 @@ static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat) if (stat & STAT_TIME_OUT_RESPONSE) { cmd->error = -ETIMEDOUT; } else if (stat & STAT_RES_CRC_ERR && cmd->flags & MMC_RSP_CRC) { -#ifdef CONFIG_PXA27x /* * workaround for erratum #42: * Intel PXA27x Family Processor Specification Update Rev 001 * A bogus CRC error can appear if the msb of a 136 bit * response is a one. */ - if (cmd->flags & MMC_RSP_136 && cmd->resp[0] & 0x80000000) { + if (cpu_is_pxa27x() && + (cmd->flags & MMC_RSP_136 && cmd->resp[0] & 0x80000000)) pr_debug("ignoring CRC from command %d - *risky*\n", cmd->opcode); - } else -#endif - cmd->error = -EILSEQ; + else + cmd->error = -EILSEQ; } pxamci_disable_irq(host, END_CMD_RES); if (host->data && !cmd->error) { pxamci_enable_irq(host, DATA_TRAN_DONE); + /* + * workaround for erratum #91, if doing write + * enable DMA late + */ + if (cpu_is_pxa27x() && host->data->flags & MMC_DATA_WRITE) + DCSR(host->dma) = DCSR_RUN; } else { pxamci_finish_request(host, host->mrq); } diff --git a/drivers/mmc/host/ricoh_mmc.c b/drivers/mmc/host/ricoh_mmc.c index be9e7b32b34..f6279051332 100644 --- a/drivers/mmc/host/ricoh_mmc.c +++ b/drivers/mmc/host/ricoh_mmc.c @@ -196,7 +196,7 @@ static void __devexit ricoh_mmc_remove(struct pci_dev *pdev) pci_set_drvdata(pdev, NULL); } -static int ricoh_mmc_suspend(struct pci_dev *pdev, pm_message_t state) +static int ricoh_mmc_suspend_late(struct pci_dev *pdev, pm_message_t state) { struct pci_dev *fw_dev = NULL; @@ -210,7 +210,7 @@ static int ricoh_mmc_suspend(struct pci_dev *pdev, pm_message_t state) return 0; } -static int ricoh_mmc_resume(struct pci_dev *pdev) +static int ricoh_mmc_resume_early(struct pci_dev *pdev) { struct pci_dev *fw_dev = NULL; @@ -229,8 +229,8 @@ static struct pci_driver ricoh_mmc_driver = { .id_table = pci_ids, .probe = ricoh_mmc_probe, .remove = __devexit_p(ricoh_mmc_remove), - .suspend = ricoh_mmc_suspend, - .resume = ricoh_mmc_resume, + .suspend_late = ricoh_mmc_suspend_late, + .resume_early = ricoh_mmc_resume_early, }; /*****************************************************************************\ diff --git a/drivers/mtd/ubi/Kconfig.debug b/drivers/mtd/ubi/Kconfig.debug index 1e2ee22edef..2246f154e2f 100644 --- a/drivers/mtd/ubi/Kconfig.debug +++ b/drivers/mtd/ubi/Kconfig.debug @@ -33,16 +33,6 @@ config MTD_UBI_DEBUG_DISABLE_BGT This option switches the background thread off by default. The thread may be also be enabled/disabled via UBI sysfs. -config MTD_UBI_DEBUG_USERSPACE_IO - bool "Direct user-space write/erase support" - default n - depends on MTD_UBI_DEBUG - help - By default, users cannot directly write and erase individual - eraseblocks of dynamic volumes, and have to use update operation - instead. This option enables this capability - it is very useful for - debugging and testing. - config MTD_UBI_DEBUG_EMULATE_BITFLIPS bool "Emulate flash bit-flips" depends on MTD_UBI_DEBUG diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 9082768cc6c..4048db83aef 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -263,8 +263,12 @@ static ssize_t dev_attribute_show(struct device *dev, return ret; } -/* Fake "release" method for UBI devices */ -static void dev_release(struct device *dev) { } +static void dev_release(struct device *dev) +{ + struct ubi_device *ubi = container_of(dev, struct ubi_device, dev); + + kfree(ubi); +} /** * ubi_sysfs_init - initialize sysfs for an UBI device. @@ -380,7 +384,7 @@ static void free_user_volumes(struct ubi_device *ubi) */ static int uif_init(struct ubi_device *ubi) { - int i, err, do_free = 0; + int i, err; dev_t dev; sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num); @@ -427,13 +431,10 @@ static int uif_init(struct ubi_device *ubi) out_volumes: kill_volumes(ubi); - do_free = 0; out_sysfs: ubi_sysfs_close(ubi); cdev_del(&ubi->cdev); out_unreg: - if (do_free) - free_user_volumes(ubi); unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1); ubi_err("cannot initialize UBI %s, error %d", ubi->ubi_name, err); return err; @@ -947,6 +948,12 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway) if (ubi->bgt_thread) kthread_stop(ubi->bgt_thread); + /* + * Get a reference to the device in order to prevent 'dev_release()' + * from freeing @ubi object. + */ + get_device(&ubi->dev); + uif_close(ubi); ubi_wl_close(ubi); free_internal_volumes(ubi); @@ -958,7 +965,7 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway) vfree(ubi->dbg_peb_buf); #endif ubi_msg("mtd%d is detached from ubi%d", ubi->mtd->index, ubi->ubi_num); - kfree(ubi); + put_device(&ubi->dev); return 0; } diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c index 98cf31ed081..e63c8fc3df3 100644 --- a/drivers/mtd/ubi/cdev.c +++ b/drivers/mtd/ubi/cdev.c @@ -40,9 +40,9 @@ #include <linux/ioctl.h> #include <linux/capability.h> #include <linux/uaccess.h> -#include <linux/smp_lock.h> +#include <linux/compat.h> +#include <linux/math64.h> #include <mtd/ubi-user.h> -#include <asm/div64.h> #include "ubi.h" /** @@ -195,7 +195,6 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count, int err, lnum, off, len, tbuf_size; size_t count_save = count; void *tbuf; - uint64_t tmp; dbg_gen("read %zd bytes from offset %lld of volume %d", count, *offp, vol->vol_id); @@ -225,10 +224,7 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count, return -ENOMEM; len = count > tbuf_size ? tbuf_size : count; - - tmp = *offp; - off = do_div(tmp, vol->usable_leb_size); - lnum = tmp; + lnum = div_u64_rem(*offp, vol->usable_leb_size, &off); do { cond_resched(); @@ -263,12 +259,9 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count, return err ? err : count_save - count; } -#ifdef CONFIG_MTD_UBI_DEBUG_USERSPACE_IO - /* * This function allows to directly write to dynamic UBI volumes, without - * issuing the volume update operation. Available only as a debugging feature. - * Very useful for testing UBI. + * issuing the volume update operation. */ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf, size_t count, loff_t *offp) @@ -279,7 +272,9 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf, int lnum, off, len, tbuf_size, err = 0; size_t count_save = count; char *tbuf; - uint64_t tmp; + + if (!vol->direct_writes) + return -EPERM; dbg_gen("requested: write %zd bytes to offset %lld of volume %u", count, *offp, vol->vol_id); @@ -287,10 +282,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf, if (vol->vol_type == UBI_STATIC_VOLUME) return -EROFS; - tmp = *offp; - off = do_div(tmp, vol->usable_leb_size); - lnum = tmp; - + lnum = div_u64_rem(*offp, vol->usable_leb_size, &off); if (off & (ubi->min_io_size - 1)) { dbg_err("unaligned position"); return -EINVAL; @@ -347,10 +339,6 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf, return err ? err : count_save - count; } -#else -#define vol_cdev_direct_write(file, buf, count, offp) (-EPERM) -#endif /* CONFIG_MTD_UBI_DEBUG_USERSPACE_IO */ - static ssize_t vol_cdev_write(struct file *file, const char __user *buf, size_t count, loff_t *offp) { @@ -402,8 +390,8 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf, return count; } -static int vol_cdev_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static long vol_cdev_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) { int err = 0; struct ubi_volume_desc *desc = file->private_data; @@ -487,7 +475,6 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file, break; } -#ifdef CONFIG_MTD_UBI_DEBUG_USERSPACE_IO /* Logical eraseblock erasure command */ case UBI_IOCEBER: { @@ -518,13 +505,77 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file, err = ubi_wl_flush(ubi); break; } -#endif + + /* Logical eraseblock map command */ + case UBI_IOCEBMAP: + { + struct ubi_map_req req; + + err = copy_from_user(&req, argp, sizeof(struct ubi_map_req)); + if (err) { + err = -EFAULT; + break; + } + err = ubi_leb_map(desc, req.lnum, req.dtype); + break; + } + + /* Logical eraseblock un-map command */ + case UBI_IOCEBUNMAP: + { + int32_t lnum; + + err = get_user(lnum, (__user int32_t *)argp); + if (err) { + err = -EFAULT; + break; + } + err = ubi_leb_unmap(desc, lnum); + break; + } + + /* Check if logical eraseblock is mapped command */ + case UBI_IOCEBISMAP: + { + int32_t lnum; + + err = get_user(lnum, (__user int32_t *)argp); + if (err) { + err = -EFAULT; + break; + } + err = ubi_is_mapped(desc, lnum); + break; + } + + /* Set volume property command*/ + case UBI_IOCSETPROP: + { + struct ubi_set_prop_req req; + + err = copy_from_user(&req, argp, + sizeof(struct ubi_set_prop_req)); + if (err) { + err = -EFAULT; + break; + } + switch (req.property) { + case UBI_PROP_DIRECT_WRITE: + mutex_lock(&ubi->volumes_mutex); + desc->vol->direct_writes = !!req.value; + mutex_unlock(&ubi->volumes_mutex); + break; + default: + err = -EINVAL; + break; + } + break; + } default: err = -ENOTTY; break; } - return err; } @@ -762,8 +813,8 @@ out_free: return err; } -static int ubi_cdev_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static long ubi_cdev_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) { int err = 0; struct ubi_device *ubi; @@ -773,7 +824,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file, if (!capable(CAP_SYS_RESOURCE)) return -EPERM; - ubi = ubi_get_by_major(imajor(inode)); + ubi = ubi_get_by_major(imajor(file->f_mapping->host)); if (!ubi) return -ENODEV; @@ -843,7 +894,6 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file, case UBI_IOCRSVOL: { int pebs; - uint64_t tmp; struct ubi_rsvol_req req; dbg_gen("re-size volume"); @@ -863,9 +913,8 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file, break; } - tmp = req.bytes; - pebs = !!do_div(tmp, desc->vol->usable_leb_size); - pebs += tmp; + pebs = div_u64(req.bytes + desc->vol->usable_leb_size - 1, + desc->vol->usable_leb_size); mutex_lock(&ubi->volumes_mutex); err = ubi_resize_volume(desc, pebs); @@ -909,8 +958,8 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file, return err; } -static int ctrl_cdev_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static long ctrl_cdev_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) { int err = 0; void __user *argp = (void __user *)arg; @@ -986,26 +1035,59 @@ static int ctrl_cdev_ioctl(struct inode *inode, struct file *file, return err; } -/* UBI control character device operations */ -struct file_operations ubi_ctrl_cdev_operations = { - .ioctl = ctrl_cdev_ioctl, - .owner = THIS_MODULE, +#ifdef CONFIG_COMPAT +static long vol_cdev_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + unsigned long translated_arg = (unsigned long)compat_ptr(arg); + + return vol_cdev_ioctl(file, cmd, translated_arg); +} + +static long ubi_cdev_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + unsigned long translated_arg = (unsigned long)compat_ptr(arg); + + return ubi_cdev_ioctl(file, cmd, translated_arg); +} + +static long ctrl_cdev_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + unsigned long translated_arg = (unsigned long)compat_ptr(arg); + + return ctrl_cdev_ioctl(file, cmd, translated_arg); +} +#else +#define vol_cdev_compat_ioctl NULL +#define ubi_cdev_compat_ioctl NULL +#define ctrl_cdev_compat_ioctl NULL +#endif + +/* UBI volume character device operations */ +const struct file_operations ubi_vol_cdev_operations = { + .owner = THIS_MODULE, + .open = vol_cdev_open, + .release = vol_cdev_release, + .llseek = vol_cdev_llseek, + .read = vol_cdev_read, + .write = vol_cdev_write, + .unlocked_ioctl = vol_cdev_ioctl, + .compat_ioctl = vol_cdev_compat_ioctl, }; /* UBI character device operations */ -struct file_operations ubi_cdev_operations = { - .owner = THIS_MODULE, - .ioctl = ubi_cdev_ioctl, - .llseek = no_llseek, +const struct file_operations ubi_cdev_operations = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .unlocked_ioctl = ubi_cdev_ioctl, + .compat_ioctl = ubi_cdev_compat_ioctl, }; -/* UBI volume character device operations */ -struct file_operations ubi_vol_cdev_operations = { - .owner = THIS_MODULE, - .open = vol_cdev_open, - .release = vol_cdev_release, - .llseek = vol_cdev_llseek, - .read = vol_cdev_read, - .write = vol_cdev_write, - .ioctl = vol_cdev_ioctl, +/* UBI control character device operations */ +const struct file_operations ubi_ctrl_cdev_operations = { + .owner = THIS_MODULE, + .unlocked_ioctl = ctrl_cdev_ioctl, + .compat_ioctl = ctrl_cdev_compat_ioctl, }; diff --git a/drivers/mtd/ubi/gluebi.c b/drivers/mtd/ubi/gluebi.c index 6dd4f5e77f8..49cd55ade9c 100644 --- a/drivers/mtd/ubi/gluebi.c +++ b/drivers/mtd/ubi/gluebi.c @@ -28,7 +28,7 @@ * eraseblock size is equivalent to the logical eraseblock size of the volume. */ -#include <asm/div64.h> +#include <linux/math64.h> #include "ubi.h" /** @@ -109,7 +109,6 @@ static int gluebi_read(struct mtd_info *mtd, loff_t from, size_t len, int err = 0, lnum, offs, total_read; struct ubi_volume *vol; struct ubi_device *ubi; - uint64_t tmp = from; dbg_gen("read %zd bytes from offset %lld", len, from); @@ -119,9 +118,7 @@ static int gluebi_read(struct mtd_info *mtd, loff_t from, size_t len, vol = container_of(mtd, struct ubi_volume, gluebi_mtd); ubi = vol->ubi; - offs = do_div(tmp, mtd->erasesize); - lnum = tmp; - + lnum = div_u64_rem(from, mtd->erasesize, &offs); total_read = len; while (total_read) { size_t to_read = mtd->erasesize - offs; @@ -160,7 +157,6 @@ static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len, int err = 0, lnum, offs, total_written; struct ubi_volume *vol; struct ubi_device *ubi; - uint64_t tmp = to; dbg_gen("write %zd bytes to offset %lld", len, to); @@ -173,8 +169,7 @@ static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len, if (ubi->ro_mode) return -EROFS; - offs = do_div(tmp, mtd->erasesize); - lnum = tmp; + lnum = div_u64_rem(to, mtd->erasesize, &offs); if (len % mtd->writesize || offs % mtd->writesize) return -EINVAL; diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c index ecde202a5a1..c3d653ba5ca 100644 --- a/drivers/mtd/ubi/scan.c +++ b/drivers/mtd/ubi/scan.c @@ -42,7 +42,7 @@ #include <linux/err.h> #include <linux/crc32.h> -#include <asm/div64.h> +#include <linux/math64.h> #include "ubi.h" #ifdef CONFIG_MTD_UBI_DEBUG_PARANOID @@ -904,10 +904,8 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi) dbg_msg("scanning is finished"); /* Calculate mean erase counter */ - if (si->ec_count) { - do_div(si->ec_sum, si->ec_count); - si->mean_ec = si->ec_sum; - } + if (si->ec_count) + si->mean_ec = div_u64(si->ec_sum, si->ec_count); if (si->is_empty) ubi_msg("empty MTD device detected"); diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index 4a8ec485c91..c055511bb1b 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -206,6 +206,7 @@ struct ubi_volume_desc; * @upd_marker: %1 if the update marker is set for this volume * @updating: %1 if the volume is being updated * @changing_leb: %1 if the atomic LEB change ioctl command is in progress + * @direct_writes: %1 if direct writes are enabled for this volume * * @gluebi_desc: gluebi UBI volume descriptor * @gluebi_refcount: reference count of the gluebi MTD device @@ -253,6 +254,7 @@ struct ubi_volume { unsigned int upd_marker:1; unsigned int updating:1; unsigned int changing_leb:1; + unsigned int direct_writes:1; #ifdef CONFIG_MTD_UBI_GLUEBI /* @@ -304,7 +306,8 @@ struct ubi_wl_entry; * @vtbl_size: size of the volume table in bytes * @vtbl: in-RAM volume table copy * @volumes_mutex: protects on-flash volume table and serializes volume - * changes, like creation, deletion, update, re-size and re-name + * changes, like creation, deletion, update, re-size, + * re-name and set property * * @max_ec: current highest erase counter value * @mean_ec: current mean erase counter value @@ -449,9 +452,9 @@ struct ubi_device { }; extern struct kmem_cache *ubi_wl_entry_slab; -extern struct file_operations ubi_ctrl_cdev_operations; -extern struct file_operations ubi_cdev_operations; -extern struct file_operations ubi_vol_cdev_operations; +extern const struct file_operations ubi_ctrl_cdev_operations; +extern const struct file_operations ubi_cdev_operations; +extern const struct file_operations ubi_vol_cdev_operations; extern struct class *ubi_class; extern struct mutex ubi_devices_mutex; diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c index 8b89cc18ff0..6b4d1ae891a 100644 --- a/drivers/mtd/ubi/upd.c +++ b/drivers/mtd/ubi/upd.c @@ -40,7 +40,7 @@ #include <linux/err.h> #include <linux/uaccess.h> -#include <asm/div64.h> +#include <linux/math64.h> #include "ubi.h" /** @@ -89,7 +89,6 @@ static int clear_update_marker(struct ubi_device *ubi, struct ubi_volume *vol, long long bytes) { int err; - uint64_t tmp; struct ubi_vtbl_record vtbl_rec; dbg_gen("clear update marker for volume %d", vol->vol_id); @@ -101,9 +100,9 @@ static int clear_update_marker(struct ubi_device *ubi, struct ubi_volume *vol, if (vol->vol_type == UBI_STATIC_VOLUME) { vol->corrupted = 0; - vol->used_bytes = tmp = bytes; - vol->last_eb_bytes = do_div(tmp, vol->usable_leb_size); - vol->used_ebs = tmp; + vol->used_bytes = bytes; + vol->used_ebs = div_u64_rem(bytes, vol->usable_leb_size, + &vol->last_eb_bytes); if (vol->last_eb_bytes) vol->used_ebs += 1; else @@ -131,7 +130,6 @@ int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol, long long bytes) { int i, err; - uint64_t tmp; dbg_gen("start update of volume %d, %llu bytes", vol->vol_id, bytes); ubi_assert(!vol->updating && !vol->changing_leb); @@ -161,9 +159,8 @@ int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol, if (!vol->upd_buf) return -ENOMEM; - tmp = bytes; - vol->upd_ebs = !!do_div(tmp, vol->usable_leb_size); - vol->upd_ebs += tmp; + vol->upd_ebs = div_u64(bytes + vol->usable_leb_size - 1, + vol->usable_leb_size); vol->upd_bytes = bytes; vol->upd_received = 0; return 0; @@ -282,7 +279,6 @@ static int write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol, const void __user *buf, int count) { - uint64_t tmp; int lnum, offs, err = 0, len, to_write = count; dbg_gen("write %d of %lld bytes, %lld already passed", @@ -291,10 +287,7 @@ int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol, if (ubi->ro_mode) return -EROFS; - tmp = vol->upd_received; - offs = do_div(tmp, vol->usable_leb_size); - lnum = tmp; - + lnum = div_u64_rem(vol->upd_received, vol->usable_leb_size, &offs); if (vol->upd_received + count > vol->upd_bytes) to_write = count = vol->upd_bytes - vol->upd_received; diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c index 22e1d7398fc..df5483562b7 100644 --- a/drivers/mtd/ubi/vmt.c +++ b/drivers/mtd/ubi/vmt.c @@ -24,7 +24,7 @@ */ #include <linux/err.h> -#include <asm/div64.h> +#include <linux/math64.h> #include "ubi.h" #ifdef CONFIG_MTD_UBI_DEBUG_PARANOID @@ -205,7 +205,6 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) int i, err, vol_id = req->vol_id, do_free = 1; struct ubi_volume *vol; struct ubi_vtbl_record vtbl_rec; - uint64_t bytes; dev_t dev; if (ubi->ro_mode) @@ -255,10 +254,8 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) /* Calculate how many eraseblocks are requested */ vol->usable_leb_size = ubi->leb_size - ubi->leb_size % req->alignment; - bytes = req->bytes; - if (do_div(bytes, vol->usable_leb_size)) - vol->reserved_pebs = 1; - vol->reserved_pebs += bytes; + vol->reserved_pebs += div_u64(req->bytes + vol->usable_leb_size - 1, + vol->usable_leb_size); /* Reserve physical eraseblocks */ if (vol->reserved_pebs > ubi->avail_pebs) { @@ -301,10 +298,10 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) vol->used_bytes = (long long)vol->used_ebs * vol->usable_leb_size; } else { - bytes = vol->used_bytes; - vol->last_eb_bytes = do_div(bytes, vol->usable_leb_size); - vol->used_ebs = bytes; - if (vol->last_eb_bytes) + vol->used_ebs = div_u64_rem(vol->used_bytes, + vol->usable_leb_size, + &vol->last_eb_bytes); + if (vol->last_eb_bytes != 0) vol->used_ebs += 1; else vol->last_eb_bytes = vol->usable_leb_size; diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 26474c92193..c986978ce76 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -31,7 +31,7 @@ char e1000_driver_name[] = "e1000"; static char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver"; -#define DRV_VERSION "7.3.20-k3-NAPI" +#define DRV_VERSION "7.3.21-k3-NAPI" const char e1000_driver_version[] = DRV_VERSION; static const char e1000_copyright[] = "Copyright (c) 1999-2006 Intel Corporation."; @@ -3712,7 +3712,7 @@ static irqreturn_t e1000_intr(int irq, void *data) struct e1000_hw *hw = &adapter->hw; u32 rctl, icr = er32(ICR); - if (unlikely(!icr)) + if (unlikely((!icr) || test_bit(__E1000_RESETTING, &adapter->flags))) return IRQ_NONE; /* Not our interrupt */ /* IMS will not auto-mask if INT_ASSERTED is not set, and if it is diff --git a/drivers/net/gianfar_mii.c b/drivers/net/gianfar_mii.c index f3706e415b4..f49a426ad68 100644 --- a/drivers/net/gianfar_mii.c +++ b/drivers/net/gianfar_mii.c @@ -234,6 +234,8 @@ static int gfar_mdio_probe(struct of_device *ofdev, if (NULL == new_bus) return -ENOMEM; + device_init_wakeup(&ofdev->dev, 1); + new_bus->name = "Gianfar MII Bus", new_bus->read = &gfar_mdio_read, new_bus->write = &gfar_mdio_write, diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c index f5e2e7235fc..13ca73f96ec 100644 --- a/drivers/net/igb/e1000_82575.c +++ b/drivers/net/igb/e1000_82575.c @@ -699,11 +699,18 @@ static s32 igb_check_for_link_82575(struct e1000_hw *hw) /* SGMII link check is done through the PCS register. */ if ((hw->phy.media_type != e1000_media_type_copper) || - (igb_sgmii_active_82575(hw))) + (igb_sgmii_active_82575(hw))) { ret_val = igb_get_pcs_speed_and_duplex_82575(hw, &speed, &duplex); - else + /* + * Use this flag to determine if link needs to be checked or + * not. If we have link clear the flag so that we do not + * continue to check for link. + */ + hw->mac.get_link_status = !hw->mac.serdes_has_link; + } else { ret_val = igb_check_for_copper_link(hw); + } return ret_val; } diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h index 5a27825cc48..aebef8e48e7 100644 --- a/drivers/net/igb/igb.h +++ b/drivers/net/igb/igb.h @@ -300,11 +300,10 @@ struct igb_adapter { #define IGB_FLAG_HAS_MSI (1 << 0) #define IGB_FLAG_MSI_ENABLE (1 << 1) -#define IGB_FLAG_HAS_DCA (1 << 2) -#define IGB_FLAG_DCA_ENABLED (1 << 3) -#define IGB_FLAG_IN_NETPOLL (1 << 5) -#define IGB_FLAG_QUAD_PORT_A (1 << 6) -#define IGB_FLAG_NEED_CTX_IDX (1 << 7) +#define IGB_FLAG_DCA_ENABLED (1 << 2) +#define IGB_FLAG_IN_NETPOLL (1 << 3) +#define IGB_FLAG_QUAD_PORT_A (1 << 4) +#define IGB_FLAG_NEED_CTX_IDX (1 << 5) enum e1000_state_t { __IGB_TESTING, diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index b82b0fb2056..a50db5398fa 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -206,10 +206,11 @@ static int __init igb_init_module(void) global_quad_port_a = 0; - ret = pci_register_driver(&igb_driver); #ifdef CONFIG_IGB_DCA dca_register_notify(&dca_notifier); #endif + + ret = pci_register_driver(&igb_driver); return ret; } @@ -1156,11 +1157,10 @@ static int __devinit igb_probe(struct pci_dev *pdev, /* set flags */ switch (hw->mac.type) { - case e1000_82576: case e1000_82575: - adapter->flags |= IGB_FLAG_HAS_DCA; adapter->flags |= IGB_FLAG_NEED_CTX_IDX; break; + case e1000_82576: default: break; } @@ -1310,8 +1310,7 @@ static int __devinit igb_probe(struct pci_dev *pdev, goto err_register; #ifdef CONFIG_IGB_DCA - if ((adapter->flags & IGB_FLAG_HAS_DCA) && - (dca_add_requester(&pdev->dev) == 0)) { + if (dca_add_requester(&pdev->dev) == 0) { adapter->flags |= IGB_FLAG_DCA_ENABLED; dev_info(&pdev->dev, "DCA enabled\n"); /* Always use CB2 mode, difference is masked @@ -1835,11 +1834,11 @@ static void igb_setup_rctl(struct igb_adapter *adapter) rctl |= E1000_RCTL_SECRC; /* - * disable store bad packets, long packet enable, and clear size bits. + * disable store bad packets and clear size bits. */ - rctl &= ~(E1000_RCTL_SBP | E1000_RCTL_LPE | E1000_RCTL_SZ_256); + rctl &= ~(E1000_RCTL_SBP | E1000_RCTL_SZ_256); - if (adapter->netdev->mtu > ETH_DATA_LEN) + /* enable LPE when to prevent packets larger than max_frame_size */ rctl |= E1000_RCTL_LPE; /* Setup buffer sizes */ @@ -1865,7 +1864,7 @@ static void igb_setup_rctl(struct igb_adapter *adapter) */ /* allocations using alloc_page take too long for regular MTU * so only enable packet split for jumbo frames */ - if (rctl & E1000_RCTL_LPE) { + if (adapter->netdev->mtu > ETH_DATA_LEN) { adapter->rx_ps_hdr_size = IGB_RXBUFFER_128; srrctl |= adapter->rx_ps_hdr_size << E1000_SRRCTL_BSIZEHDRSIZE_SHIFT; @@ -3473,19 +3472,16 @@ static int __igb_notify_dca(struct device *dev, void *data) struct e1000_hw *hw = &adapter->hw; unsigned long event = *(unsigned long *)data; - if (!(adapter->flags & IGB_FLAG_HAS_DCA)) - goto out; - switch (event) { case DCA_PROVIDER_ADD: /* if already enabled, don't do it again */ if (adapter->flags & IGB_FLAG_DCA_ENABLED) break; - adapter->flags |= IGB_FLAG_DCA_ENABLED; /* Always use CB2 mode, difference is masked * in the CB driver. */ wr32(E1000_DCA_CTRL, 2); if (dca_add_requester(dev) == 0) { + adapter->flags |= IGB_FLAG_DCA_ENABLED; dev_info(&adapter->pdev->dev, "DCA enabled\n"); igb_setup_dca(adapter); break; @@ -3502,7 +3498,7 @@ static int __igb_notify_dca(struct device *dev, void *data) } break; } -out: + return 0; } diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index a75a31005fd..9c78c963b72 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -210,7 +210,7 @@ #define MAX_CMD_DESCRIPTORS_HOST 1024 #define MAX_RCV_DESCRIPTORS_1G 2048 #define MAX_RCV_DESCRIPTORS_10G 4096 -#define MAX_JUMBO_RCV_DESCRIPTORS 512 +#define MAX_JUMBO_RCV_DESCRIPTORS 1024 #define MAX_LRO_RCV_DESCRIPTORS 8 #define MAX_RCVSTATUS_DESCRIPTORS MAX_RCV_DESCRIPTORS #define MAX_JUMBO_RCV_DESC MAX_JUMBO_RCV_DESCRIPTORS diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index ca7c8d8050c..ffd37bea162 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -947,8 +947,10 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose) } for (i = 0; i < n; i++) { if (netxen_rom_fast_read(adapter, 8*i + 4*offset, &val) != 0 || - netxen_rom_fast_read(adapter, 8*i + 4*offset + 4, &addr) != 0) + netxen_rom_fast_read(adapter, 8*i + 4*offset + 4, &addr) != 0) { + kfree(buf); return -EIO; + } buf[i].addr = addr; buf[i].data = val; diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c index 72fd9e97c19..b2dcdb5ed8b 100644 --- a/drivers/net/r6040.c +++ b/drivers/net/r6040.c @@ -438,7 +438,6 @@ static void r6040_down(struct net_device *dev) { struct r6040_private *lp = netdev_priv(dev); void __iomem *ioaddr = lp->base; - struct pci_dev *pdev = lp->pdev; int limit = 2048; u16 *adrp; u16 cmd; diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 7673fd92eaf..ab0e09bf154 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -676,9 +676,8 @@ static int efx_init_port(struct efx_nic *efx) rc = efx->phy_op->init(efx); if (rc) return rc; - efx->phy_op->reconfigure(efx); - mutex_lock(&efx->mac_lock); + efx->phy_op->reconfigure(efx); rc = falcon_switch_mac(efx); mutex_unlock(&efx->mac_lock); if (rc) @@ -686,7 +685,7 @@ static int efx_init_port(struct efx_nic *efx) efx->mac_op->reconfigure(efx); efx->port_initialized = true; - efx->stats_enabled = true; + efx_stats_enable(efx); return 0; fail: @@ -735,6 +734,7 @@ static void efx_fini_port(struct efx_nic *efx) if (!efx->port_initialized) return; + efx_stats_disable(efx); efx->phy_op->fini(efx); efx->port_initialized = false; @@ -1361,6 +1361,20 @@ static int efx_net_stop(struct net_device *net_dev) return 0; } +void efx_stats_disable(struct efx_nic *efx) +{ + spin_lock(&efx->stats_lock); + ++efx->stats_disable_count; + spin_unlock(&efx->stats_lock); +} + +void efx_stats_enable(struct efx_nic *efx) +{ + spin_lock(&efx->stats_lock); + --efx->stats_disable_count; + spin_unlock(&efx->stats_lock); +} + /* Context: process, dev_base_lock or RTNL held, non-blocking. */ static struct net_device_stats *efx_net_stats(struct net_device *net_dev) { @@ -1369,12 +1383,12 @@ static struct net_device_stats *efx_net_stats(struct net_device *net_dev) struct net_device_stats *stats = &net_dev->stats; /* Update stats if possible, but do not wait if another thread - * is updating them (or resetting the NIC); slightly stale - * stats are acceptable. + * is updating them or if MAC stats fetches are temporarily + * disabled; slightly stale stats are acceptable. */ if (!spin_trylock(&efx->stats_lock)) return stats; - if (efx->stats_enabled) { + if (!efx->stats_disable_count) { efx->mac_op->update_stats(efx); falcon_update_nic_stats(efx); } @@ -1622,16 +1636,12 @@ static void efx_unregister_netdev(struct efx_nic *efx) /* Tears down the entire software state and most of the hardware state * before reset. */ -void efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd) +void efx_reset_down(struct efx_nic *efx, enum reset_type method, + struct ethtool_cmd *ecmd) { EFX_ASSERT_RESET_SERIALISED(efx); - /* The net_dev->get_stats handler is quite slow, and will fail - * if a fetch is pending over reset. Serialise against it. */ - spin_lock(&efx->stats_lock); - efx->stats_enabled = false; - spin_unlock(&efx->stats_lock); - + efx_stats_disable(efx); efx_stop_all(efx); mutex_lock(&efx->mac_lock); mutex_lock(&efx->spi_lock); @@ -1639,6 +1649,8 @@ void efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd) efx->phy_op->get_settings(efx, ecmd); efx_fini_channels(efx); + if (efx->port_initialized && method != RESET_TYPE_INVISIBLE) + efx->phy_op->fini(efx); } /* This function will always ensure that the locks acquired in @@ -1646,7 +1658,8 @@ void efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd) * that we were unable to reinitialise the hardware, and the * driver should be disabled. If ok is false, then the rx and tx * engines are not restarted, pending a RESET_DISABLE. */ -int efx_reset_up(struct efx_nic *efx, struct ethtool_cmd *ecmd, bool ok) +int efx_reset_up(struct efx_nic *efx, enum reset_type method, + struct ethtool_cmd *ecmd, bool ok) { int rc; @@ -1658,6 +1671,15 @@ int efx_reset_up(struct efx_nic *efx, struct ethtool_cmd *ecmd, bool ok) ok = false; } + if (efx->port_initialized && method != RESET_TYPE_INVISIBLE) { + if (ok) { + rc = efx->phy_op->init(efx); + if (rc) + ok = false; + } else + efx->port_initialized = false; + } + if (ok) { efx_init_channels(efx); @@ -1670,7 +1692,7 @@ int efx_reset_up(struct efx_nic *efx, struct ethtool_cmd *ecmd, bool ok) if (ok) { efx_start_all(efx); - efx->stats_enabled = true; + efx_stats_enable(efx); } return rc; } @@ -1702,7 +1724,7 @@ static int efx_reset(struct efx_nic *efx) EFX_INFO(efx, "resetting (%d)\n", method); - efx_reset_down(efx, &ecmd); + efx_reset_down(efx, method, &ecmd); rc = falcon_reset_hw(efx, method); if (rc) { @@ -1721,10 +1743,10 @@ static int efx_reset(struct efx_nic *efx) /* Leave device stopped if necessary */ if (method == RESET_TYPE_DISABLE) { - efx_reset_up(efx, &ecmd, false); + efx_reset_up(efx, method, &ecmd, false); rc = -EIO; } else { - rc = efx_reset_up(efx, &ecmd, true); + rc = efx_reset_up(efx, method, &ecmd, true); } out_disable: @@ -1876,6 +1898,7 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, efx->rx_checksum_enabled = true; spin_lock_init(&efx->netif_stop_lock); spin_lock_init(&efx->stats_lock); + efx->stats_disable_count = 1; mutex_init(&efx->mac_lock); efx->mac_op = &efx_dummy_mac_operations; efx->phy_op = &efx_dummy_phy_operations; diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h index 0dd7a532c78..55d0f131b0e 100644 --- a/drivers/net/sfc/efx.h +++ b/drivers/net/sfc/efx.h @@ -36,13 +36,16 @@ extern void efx_process_channel_now(struct efx_channel *channel); extern void efx_flush_queues(struct efx_nic *efx); /* Ports */ +extern void efx_stats_disable(struct efx_nic *efx); +extern void efx_stats_enable(struct efx_nic *efx); extern void efx_reconfigure_port(struct efx_nic *efx); extern void __efx_reconfigure_port(struct efx_nic *efx); /* Reset handling */ -extern void efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd); -extern int efx_reset_up(struct efx_nic *efx, struct ethtool_cmd *ecmd, - bool ok); +extern void efx_reset_down(struct efx_nic *efx, enum reset_type method, + struct ethtool_cmd *ecmd); +extern int efx_reset_up(struct efx_nic *efx, enum reset_type method, + struct ethtool_cmd *ecmd, bool ok); /* Global */ extern void efx_schedule_reset(struct efx_nic *efx, enum reset_type type); diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 53d259e9018..7b5924c039b 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -219,9 +219,6 @@ int efx_ethtool_set_settings(struct net_device *net_dev, struct efx_nic *efx = netdev_priv(net_dev); int rc; - if (EFX_WORKAROUND_13963(efx) && !ecmd->autoneg) - return -EINVAL; - /* Falcon GMAC does not support 1000Mbps HD */ if (ecmd->speed == SPEED_1000 && ecmd->duplex != DUPLEX_FULL) { EFX_LOG(efx, "rejecting unsupported 1000Mbps HD" diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index 5b9f2d9cc4e..d5378e60fcd 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -824,10 +824,6 @@ static void falcon_handle_rx_not_ok(struct efx_rx_queue *rx_queue, rx_ev_pause_frm ? " [PAUSE]" : ""); } #endif - - if (unlikely(rx_ev_eth_crc_err && EFX_WORKAROUND_10750(efx) && - efx->phy_type == PHY_TYPE_SFX7101)) - tenxpress_crc_err(efx); } /* Handle receive events that are not in-order. */ @@ -1887,7 +1883,7 @@ static int falcon_reset_macs(struct efx_nic *efx) /* MAC stats will fail whilst the TX fifo is draining. Serialise * the drain sequence with the statistics fetch */ - spin_lock(&efx->stats_lock); + efx_stats_disable(efx); falcon_read(efx, ®, MAC0_CTRL_REG_KER); EFX_SET_OWORD_FIELD(reg, TXFIFO_DRAIN_EN_B0, 1); @@ -1917,7 +1913,7 @@ static int falcon_reset_macs(struct efx_nic *efx) udelay(10); } - spin_unlock(&efx->stats_lock); + efx_stats_enable(efx); /* If we've reset the EM block and the link is up, then * we'll have to kick the XAUI link so the PHY can recover */ @@ -2277,6 +2273,10 @@ int falcon_switch_mac(struct efx_nic *efx) struct efx_mac_operations *old_mac_op = efx->mac_op; efx_oword_t nic_stat; unsigned strap_val; + int rc = 0; + + /* Don't try to fetch MAC stats while we're switching MACs */ + efx_stats_disable(efx); /* Internal loopbacks override the phy speed setting */ if (efx->loopback_mode == LOOPBACK_GMAC) { @@ -2287,16 +2287,12 @@ int falcon_switch_mac(struct efx_nic *efx) efx->link_fd = true; } + WARN_ON(!mutex_is_locked(&efx->mac_lock)); efx->mac_op = (EFX_IS10G(efx) ? &falcon_xmac_operations : &falcon_gmac_operations); - if (old_mac_op == efx->mac_op) - return 0; - - WARN_ON(!mutex_is_locked(&efx->mac_lock)); - - /* Not all macs support a mac-level link state */ - efx->mac_up = true; + /* Always push the NIC_STAT_REG setting even if the mac hasn't + * changed, because this function is run post online reset */ falcon_read(efx, &nic_stat, NIC_STAT_REG); strap_val = EFX_IS10G(efx) ? 5 : 3; if (falcon_rev(efx) >= FALCON_REV_B0) { @@ -2309,9 +2305,17 @@ int falcon_switch_mac(struct efx_nic *efx) BUG_ON(EFX_OWORD_FIELD(nic_stat, STRAP_PINS) != strap_val); } + if (old_mac_op == efx->mac_op) + goto out; EFX_LOG(efx, "selected %cMAC\n", EFX_IS10G(efx) ? 'X' : 'G'); - return falcon_reset_macs(efx); + /* Not all macs support a mac-level link state */ + efx->mac_up = true; + + rc = falcon_reset_macs(efx); +out: + efx_stats_enable(efx); + return rc; } /* This call is responsible for hooking in the MAC and PHY operations */ diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c index f6a16428113..f9e2f95c3b4 100644 --- a/drivers/net/sfc/mdio_10g.c +++ b/drivers/net/sfc/mdio_10g.c @@ -15,6 +15,7 @@ #include "net_driver.h" #include "mdio_10g.h" #include "boards.h" +#include "workarounds.h" int mdio_clause45_reset_mmd(struct efx_nic *port, int mmd, int spins, int spintime) @@ -179,17 +180,12 @@ bool mdio_clause45_links_ok(struct efx_nic *efx, unsigned int mmd_mask) return false; else if (efx_phy_mode_disabled(efx->phy_mode)) return false; - else if (efx->loopback_mode == LOOPBACK_PHYXS) { + else if (efx->loopback_mode == LOOPBACK_PHYXS) mmd_mask &= ~(MDIO_MMDREG_DEVS_PHYXS | MDIO_MMDREG_DEVS_PCS | MDIO_MMDREG_DEVS_PMAPMD | MDIO_MMDREG_DEVS_AN); - if (!mmd_mask) { - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PHYXS, - MDIO_PHYXS_STATUS2); - return !(reg & (1 << MDIO_PHYXS_STATUS2_RX_FAULT_LBN)); - } - } else if (efx->loopback_mode == LOOPBACK_PCS) + else if (efx->loopback_mode == LOOPBACK_PCS) mmd_mask &= ~(MDIO_MMDREG_DEVS_PCS | MDIO_MMDREG_DEVS_PMAPMD | MDIO_MMDREG_DEVS_AN); @@ -197,6 +193,13 @@ bool mdio_clause45_links_ok(struct efx_nic *efx, unsigned int mmd_mask) mmd_mask &= ~(MDIO_MMDREG_DEVS_PMAPMD | MDIO_MMDREG_DEVS_AN); + if (!mmd_mask) { + /* Use presence of XGMII faults in leui of link state */ + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PHYXS, + MDIO_PHYXS_STATUS2); + return !(reg & (1 << MDIO_PHYXS_STATUS2_RX_FAULT_LBN)); + } + while (mmd_mask) { if (mmd_mask & 1) { /* Double reads because link state is latched, and a @@ -263,7 +266,7 @@ void mdio_clause45_set_mmds_lpower(struct efx_nic *efx, } } -static u32 mdio_clause45_get_an(struct efx_nic *efx, u16 addr, u32 xnp) +static u32 mdio_clause45_get_an(struct efx_nic *efx, u16 addr) { int phy_id = efx->mii.phy_id; u32 result = 0; @@ -278,9 +281,6 @@ static u32 mdio_clause45_get_an(struct efx_nic *efx, u16 addr, u32 xnp) result |= ADVERTISED_100baseT_Half; if (reg & ADVERTISE_100FULL) result |= ADVERTISED_100baseT_Full; - if (reg & LPA_RESV) - result |= xnp; - return result; } @@ -310,7 +310,7 @@ void mdio_clause45_get_settings(struct efx_nic *efx, */ void mdio_clause45_get_settings_ext(struct efx_nic *efx, struct ethtool_cmd *ecmd, - u32 xnp, u32 xnp_lpa) + u32 npage_adv, u32 npage_lpa) { int phy_id = efx->mii.phy_id; int reg; @@ -361,8 +361,8 @@ void mdio_clause45_get_settings_ext(struct efx_nic *efx, ecmd->autoneg = AUTONEG_ENABLE; ecmd->advertising |= ADVERTISED_Autoneg | - mdio_clause45_get_an(efx, - MDIO_AN_ADVERTISE, xnp); + mdio_clause45_get_an(efx, MDIO_AN_ADVERTISE) | + npage_adv; } else ecmd->autoneg = AUTONEG_DISABLE; } else @@ -371,27 +371,30 @@ void mdio_clause45_get_settings_ext(struct efx_nic *efx, if (ecmd->autoneg) { /* If AN is complete, report best common mode, * otherwise report best advertised mode. */ - u32 common = ecmd->advertising; + u32 modes = 0; if (mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, MDIO_MMDREG_STAT1) & - (1 << MDIO_AN_STATUS_AN_DONE_LBN)) { - common &= mdio_clause45_get_an(efx, MDIO_AN_LPA, - xnp_lpa); - } - if (common & ADVERTISED_10000baseT_Full) { + (1 << MDIO_AN_STATUS_AN_DONE_LBN)) + modes = (ecmd->advertising & + (mdio_clause45_get_an(efx, MDIO_AN_LPA) | + npage_lpa)); + if (modes == 0) + modes = ecmd->advertising; + + if (modes & ADVERTISED_10000baseT_Full) { ecmd->speed = SPEED_10000; ecmd->duplex = DUPLEX_FULL; - } else if (common & (ADVERTISED_1000baseT_Full | - ADVERTISED_1000baseT_Half)) { + } else if (modes & (ADVERTISED_1000baseT_Full | + ADVERTISED_1000baseT_Half)) { ecmd->speed = SPEED_1000; - ecmd->duplex = !!(common & ADVERTISED_1000baseT_Full); - } else if (common & (ADVERTISED_100baseT_Full | - ADVERTISED_100baseT_Half)) { + ecmd->duplex = !!(modes & ADVERTISED_1000baseT_Full); + } else if (modes & (ADVERTISED_100baseT_Full | + ADVERTISED_100baseT_Half)) { ecmd->speed = SPEED_100; - ecmd->duplex = !!(common & ADVERTISED_100baseT_Full); + ecmd->duplex = !!(modes & ADVERTISED_100baseT_Full); } else { ecmd->speed = SPEED_10; - ecmd->duplex = !!(common & ADVERTISED_10baseT_Full); + ecmd->duplex = !!(modes & ADVERTISED_10baseT_Full); } } else { /* Report forced settings */ @@ -415,7 +418,7 @@ int mdio_clause45_set_settings(struct efx_nic *efx, int phy_id = efx->mii.phy_id; struct ethtool_cmd prev; u32 required; - int ctrl1_bits, reg; + int reg; efx->phy_op->get_settings(efx, &prev); @@ -430,99 +433,83 @@ int mdio_clause45_set_settings(struct efx_nic *efx, if (prev.port != PORT_TP || ecmd->port != PORT_TP) return -EINVAL; - /* Check that PHY supports these settings and work out the - * basic control bits */ - if (ecmd->duplex) { + /* Check that PHY supports these settings */ + if (ecmd->autoneg) { + required = SUPPORTED_Autoneg; + } else if (ecmd->duplex) { switch (ecmd->speed) { - case SPEED_10: - ctrl1_bits = BMCR_FULLDPLX; - required = SUPPORTED_10baseT_Full; - break; - case SPEED_100: - ctrl1_bits = BMCR_SPEED100 | BMCR_FULLDPLX; - required = SUPPORTED_100baseT_Full; - break; - case SPEED_1000: - ctrl1_bits = BMCR_SPEED1000 | BMCR_FULLDPLX; - required = SUPPORTED_1000baseT_Full; - break; - case SPEED_10000: - ctrl1_bits = (BMCR_SPEED1000 | BMCR_SPEED100 | - BMCR_FULLDPLX); - required = SUPPORTED_10000baseT_Full; - break; - default: - return -EINVAL; + case SPEED_10: required = SUPPORTED_10baseT_Full; break; + case SPEED_100: required = SUPPORTED_100baseT_Full; break; + default: return -EINVAL; } } else { switch (ecmd->speed) { - case SPEED_10: - ctrl1_bits = 0; - required = SUPPORTED_10baseT_Half; - break; - case SPEED_100: - ctrl1_bits = BMCR_SPEED100; - required = SUPPORTED_100baseT_Half; - break; - case SPEED_1000: - ctrl1_bits = BMCR_SPEED1000; - required = SUPPORTED_1000baseT_Half; - break; - default: - return -EINVAL; + case SPEED_10: required = SUPPORTED_10baseT_Half; break; + case SPEED_100: required = SUPPORTED_100baseT_Half; break; + default: return -EINVAL; } } - if (ecmd->autoneg) - required |= SUPPORTED_Autoneg; required |= ecmd->advertising; if (required & ~prev.supported) return -EINVAL; - /* Set the basic control bits */ - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, - MDIO_MMDREG_CTRL1); - reg &= ~(BMCR_SPEED1000 | BMCR_SPEED100 | BMCR_FULLDPLX | 0x003c); - reg |= ctrl1_bits; - mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, MDIO_MMDREG_CTRL1, - reg); - - /* Set the AN registers */ - if (ecmd->autoneg != prev.autoneg || - ecmd->advertising != prev.advertising) { - bool xnp = false; - - if (efx->phy_op->set_xnp_advertise) - xnp = efx->phy_op->set_xnp_advertise(efx, - ecmd->advertising); - - if (ecmd->autoneg) { - reg = 0; - if (ecmd->advertising & ADVERTISED_10baseT_Half) - reg |= ADVERTISE_10HALF; - if (ecmd->advertising & ADVERTISED_10baseT_Full) - reg |= ADVERTISE_10FULL; - if (ecmd->advertising & ADVERTISED_100baseT_Half) - reg |= ADVERTISE_100HALF; - if (ecmd->advertising & ADVERTISED_100baseT_Full) - reg |= ADVERTISE_100FULL; - if (xnp) - reg |= ADVERTISE_RESV; - mdio_clause45_write(efx, phy_id, MDIO_MMD_AN, - MDIO_AN_ADVERTISE, reg); - } + if (ecmd->autoneg) { + bool xnp = (ecmd->advertising & ADVERTISED_10000baseT_Full + || EFX_WORKAROUND_13204(efx)); + + /* Set up the base page */ + reg = ADVERTISE_CSMA; + if (ecmd->advertising & ADVERTISED_10baseT_Half) + reg |= ADVERTISE_10HALF; + if (ecmd->advertising & ADVERTISED_10baseT_Full) + reg |= ADVERTISE_10FULL; + if (ecmd->advertising & ADVERTISED_100baseT_Half) + reg |= ADVERTISE_100HALF; + if (ecmd->advertising & ADVERTISED_100baseT_Full) + reg |= ADVERTISE_100FULL; + if (xnp) + reg |= ADVERTISE_RESV; + else if (ecmd->advertising & (ADVERTISED_1000baseT_Half | + ADVERTISED_1000baseT_Full)) + reg |= ADVERTISE_NPAGE; + reg |= efx_fc_advertise(efx->wanted_fc); + mdio_clause45_write(efx, phy_id, MDIO_MMD_AN, + MDIO_AN_ADVERTISE, reg); + + /* Set up the (extended) next page if necessary */ + if (efx->phy_op->set_npage_adv) + efx->phy_op->set_npage_adv(efx, ecmd->advertising); + /* Enable and restart AN */ reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, MDIO_MMDREG_CTRL1); - if (ecmd->autoneg) - reg |= BMCR_ANENABLE | BMCR_ANRESTART; - else - reg &= ~BMCR_ANENABLE; + reg |= BMCR_ANENABLE; + if (!(EFX_WORKAROUND_15195(efx) && + LOOPBACK_MASK(efx) & efx->phy_op->loopbacks)) + reg |= BMCR_ANRESTART; if (xnp) reg |= 1 << MDIO_AN_CTRL_XNP_LBN; else reg &= ~(1 << MDIO_AN_CTRL_XNP_LBN); mdio_clause45_write(efx, phy_id, MDIO_MMD_AN, MDIO_MMDREG_CTRL1, reg); + } else { + /* Disable AN */ + mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_AN, + MDIO_MMDREG_CTRL1, + __ffs(BMCR_ANENABLE), false); + + /* Set the basic control bits */ + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, + MDIO_MMDREG_CTRL1); + reg &= ~(BMCR_SPEED1000 | BMCR_SPEED100 | BMCR_FULLDPLX | + 0x003c); + if (ecmd->speed == SPEED_100) + reg |= BMCR_SPEED100; + if (ecmd->duplex) + reg |= BMCR_FULLDPLX; + mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, + MDIO_MMDREG_CTRL1, reg); } return 0; diff --git a/drivers/net/sfc/mdio_10g.h b/drivers/net/sfc/mdio_10g.h index 09bf801d056..8ba49773ce7 100644 --- a/drivers/net/sfc/mdio_10g.h +++ b/drivers/net/sfc/mdio_10g.h @@ -155,7 +155,8 @@ #define MDIO_AN_XNP 22 #define MDIO_AN_LPA_XNP 25 -#define MDIO_AN_10GBT_ADVERTISE 32 +#define MDIO_AN_10GBT_CTRL 32 +#define MDIO_AN_10GBT_CTRL_ADV_10G_LBN 12 #define MDIO_AN_10GBT_STATUS (33) #define MDIO_AN_10GBT_STATUS_MS_FLT_LBN (15) /* MASTER/SLAVE config fault */ #define MDIO_AN_10GBT_STATUS_MS_LBN (14) /* MASTER/SLAVE config */ diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 5f255f75754..e019ad1fb9a 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -566,7 +566,7 @@ struct efx_mac_operations { * @poll: Poll for hardware state. Serialised by the mac_lock. * @get_settings: Get ethtool settings. Serialised by the mac_lock. * @set_settings: Set ethtool settings. Serialised by the mac_lock. - * @set_xnp_advertise: Set abilities advertised in Extended Next Page + * @set_npage_adv: Set abilities advertised in (Extended) Next Page * (only needed where AN bit is set in mmds) * @num_tests: Number of PHY-specific tests/results * @test_names: Names of the tests/results @@ -586,7 +586,7 @@ struct efx_phy_operations { struct ethtool_cmd *ecmd); int (*set_settings) (struct efx_nic *efx, struct ethtool_cmd *ecmd); - bool (*set_xnp_advertise) (struct efx_nic *efx, u32); + void (*set_npage_adv) (struct efx_nic *efx, u32); u32 num_tests; const char *const *test_names; int (*run_tests) (struct efx_nic *efx, int *results, unsigned flags); @@ -754,8 +754,7 @@ union efx_multicast_hash { * &struct net_device_stats. * @stats_buffer: DMA buffer for statistics * @stats_lock: Statistics update lock. Serialises statistics fetches - * @stats_enabled: Temporarily disable statistics fetches. - * Serialised by @stats_lock + * @stats_disable_count: Nest count for disabling statistics fetches * @mac_op: MAC interface * @mac_address: Permanent MAC address * @phy_type: PHY type @@ -837,7 +836,7 @@ struct efx_nic { struct efx_mac_stats mac_stats; struct efx_buffer stats_buffer; spinlock_t stats_lock; - bool stats_enabled; + unsigned int stats_disable_count; struct efx_mac_operations *mac_op; unsigned char mac_address[ETH_ALEN]; diff --git a/drivers/net/sfc/phy.h b/drivers/net/sfc/phy.h index 58c493ef81b..07e855c148b 100644 --- a/drivers/net/sfc/phy.h +++ b/drivers/net/sfc/phy.h @@ -17,7 +17,6 @@ extern struct efx_phy_operations falcon_sfx7101_phy_ops; extern struct efx_phy_operations falcon_sft9001_phy_ops; extern void tenxpress_phy_blink(struct efx_nic *efx, bool blink); -extern void tenxpress_crc_err(struct efx_nic *efx); /**************************************************************************** * Exported functions from the driver for XFP optical PHYs diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index dba0d64d50c..0a598084c51 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c @@ -665,6 +665,7 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, { enum efx_loopback_mode loopback_mode = efx->loopback_mode; int phy_mode = efx->phy_mode; + enum reset_type reset_method = RESET_TYPE_INVISIBLE; struct ethtool_cmd ecmd; struct efx_channel *channel; int rc_test = 0, rc_reset = 0, rc; @@ -718,21 +719,21 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, mutex_unlock(&efx->mac_lock); /* free up all consumers of SRAM (including all the queues) */ - efx_reset_down(efx, &ecmd); + efx_reset_down(efx, reset_method, &ecmd); rc = efx_test_chip(efx, tests); if (rc && !rc_test) rc_test = rc; /* reset the chip to recover from the register test */ - rc_reset = falcon_reset_hw(efx, RESET_TYPE_ALL); + rc_reset = falcon_reset_hw(efx, reset_method); /* Ensure that the phy is powered and out of loopback * for the bist and loopback tests */ efx->phy_mode &= ~PHY_MODE_LOW_POWER; efx->loopback_mode = LOOPBACK_NONE; - rc = efx_reset_up(efx, &ecmd, rc_reset == 0); + rc = efx_reset_up(efx, reset_method, &ecmd, rc_reset == 0); if (rc && !rc_reset) rc_reset = rc; diff --git a/drivers/net/sfc/sfe4001.c b/drivers/net/sfc/sfe4001.c index 16b80acb999..cb25ae5b257 100644 --- a/drivers/net/sfc/sfe4001.c +++ b/drivers/net/sfc/sfe4001.c @@ -186,19 +186,22 @@ static int sfn4111t_reset(struct efx_nic *efx) { efx_oword_t reg; - /* GPIO pins are also used for I2C, so block that temporarily */ + /* GPIO 3 and the GPIO register are shared with I2C, so block that */ mutex_lock(&efx->i2c_adap.bus_lock); + /* Pull RST_N (GPIO 2) low then let it up again, setting the + * FLASH_CFG_1 strap (GPIO 3) appropriately. Only change the + * output enables; the output levels should always be 0 (low) + * and we rely on external pull-ups. */ falcon_read(efx, ®, GPIO_CTL_REG_KER); EFX_SET_OWORD_FIELD(reg, GPIO2_OEN, true); - EFX_SET_OWORD_FIELD(reg, GPIO2_OUT, false); falcon_write(efx, ®, GPIO_CTL_REG_KER); msleep(1000); - EFX_SET_OWORD_FIELD(reg, GPIO2_OUT, true); - EFX_SET_OWORD_FIELD(reg, GPIO3_OEN, true); - EFX_SET_OWORD_FIELD(reg, GPIO3_OUT, - !(efx->phy_mode & PHY_MODE_SPECIAL)); + EFX_SET_OWORD_FIELD(reg, GPIO2_OEN, false); + EFX_SET_OWORD_FIELD(reg, GPIO3_OEN, + !!(efx->phy_mode & PHY_MODE_SPECIAL)); falcon_write(efx, ®, GPIO_CTL_REG_KER); + msleep(1); mutex_unlock(&efx->i2c_adap.bus_lock); @@ -232,12 +235,18 @@ static ssize_t set_phy_flash_cfg(struct device *dev, } else if (efx->state != STATE_RUNNING || netif_running(efx->net_dev)) { err = -EBUSY; } else { + /* Reset the PHY, reconfigure the MAC and enable/disable + * MAC stats accordingly. */ efx->phy_mode = new_mode; + if (new_mode & PHY_MODE_SPECIAL) + efx_stats_disable(efx); if (efx->board_info.type == EFX_BOARD_SFE4001) err = sfe4001_poweron(efx); else err = sfn4111t_reset(efx); efx_reconfigure_port(efx); + if (!(new_mode & PHY_MODE_SPECIAL)) + efx_stats_enable(efx); } rtnl_unlock(); @@ -326,6 +335,11 @@ int sfe4001_init(struct efx_nic *efx) efx->board_info.monitor = sfe4001_check_hw; efx->board_info.fini = sfe4001_fini; + if (efx->phy_mode & PHY_MODE_SPECIAL) { + /* PHY won't generate a 156.25 MHz clock and MAC stats fetch + * will fail. */ + efx_stats_disable(efx); + } rc = sfe4001_poweron(efx); if (rc) goto fail_ioexp; @@ -372,17 +386,25 @@ static void sfn4111t_fini(struct efx_nic *efx) i2c_unregister_device(efx->board_info.hwmon_client); } -static struct i2c_board_info sfn4111t_hwmon_info = { +static struct i2c_board_info sfn4111t_a0_hwmon_info = { I2C_BOARD_INFO("max6647", 0x4e), .irq = -1, }; +static struct i2c_board_info sfn4111t_r5_hwmon_info = { + I2C_BOARD_INFO("max6646", 0x4d), + .irq = -1, +}; + int sfn4111t_init(struct efx_nic *efx) { int rc; efx->board_info.hwmon_client = - i2c_new_device(&efx->i2c_adap, &sfn4111t_hwmon_info); + i2c_new_device(&efx->i2c_adap, + (efx->board_info.minor < 5) ? + &sfn4111t_a0_hwmon_info : + &sfn4111t_r5_hwmon_info); if (!efx->board_info.hwmon_client) return -EIO; @@ -394,8 +416,10 @@ int sfn4111t_init(struct efx_nic *efx) if (rc) goto fail_hwmon; - if (efx->phy_mode & PHY_MODE_SPECIAL) + if (efx->phy_mode & PHY_MODE_SPECIAL) { + efx_stats_disable(efx); sfn4111t_reset(efx); + } return 0; diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index 9ecb77da954..f0efd246962 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c @@ -67,6 +67,8 @@ #define PMA_PMD_EXT_CLK312_WIDTH 1 #define PMA_PMD_EXT_LPOWER_LBN 12 #define PMA_PMD_EXT_LPOWER_WIDTH 1 +#define PMA_PMD_EXT_ROBUST_LBN 14 +#define PMA_PMD_EXT_ROBUST_WIDTH 1 #define PMA_PMD_EXT_SSR_LBN 15 #define PMA_PMD_EXT_SSR_WIDTH 1 @@ -177,35 +179,24 @@ #define C22EXT_STATUS_LINK_LBN 2 #define C22EXT_STATUS_LINK_WIDTH 1 -#define C22EXT_MSTSLV_REG 49162 -#define C22EXT_MSTSLV_1000_HD_LBN 10 -#define C22EXT_MSTSLV_1000_HD_WIDTH 1 -#define C22EXT_MSTSLV_1000_FD_LBN 11 -#define C22EXT_MSTSLV_1000_FD_WIDTH 1 +#define C22EXT_MSTSLV_CTRL 49161 +#define C22EXT_MSTSLV_CTRL_ADV_1000_HD_LBN 8 +#define C22EXT_MSTSLV_CTRL_ADV_1000_FD_LBN 9 + +#define C22EXT_MSTSLV_STATUS 49162 +#define C22EXT_MSTSLV_STATUS_LP_1000_HD_LBN 10 +#define C22EXT_MSTSLV_STATUS_LP_1000_FD_LBN 11 /* Time to wait between powering down the LNPGA and turning off the power * rails */ #define LNPGA_PDOWN_WAIT (HZ / 5) -static int crc_error_reset_threshold = 100; -module_param(crc_error_reset_threshold, int, 0644); -MODULE_PARM_DESC(crc_error_reset_threshold, - "Max number of CRC errors before XAUI reset"); - struct tenxpress_phy_data { enum efx_loopback_mode loopback_mode; - atomic_t bad_crc_count; enum efx_phy_mode phy_mode; int bad_lp_tries; }; -void tenxpress_crc_err(struct efx_nic *efx) -{ - struct tenxpress_phy_data *phy_data = efx->phy_data; - if (phy_data != NULL) - atomic_inc(&phy_data->bad_crc_count); -} - static ssize_t show_phy_short_reach(struct device *dev, struct device_attribute *attr, char *buf) { @@ -284,7 +275,9 @@ static int tenxpress_init(struct efx_nic *efx) PMA_PMD_XCONTROL_REG); reg |= ((1 << PMA_PMD_EXT_GMII_EN_LBN) | (1 << PMA_PMD_EXT_CLK_OUT_LBN) | - (1 << PMA_PMD_EXT_CLK312_LBN)); + (1 << PMA_PMD_EXT_CLK312_LBN) | + (1 << PMA_PMD_EXT_ROBUST_LBN)); + mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, reg); mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_C22EXT, @@ -346,6 +339,7 @@ static int tenxpress_phy_init(struct efx_nic *efx) rc = tenxpress_init(efx); if (rc < 0) goto fail; + mdio_clause45_set_pause(efx); if (efx->phy_type == PHY_TYPE_SFT9001B) { rc = device_create_file(&efx->pci_dev->dev, @@ -376,8 +370,8 @@ static int tenxpress_special_reset(struct efx_nic *efx) /* The XGMAC clock is driven from the SFC7101/SFT9001 312MHz clock, so * a special software reset can glitch the XGMAC sufficiently for stats - * requests to fail. Since we don't often special_reset, just lock. */ - spin_lock(&efx->stats_lock); + * requests to fail. */ + efx_stats_disable(efx); /* Initiate reset */ reg = mdio_clause45_read(efx, efx->mii.phy_id, @@ -392,17 +386,17 @@ static int tenxpress_special_reset(struct efx_nic *efx) rc = mdio_clause45_wait_reset_mmds(efx, TENXPRESS_REQUIRED_DEVS); if (rc < 0) - goto unlock; + goto out; /* Try and reconfigure the device */ rc = tenxpress_init(efx); if (rc < 0) - goto unlock; + goto out; /* Wait for the XGXS state machine to churn */ mdelay(10); -unlock: - spin_unlock(&efx->stats_lock); +out: + efx_stats_enable(efx); return rc; } @@ -520,7 +514,7 @@ static void tenxpress_phy_reconfigure(struct efx_nic *efx) { struct tenxpress_phy_data *phy_data = efx->phy_data; struct ethtool_cmd ecmd; - bool phy_mode_change, loop_reset, loop_toggle, loopback; + bool phy_mode_change, loop_reset; if (efx->phy_mode & (PHY_MODE_OFF | PHY_MODE_SPECIAL)) { phy_data->phy_mode = efx->phy_mode; @@ -531,12 +525,10 @@ static void tenxpress_phy_reconfigure(struct efx_nic *efx) phy_mode_change = (efx->phy_mode == PHY_MODE_NORMAL && phy_data->phy_mode != PHY_MODE_NORMAL); - loopback = LOOPBACK_MASK(efx) & efx->phy_op->loopbacks; - loop_toggle = LOOPBACK_CHANGED(phy_data, efx, efx->phy_op->loopbacks); loop_reset = (LOOPBACK_OUT_OF(phy_data, efx, efx->phy_op->loopbacks) || LOOPBACK_CHANGED(phy_data, efx, 1 << LOOPBACK_GPHY)); - if (loop_reset || loop_toggle || loopback || phy_mode_change) { + if (loop_reset || phy_mode_change) { int rc; efx->phy_op->get_settings(efx, &ecmd); @@ -551,20 +543,6 @@ static void tenxpress_phy_reconfigure(struct efx_nic *efx) falcon_reset_xaui(efx); } - if (efx->phy_type != PHY_TYPE_SFX7101) { - /* Only change autoneg once, on coming out or - * going into loopback */ - if (loop_toggle) - ecmd.autoneg = !loopback; - if (loopback) { - ecmd.duplex = DUPLEX_FULL; - if (efx->loopback_mode == LOOPBACK_GPHY) - ecmd.speed = SPEED_1000; - else - ecmd.speed = SPEED_10000; - } - } - rc = efx->phy_op->set_settings(efx, &ecmd); WARN_ON(rc); } @@ -623,13 +601,6 @@ static void tenxpress_phy_poll(struct efx_nic *efx) if (phy_data->phy_mode != PHY_MODE_NORMAL) return; - - if (EFX_WORKAROUND_10750(efx) && - atomic_read(&phy_data->bad_crc_count) > crc_error_reset_threshold) { - EFX_ERR(efx, "Resetting XAUI due to too many CRC errors\n"); - falcon_reset_xaui(efx); - atomic_set(&phy_data->bad_crc_count, 0); - } } static void tenxpress_phy_fini(struct efx_nic *efx) @@ -772,107 +743,76 @@ reset: return rc; } -static u32 tenxpress_get_xnp_lpa(struct efx_nic *efx) +static void +tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) { - int phy = efx->mii.phy_id; - u32 lpa = 0; + int phy_id = efx->mii.phy_id; + u32 adv = 0, lpa = 0; int reg; if (efx->phy_type != PHY_TYPE_SFX7101) { - reg = mdio_clause45_read(efx, phy, MDIO_MMD_C22EXT, - C22EXT_MSTSLV_REG); - if (reg & (1 << C22EXT_MSTSLV_1000_HD_LBN)) + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_C22EXT, + C22EXT_MSTSLV_CTRL); + if (reg & (1 << C22EXT_MSTSLV_CTRL_ADV_1000_FD_LBN)) + adv |= ADVERTISED_1000baseT_Full; + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_C22EXT, + C22EXT_MSTSLV_STATUS); + if (reg & (1 << C22EXT_MSTSLV_STATUS_LP_1000_HD_LBN)) lpa |= ADVERTISED_1000baseT_Half; - if (reg & (1 << C22EXT_MSTSLV_1000_FD_LBN)) + if (reg & (1 << C22EXT_MSTSLV_STATUS_LP_1000_FD_LBN)) lpa |= ADVERTISED_1000baseT_Full; } - reg = mdio_clause45_read(efx, phy, MDIO_MMD_AN, MDIO_AN_10GBT_STATUS); + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, + MDIO_AN_10GBT_CTRL); + if (reg & (1 << MDIO_AN_10GBT_CTRL_ADV_10G_LBN)) + adv |= ADVERTISED_10000baseT_Full; + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, + MDIO_AN_10GBT_STATUS); if (reg & (1 << MDIO_AN_10GBT_STATUS_LP_10G_LBN)) lpa |= ADVERTISED_10000baseT_Full; - return lpa; -} -static void sfx7101_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) -{ - mdio_clause45_get_settings_ext(efx, ecmd, ADVERTISED_10000baseT_Full, - tenxpress_get_xnp_lpa(efx)); - ecmd->supported |= SUPPORTED_10000baseT_Full; - ecmd->advertising |= ADVERTISED_10000baseT_Full; + mdio_clause45_get_settings_ext(efx, ecmd, adv, lpa); + + if (efx->phy_type != PHY_TYPE_SFX7101) + ecmd->supported |= (SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full); + + /* In loopback, the PHY automatically brings up the correct interface, + * but doesn't advertise the correct speed. So override it */ + if (efx->loopback_mode == LOOPBACK_GPHY) + ecmd->speed = SPEED_1000; + else if (LOOPBACK_MASK(efx) & efx->phy_op->loopbacks) + ecmd->speed = SPEED_10000; } -static void sft9001_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) +static int tenxpress_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) { - int phy_id = efx->mii.phy_id; - u32 xnp_adv = 0; - int reg; - - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_SPEED_ENABLE_REG); - if (EFX_WORKAROUND_13204(efx) && (reg & (1 << PMA_PMD_100TX_ADV_LBN))) - xnp_adv |= ADVERTISED_100baseT_Full; - if (reg & (1 << PMA_PMD_1000T_ADV_LBN)) - xnp_adv |= ADVERTISED_1000baseT_Full; - if (reg & (1 << PMA_PMD_10000T_ADV_LBN)) - xnp_adv |= ADVERTISED_10000baseT_Full; - - mdio_clause45_get_settings_ext(efx, ecmd, xnp_adv, - tenxpress_get_xnp_lpa(efx)); - - ecmd->supported |= (SUPPORTED_100baseT_Half | - SUPPORTED_100baseT_Full | - SUPPORTED_1000baseT_Full); + if (!ecmd->autoneg) + return -EINVAL; - /* Use the vendor defined C22ext register for duplex settings */ - if (ecmd->speed != SPEED_10000 && !ecmd->autoneg) { - reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_C22EXT, - GPHY_XCONTROL_REG); - ecmd->duplex = (reg & (1 << GPHY_DUPLEX_LBN) ? - DUPLEX_FULL : DUPLEX_HALF); - } + return mdio_clause45_set_settings(efx, ecmd); } -static int sft9001_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) +static void sfx7101_set_npage_adv(struct efx_nic *efx, u32 advertising) { - int phy_id = efx->mii.phy_id; - int rc; - - rc = mdio_clause45_set_settings(efx, ecmd); - if (rc) - return rc; - - if (ecmd->speed != SPEED_10000 && !ecmd->autoneg) - mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_C22EXT, - GPHY_XCONTROL_REG, GPHY_DUPLEX_LBN, - ecmd->duplex == DUPLEX_FULL); - - return rc; + mdio_clause45_set_flag(efx, efx->mii.phy_id, MDIO_MMD_AN, + MDIO_AN_10GBT_CTRL, + MDIO_AN_10GBT_CTRL_ADV_10G_LBN, + advertising & ADVERTISED_10000baseT_Full); } -static bool sft9001_set_xnp_advertise(struct efx_nic *efx, u32 advertising) +static void sft9001_set_npage_adv(struct efx_nic *efx, u32 advertising) { - int phy = efx->mii.phy_id; - int reg = mdio_clause45_read(efx, phy, MDIO_MMD_PMAPMD, - PMA_PMD_SPEED_ENABLE_REG); - bool enabled; - - reg &= ~((1 << 2) | (1 << 3)); - if (EFX_WORKAROUND_13204(efx) && - (advertising & ADVERTISED_100baseT_Full)) - reg |= 1 << PMA_PMD_100TX_ADV_LBN; - if (advertising & ADVERTISED_1000baseT_Full) - reg |= 1 << PMA_PMD_1000T_ADV_LBN; - if (advertising & ADVERTISED_10000baseT_Full) - reg |= 1 << PMA_PMD_10000T_ADV_LBN; - mdio_clause45_write(efx, phy, MDIO_MMD_PMAPMD, - PMA_PMD_SPEED_ENABLE_REG, reg); - - enabled = (advertising & - (ADVERTISED_1000baseT_Half | - ADVERTISED_1000baseT_Full | - ADVERTISED_10000baseT_Full)); - if (EFX_WORKAROUND_13204(efx)) - enabled |= (advertising & ADVERTISED_100baseT_Full); - return enabled; + int phy_id = efx->mii.phy_id; + + mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_C22EXT, + C22EXT_MSTSLV_CTRL, + C22EXT_MSTSLV_CTRL_ADV_1000_FD_LBN, + advertising & ADVERTISED_1000baseT_Full); + mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_AN, + MDIO_AN_10GBT_CTRL, + MDIO_AN_10GBT_CTRL_ADV_10G_LBN, + advertising & ADVERTISED_10000baseT_Full); } struct efx_phy_operations falcon_sfx7101_phy_ops = { @@ -882,8 +822,9 @@ struct efx_phy_operations falcon_sfx7101_phy_ops = { .poll = tenxpress_phy_poll, .fini = tenxpress_phy_fini, .clear_interrupt = efx_port_dummy_op_void, - .get_settings = sfx7101_get_settings, - .set_settings = mdio_clause45_set_settings, + .get_settings = tenxpress_get_settings, + .set_settings = tenxpress_set_settings, + .set_npage_adv = sfx7101_set_npage_adv, .num_tests = ARRAY_SIZE(sfx7101_test_names), .test_names = sfx7101_test_names, .run_tests = sfx7101_run_tests, @@ -898,9 +839,9 @@ struct efx_phy_operations falcon_sft9001_phy_ops = { .poll = tenxpress_phy_poll, .fini = tenxpress_phy_fini, .clear_interrupt = efx_port_dummy_op_void, - .get_settings = sft9001_get_settings, - .set_settings = sft9001_set_settings, - .set_xnp_advertise = sft9001_set_xnp_advertise, + .get_settings = tenxpress_get_settings, + .set_settings = tenxpress_set_settings, + .set_npage_adv = sft9001_set_npage_adv, .num_tests = ARRAY_SIZE(sft9001_test_names), .test_names = sft9001_test_names, .run_tests = sft9001_run_tests, diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h index 82e03e1d737..78de68f4a95 100644 --- a/drivers/net/sfc/workarounds.h +++ b/drivers/net/sfc/workarounds.h @@ -18,8 +18,8 @@ #define EFX_WORKAROUND_ALWAYS(efx) 1 #define EFX_WORKAROUND_FALCON_A(efx) (falcon_rev(efx) <= FALCON_REV_A1) #define EFX_WORKAROUND_10G(efx) EFX_IS10G(efx) -#define EFX_WORKAROUND_SFX7101(efx) ((efx)->phy_type == PHY_TYPE_SFX7101) -#define EFX_WORKAROUND_SFT9001A(efx) ((efx)->phy_type == PHY_TYPE_SFT9001A) +#define EFX_WORKAROUND_SFT9001(efx) ((efx)->phy_type == PHY_TYPE_SFT9001A || \ + (efx)->phy_type == PHY_TYPE_SFT9001B) /* XAUI resets if link not detected */ #define EFX_WORKAROUND_5147 EFX_WORKAROUND_ALWAYS @@ -29,8 +29,6 @@ #define EFX_WORKAROUND_7884 EFX_WORKAROUND_10G /* TX pkt parser problem with <= 16 byte TXes */ #define EFX_WORKAROUND_9141 EFX_WORKAROUND_ALWAYS -/* Low rate CRC errors require XAUI reset */ -#define EFX_WORKAROUND_10750 EFX_WORKAROUND_SFX7101 /* TX_EV_PKT_ERR can be caused by a dangling TX descriptor * or a PCIe error (bug 11028) */ #define EFX_WORKAROUND_10727 EFX_WORKAROUND_ALWAYS @@ -55,8 +53,8 @@ #define EFX_WORKAROUND_8071 EFX_WORKAROUND_FALCON_A /* Need to send XNP pages for 100BaseT */ -#define EFX_WORKAROUND_13204 EFX_WORKAROUND_SFT9001A -/* Need to keep AN enabled */ -#define EFX_WORKAROUND_13963 EFX_WORKAROUND_SFT9001A +#define EFX_WORKAROUND_13204 EFX_WORKAROUND_SFT9001 +/* Don't restart AN in near-side loopback */ +#define EFX_WORKAROUND_15195 EFX_WORKAROUND_SFT9001 #endif /* EFX_WORKAROUNDS_H */ diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c index 607efeaf0bc..9a00e5566af 100644 --- a/drivers/net/skfp/skfddi.c +++ b/drivers/net/skfp/skfddi.c @@ -1003,9 +1003,9 @@ static int skfp_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) break; case SKFP_CLR_STATS: /* Zero out the driver statistics */ if (!capable(CAP_NET_ADMIN)) { - memset(&lp->MacStat, 0, sizeof(lp->MacStat)); - } else { status = -EPERM; + } else { + memset(&lp->MacStat, 0, sizeof(lp->MacStat)); } break; default: diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 3668e81e474..994703cc0db 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1403,9 +1403,6 @@ static int sky2_up(struct net_device *dev) } - if (netif_msg_ifup(sky2)) - printk(KERN_INFO PFX "%s: enabling interface\n", dev->name); - netif_carrier_off(dev); /* must be power of 2 */ @@ -1484,6 +1481,9 @@ static int sky2_up(struct net_device *dev) sky2_write32(hw, B0_IMSK, imask); sky2_set_multicast(dev); + + if (netif_msg_ifup(sky2)) + printk(KERN_INFO PFX "%s: enabling interface\n", dev->name); return 0; err_out: diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c index f513bdf1c88..783c1a7b869 100644 --- a/drivers/net/smsc911x.c +++ b/drivers/net/smsc911x.c @@ -953,7 +953,7 @@ smsc911x_rx_fastforward(struct smsc911x_data *pdata, unsigned int pktbytes) do { udelay(1); val = smsc911x_reg_read(pdata, RX_DP_CTRL); - } while (timeout-- && (val & RX_DP_CTRL_RX_FFWD_)); + } while (--timeout && (val & RX_DP_CTRL_RX_FFWD_)); if (unlikely(timeout == 0)) SMSC_WARNING(HW, "Timed out waiting for " diff --git a/drivers/net/smsc9420.c b/drivers/net/smsc9420.c index c14a4c6452c..d801900a503 100644 --- a/drivers/net/smsc9420.c +++ b/drivers/net/smsc9420.c @@ -1378,6 +1378,7 @@ static int smsc9420_open(struct net_device *dev) /* test the IRQ connection to the ISR */ smsc_dbg(IFUP, "Testing ISR using IRQ %d", dev->irq); + pd->software_irq_signal = false; spin_lock_irqsave(&pd->int_lock, flags); /* configure interrupt deassertion timer and enable interrupts */ @@ -1393,8 +1394,6 @@ static int smsc9420_open(struct net_device *dev) smsc9420_pci_flush_write(pd); timeout = 1000; - pd->software_irq_signal = false; - smp_wmb(); while (timeout--) { if (pd->software_irq_signal) break; diff --git a/drivers/net/tulip/21142.c b/drivers/net/tulip/21142.c index 1210fb3748a..db7d5e11855 100644 --- a/drivers/net/tulip/21142.c +++ b/drivers/net/tulip/21142.c @@ -9,6 +9,11 @@ Please refer to Documentation/DocBook/tulip-user.{pdf,ps,html} for more information on this driver. + + DC21143 manual "21143 PCI/CardBus 10/100Mb/s Ethernet LAN Controller + Hardware Reference Manual" is currently available at : + http://developer.intel.com/design/network/manuals/278074.htm + Please submit bugs to http://bugzilla.kernel.org/ . */ @@ -32,7 +37,11 @@ void t21142_media_task(struct work_struct *work) int csr12 = ioread32(ioaddr + CSR12); int next_tick = 60*HZ; int new_csr6 = 0; + int csr14 = ioread32(ioaddr + CSR14); + /* CSR12[LS10,LS100] are not reliable during autonegotiation */ + if ((csr14 & 0x80) && (csr12 & 0x7000) != 0x5000) + csr12 |= 6; if (tulip_debug > 2) printk(KERN_INFO"%s: 21143 negotiation status %8.8x, %s.\n", dev->name, csr12, medianame[dev->if_port]); @@ -76,7 +85,7 @@ void t21142_media_task(struct work_struct *work) new_csr6 = 0x83860000; dev->if_port = 3; iowrite32(0, ioaddr + CSR13); - iowrite32(0x0003FF7F, ioaddr + CSR14); + iowrite32(0x0003FFFF, ioaddr + CSR14); iowrite16(8, ioaddr + CSR15); iowrite32(1, ioaddr + CSR13); } @@ -132,10 +141,14 @@ void t21142_lnk_change(struct net_device *dev, int csr5) struct tulip_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->base_addr; int csr12 = ioread32(ioaddr + CSR12); + int csr14 = ioread32(ioaddr + CSR14); + /* CSR12[LS10,LS100] are not reliable during autonegotiation */ + if ((csr14 & 0x80) && (csr12 & 0x7000) != 0x5000) + csr12 |= 6; if (tulip_debug > 1) printk(KERN_INFO"%s: 21143 link status interrupt %8.8x, CSR5 %x, " - "%8.8x.\n", dev->name, csr12, csr5, ioread32(ioaddr + CSR14)); + "%8.8x.\n", dev->name, csr12, csr5, csr14); /* If NWay finished and we have a negotiated partner capability. */ if (tp->nway && !tp->nwayset && (csr12 & 0x7000) == 0x5000) { @@ -143,7 +156,9 @@ void t21142_lnk_change(struct net_device *dev, int csr5) int negotiated = tp->sym_advertise & (csr12 >> 16); tp->lpar = csr12 >> 16; tp->nwayset = 1; - if (negotiated & 0x0100) dev->if_port = 5; + /* If partner cannot negotiate, it is 10Mbps Half Duplex */ + if (!(csr12 & 0x8000)) dev->if_port = 0; + else if (negotiated & 0x0100) dev->if_port = 5; else if (negotiated & 0x0080) dev->if_port = 3; else if (negotiated & 0x0040) dev->if_port = 4; else if (negotiated & 0x0020) dev->if_port = 0; @@ -214,7 +229,7 @@ void t21142_lnk_change(struct net_device *dev, int csr5) tp->timer.expires = RUN_AT(3*HZ); add_timer(&tp->timer); } else if (dev->if_port == 5) - iowrite32(ioread32(ioaddr + CSR14) & ~0x080, ioaddr + CSR14); + iowrite32(csr14 & ~0x080, ioaddr + CSR14); } else if (dev->if_port == 0 || dev->if_port == 4) { if ((csr12 & 4) == 0) printk(KERN_INFO"%s: 21143 10baseT link beat good.\n", diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 11441225bf4..e87986867ba 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -1536,6 +1536,11 @@ static void adjust_link(struct net_device *dev) static int init_phy(struct net_device *dev) { struct ucc_geth_private *priv = netdev_priv(dev); + struct device_node *np = priv->node; + struct device_node *phy, *mdio; + const phandle *ph; + char bus_name[MII_BUS_ID_SIZE]; + const unsigned int *id; struct phy_device *phydev; char phy_id[BUS_ID_SIZE]; @@ -1543,8 +1548,18 @@ static int init_phy(struct net_device *dev) priv->oldspeed = 0; priv->oldduplex = -1; - snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT, priv->ug_info->mdio_bus, - priv->ug_info->phy_address); + ph = of_get_property(np, "phy-handle", NULL); + phy = of_find_node_by_phandle(*ph); + mdio = of_get_parent(phy); + + id = of_get_property(phy, "reg", NULL); + + of_node_put(phy); + of_node_put(mdio); + + uec_mdio_bus_name(bus_name, mdio); + snprintf(phy_id, sizeof(phy_id), "%s:%02x", + bus_name, *id); phydev = phy_connect(dev, phy_id, &adjust_link, 0, priv->phy_interface); @@ -3748,6 +3763,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma ugeth->ug_info = ug_info; ugeth->dev = dev; + ugeth->node = np; return 0; } diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h index 8f699cb773e..16cbe42ba43 100644 --- a/drivers/net/ucc_geth.h +++ b/drivers/net/ucc_geth.h @@ -1186,6 +1186,8 @@ struct ucc_geth_private { int oldspeed; int oldduplex; int oldlink; + + struct device_node *node; }; void uec_set_ethtool_ops(struct net_device *netdev); diff --git a/drivers/net/ucc_geth_mii.c b/drivers/net/ucc_geth_mii.c index c001d261366..54635911305 100644 --- a/drivers/net/ucc_geth_mii.c +++ b/drivers/net/ucc_geth_mii.c @@ -156,7 +156,7 @@ static int uec_mdio_probe(struct of_device *ofdev, const struct of_device_id *ma if (err) goto reg_map_fail; - snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", res.start); + uec_mdio_bus_name(new_bus->id, np); new_bus->irq = kmalloc(32 * sizeof(int), GFP_KERNEL); @@ -283,3 +283,13 @@ void uec_mdio_exit(void) { of_unregister_platform_driver(&uec_mdio_driver); } + +void uec_mdio_bus_name(char *name, struct device_node *np) +{ + const u32 *reg; + + reg = of_get_property(np, "reg", NULL); + + snprintf(name, MII_BUS_ID_SIZE, "%s@%x", np->name, reg ? *reg : 0); +} + diff --git a/drivers/net/ucc_geth_mii.h b/drivers/net/ucc_geth_mii.h index 1e45b2028a5..840cf80235b 100644 --- a/drivers/net/ucc_geth_mii.h +++ b/drivers/net/ucc_geth_mii.h @@ -97,4 +97,5 @@ int uec_mdio_read(struct mii_bus *bus, int mii_id, int regnum); int uec_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value); int __init uec_mdio_init(void); void uec_mdio_exit(void); +void uec_mdio_bus_name(char *name, struct device_node *np); #endif /* __UEC_MII_H */ diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 63ef2a8905f..c68808336c8 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -287,7 +287,7 @@ static void try_fill_recv_maxbufs(struct virtnet_info *vi) skb_put(skb, MAX_PACKET_LEN); hdr = skb_vnet_hdr(skb); - sg_init_one(sg, hdr, sizeof(*hdr)); + sg_set_buf(sg, hdr, sizeof(*hdr)); if (vi->big_packets) { for (i = 0; i < MAX_SKB_FRAGS; i++) { @@ -488,9 +488,9 @@ static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb) /* Encode metadata header at front. */ if (vi->mergeable_rx_bufs) - sg_init_one(sg, mhdr, sizeof(*mhdr)); + sg_set_buf(sg, mhdr, sizeof(*mhdr)); else - sg_init_one(sg, hdr, sizeof(*hdr)); + sg_set_buf(sg, hdr, sizeof(*hdr)); num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1; diff --git a/drivers/net/wimax/i2400m/debugfs.c b/drivers/net/wimax/i2400m/debugfs.c index 62663298597..9b81af3f80a 100644 --- a/drivers/net/wimax/i2400m/debugfs.c +++ b/drivers/net/wimax/i2400m/debugfs.c @@ -234,20 +234,6 @@ struct dentry *debugfs_create_i2400m_reset( &fops_i2400m_reset); } -/* - * Debug levels control; see debug.h - */ -struct d_level D_LEVEL[] = { - D_SUBMODULE_DEFINE(control), - D_SUBMODULE_DEFINE(driver), - D_SUBMODULE_DEFINE(debugfs), - D_SUBMODULE_DEFINE(fw), - D_SUBMODULE_DEFINE(netdev), - D_SUBMODULE_DEFINE(rfkill), - D_SUBMODULE_DEFINE(rx), - D_SUBMODULE_DEFINE(tx), -}; -size_t D_LEVEL_SIZE = ARRAY_SIZE(D_LEVEL); #define __debugfs_register(prefix, name, parent) \ do { \ diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c index 5f98047e18c..e80a0b65a75 100644 --- a/drivers/net/wimax/i2400m/driver.c +++ b/drivers/net/wimax/i2400m/driver.c @@ -707,6 +707,22 @@ void i2400m_release(struct i2400m *i2400m) EXPORT_SYMBOL_GPL(i2400m_release); +/* + * Debug levels control; see debug.h + */ +struct d_level D_LEVEL[] = { + D_SUBMODULE_DEFINE(control), + D_SUBMODULE_DEFINE(driver), + D_SUBMODULE_DEFINE(debugfs), + D_SUBMODULE_DEFINE(fw), + D_SUBMODULE_DEFINE(netdev), + D_SUBMODULE_DEFINE(rfkill), + D_SUBMODULE_DEFINE(rx), + D_SUBMODULE_DEFINE(tx), +}; +size_t D_LEVEL_SIZE = ARRAY_SIZE(D_LEVEL); + + static int __init i2400m_driver_init(void) { diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 8ef87356e08..a533ed60bb4 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -1028,6 +1028,8 @@ ath5k_setup_bands(struct ieee80211_hw *hw) * it's done by reseting the chip. To accomplish this we must * first cleanup any pending DMA, then restart stuff after a la * ath5k_init. + * + * Called with sc->lock. */ static int ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan) @@ -2814,11 +2816,17 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed) { struct ath5k_softc *sc = hw->priv; struct ieee80211_conf *conf = &hw->conf; + int ret; + + mutex_lock(&sc->lock); sc->bintval = conf->beacon_int; sc->power_level = conf->power_level; - return ath5k_chan_set(sc, conf->channel); + ret = ath5k_chan_set(sc, conf->channel); + + mutex_unlock(&sc->lock); + return ret; } static int diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 0dc8eed1640..b35c8813bef 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1719,6 +1719,10 @@ static int iwl_read_ucode(struct iwl_priv *priv) priv->ucode_data_backup.len = data_size; iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data_backup); + if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr || + !priv->ucode_data_backup.v_addr) + goto err_pci_alloc; + /* Initialization instructions and data */ if (init_size && init_data_size) { priv->ucode_init.len = init_size; diff --git a/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c index 4e75e8e7fa9..78df281b297 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c +++ b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c @@ -285,7 +285,10 @@ static void rtl8225_rf_set_tx_power(struct ieee80211_hw *dev, int channel) ofdm_power = priv->channels[channel - 1].hw_value >> 4; cck_power = min(cck_power, (u8)11); - ofdm_power = min(ofdm_power, (u8)35); + if (ofdm_power > (u8)15) + ofdm_power = 25; + else + ofdm_power += 10; rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, rtl8225_tx_gain_cck_ofdm[cck_power / 6] >> 1); @@ -536,7 +539,10 @@ static void rtl8225z2_rf_set_tx_power(struct ieee80211_hw *dev, int channel) cck_power += priv->txpwr_base & 0xF; cck_power = min(cck_power, (u8)35); - ofdm_power = min(ofdm_power, (u8)15); + if (ofdm_power > (u8)15) + ofdm_power = 25; + else + ofdm_power += 10; ofdm_power += priv->txpwr_base >> 4; ofdm_power = min(ofdm_power, (u8)35); diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index 3fac8f81d59..a70cf16ee1a 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -668,7 +668,7 @@ sba_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt) * @dev: instance of PCI owned by the driver that's asking * @mask: number of address bits this PCI device can handle * - * See Documentation/DMA-mapping.txt + * See Documentation/PCI/PCI-DMA-mapping.txt */ static int sba_dma_supported( struct device *dev, u64 mask) { @@ -680,8 +680,8 @@ static int sba_dma_supported( struct device *dev, u64 mask) return(0); } - /* Documentation/DMA-mapping.txt tells drivers to try 64-bit first, - * then fall back to 32-bit if that fails. + /* Documentation/PCI/PCI-DMA-mapping.txt tells drivers to try 64-bit + * first, then fall back to 32-bit if that fails. * We are just "encouraging" 32-bit DMA masks here since we can * never allow IOMMU bypass unless we add special support for ZX1. */ @@ -706,7 +706,7 @@ static int sba_dma_supported( struct device *dev, u64 mask) * @size: number of bytes to map in driver buffer. * @direction: R/W or both. * - * See Documentation/DMA-mapping.txt + * See Documentation/PCI/PCI-DMA-mapping.txt */ static dma_addr_t sba_map_single(struct device *dev, void *addr, size_t size, @@ -785,7 +785,7 @@ sba_map_single(struct device *dev, void *addr, size_t size, * @size: number of bytes mapped in driver buffer. * @direction: R/W or both. * - * See Documentation/DMA-mapping.txt + * See Documentation/PCI/PCI-DMA-mapping.txt */ static void sba_unmap_single(struct device *dev, dma_addr_t iova, size_t size, @@ -861,7 +861,7 @@ sba_unmap_single(struct device *dev, dma_addr_t iova, size_t size, * @size: number of bytes mapped in driver buffer. * @dma_handle: IOVA of new buffer. * - * See Documentation/DMA-mapping.txt + * See Documentation/PCI/PCI-DMA-mapping.txt */ static void *sba_alloc_consistent(struct device *hwdev, size_t size, dma_addr_t *dma_handle, gfp_t gfp) @@ -892,7 +892,7 @@ static void *sba_alloc_consistent(struct device *hwdev, size_t size, * @vaddr: virtual address IOVA of "consistent" buffer. * @dma_handler: IO virtual address of "consistent" buffer. * - * See Documentation/DMA-mapping.txt + * See Documentation/PCI/PCI-DMA-mapping.txt */ static void sba_free_consistent(struct device *hwdev, size_t size, void *vaddr, @@ -927,7 +927,7 @@ int dump_run_sg = 0; * @nents: number of entries in list * @direction: R/W or both. * - * See Documentation/DMA-mapping.txt + * See Documentation/PCI/PCI-DMA-mapping.txt */ static int sba_map_sg(struct device *dev, struct scatterlist *sglist, int nents, @@ -1011,7 +1011,7 @@ sba_map_sg(struct device *dev, struct scatterlist *sglist, int nents, * @nents: number of entries in list * @direction: R/W or both. * - * See Documentation/DMA-mapping.txt + * See Documentation/PCI/PCI-DMA-mapping.txt */ static void sba_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents, diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 7c789f0a94d..de91ddab0a8 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -382,6 +382,11 @@ static int __init hp_wmi_input_setup(void) case KE_SW: set_bit(EV_SW, hp_wmi_input_dev->evbit); set_bit(key->keycode, hp_wmi_input_dev->swbit); + + /* Set initial dock state */ + input_report_switch(hp_wmi_input_dev, key->keycode, + hp_wmi_dock_state()); + input_sync(hp_wmi_input_dev); break; } } @@ -441,6 +446,7 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) bluetooth_rfkill->toggle_radio = hp_wmi_bluetooth_set; bluetooth_rfkill->user_claim_unsupported = 1; err = rfkill_register(bluetooth_rfkill); + if (err) goto register_bluetooth_error; } diff --git a/drivers/regulator/bq24022.c b/drivers/regulator/bq24022.c index 366565aba86..c175e38a4cd 100644 --- a/drivers/regulator/bq24022.c +++ b/drivers/regulator/bq24022.c @@ -152,11 +152,7 @@ static void __exit bq24022_exit(void) platform_driver_unregister(&bq24022_driver); } -/* - * make sure this is probed before gpio_vbus and pda_power, - * but after asic3 or other GPIO expander drivers. - */ -subsys_initcall(bq24022_init); +module_init(bq24022_init); module_exit(bq24022_exit); MODULE_AUTHOR("Philipp Zabel"); diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index 7aa35248181..5056e23e441 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c @@ -1435,7 +1435,7 @@ int wm8350_register_led(struct wm8350 *wm8350, int lednum, int dcdc, int isink, struct platform_device *pdev; int ret; - if (lednum > ARRAY_SIZE(wm8350->pmic.led) || lednum < 0) { + if (lednum >= ARRAY_SIZE(wm8350->pmic.led) || lednum < 0) { dev_err(wm8350->dev, "Invalid LED index %d\n", lednum); return -ENODEV; } diff --git a/drivers/serial/jsm/jsm_tty.c b/drivers/serial/jsm/jsm_tty.c index 3547558d2ca..324c74d2f66 100644 --- a/drivers/serial/jsm/jsm_tty.c +++ b/drivers/serial/jsm/jsm_tty.c @@ -161,6 +161,11 @@ static void jsm_tty_stop_rx(struct uart_port *port) channel->ch_bd->bd_ops->disable_receiver(channel); } +static void jsm_tty_enable_ms(struct uart_port *port) +{ + /* Nothing needed */ +} + static void jsm_tty_break(struct uart_port *port, int break_state) { unsigned long lock_flags; @@ -345,6 +350,7 @@ static struct uart_ops jsm_ops = { .start_tx = jsm_tty_start_tx, .send_xchar = jsm_tty_send_xchar, .stop_rx = jsm_tty_stop_rx, + .enable_ms = jsm_tty_enable_ms, .break_ctl = jsm_tty_break, .startup = jsm_tty_open, .shutdown = jsm_tty_close, diff --git a/drivers/staging/agnx/agnx.h b/drivers/staging/agnx/agnx.h index a75b0db3726..20f36da6247 100644 --- a/drivers/staging/agnx/agnx.h +++ b/drivers/staging/agnx/agnx.h @@ -1,6 +1,8 @@ #ifndef AGNX_H_ #define AGNX_H_ +#include <linux/io.h> + #include "xmit.h" #define PFX KBUILD_MODNAME ": " diff --git a/drivers/staging/altpciechdma/altpciechdma.c b/drivers/staging/altpciechdma/altpciechdma.c index 8e2b4ca0651..f516140ca97 100644 --- a/drivers/staging/altpciechdma/altpciechdma.c +++ b/drivers/staging/altpciechdma/altpciechdma.c @@ -531,7 +531,7 @@ static int __devinit dma_test(struct ape_dev *ape, struct pci_dev *dev) goto fail; /* allocate and map coherently-cached memory for a DMA-able buffer */ - /* @see 2.6.26.2/Documentation/DMA-mapping.txt line 318 */ + /* @see Documentation/PCI/PCI-DMA-mapping.txt, near line 318 */ buffer_virt = (u8 *)pci_alloc_consistent(dev, PAGE_SIZE * 4, &buffer_bus); if (!buffer_virt) { printk(KERN_DEBUG "Could not allocate coherent DMA buffer.\n"); @@ -846,7 +846,7 @@ static int __devinit probe(struct pci_dev *dev, const struct pci_device_id *id) #if 1 // @todo For now, disable 64-bit, because I do not understand the implications (DAC!) /* query for DMA transfer */ - /* @see Documentation/DMA-mapping.txt */ + /* @see Documentation/PCI/PCI-DMA-mapping.txt */ if (!pci_set_dma_mask(dev, DMA_64BIT_MASK)) { pci_set_consistent_dma_mask(dev, DMA_64BIT_MASK); /* use 64-bit DMA */ diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c index 6a4ceacb33f..758131cad08 100644 --- a/drivers/staging/android/binder.c +++ b/drivers/staging/android/binder.c @@ -319,6 +319,7 @@ int task_get_unused_fd_flags(struct task_struct *tsk, int flags) int fd, error; struct fdtable *fdt; unsigned long rlim_cur; + unsigned long irqs; if (files == NULL) return -ESRCH; @@ -335,12 +336,11 @@ repeat: * N.B. For clone tasks sharing a files structure, this test * will limit the total number of files that can be opened. */ - rcu_read_lock(); - if (tsk->signal) + rlim_cur = 0; + if (lock_task_sighand(tsk, &irqs)) { rlim_cur = tsk->signal->rlim[RLIMIT_NOFILE].rlim_cur; - else - rlim_cur = 0; - rcu_read_unlock(); + unlock_task_sighand(tsk, &irqs); + } if (fd >= rlim_cur) goto out; @@ -2649,14 +2649,14 @@ static void binder_vma_open(struct vm_area_struct *vma) { struct binder_proc *proc = vma->vm_private_data; if (binder_debug_mask & BINDER_DEBUG_OPEN_CLOSE) - printk(KERN_INFO "binder: %d open vm area %lx-%lx (%ld K) vma %lx pagep %lx\n", proc->pid, vma->vm_start, vma->vm_end, (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, vma->vm_page_prot.pgprot); + printk(KERN_INFO "binder: %d open vm area %lx-%lx (%ld K) vma %lx pagep %lx\n", proc->pid, vma->vm_start, vma->vm_end, (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, pgprot_val(vma->vm_page_prot)); dump_stack(); } static void binder_vma_close(struct vm_area_struct *vma) { struct binder_proc *proc = vma->vm_private_data; if (binder_debug_mask & BINDER_DEBUG_OPEN_CLOSE) - printk(KERN_INFO "binder: %d close vm area %lx-%lx (%ld K) vma %lx pagep %lx\n", proc->pid, vma->vm_start, vma->vm_end, (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, vma->vm_page_prot.pgprot); + printk(KERN_INFO "binder: %d close vm area %lx-%lx (%ld K) vma %lx pagep %lx\n", proc->pid, vma->vm_start, vma->vm_end, (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, pgprot_val(vma->vm_page_prot)); proc->vma = NULL; } @@ -2677,7 +2677,7 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma) vma->vm_end = vma->vm_start + SZ_4M; if (binder_debug_mask & BINDER_DEBUG_OPEN_CLOSE) - printk(KERN_INFO "binder_mmap: %d %lx-%lx (%ld K) vma %lx pagep %lx\n", proc->pid, vma->vm_start, vma->vm_end, (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, vma->vm_page_prot.pgprot); + printk(KERN_INFO "binder_mmap: %d %lx-%lx (%ld K) vma %lx pagep %lx\n", proc->pid, vma->vm_start, vma->vm_end, (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, pgprot_val(vma->vm_page_prot)); if (vma->vm_flags & FORBIDDEN_MMAP_FLAGS) { ret = -EPERM; diff --git a/drivers/staging/android/lowmemorykiller.txt b/drivers/staging/android/lowmemorykiller.txt new file mode 100644 index 00000000000..bd5c0c02896 --- /dev/null +++ b/drivers/staging/android/lowmemorykiller.txt @@ -0,0 +1,16 @@ +The lowmemorykiller driver lets user-space specify a set of memory thresholds +where processes with a range of oom_adj values will get killed. Specify the +minimum oom_adj values in /sys/module/lowmemorykiller/parameters/adj and the +number of free pages in /sys/module/lowmemorykiller/parameters/minfree. Both +files take a comma separated list of numbers in ascending order. + +For example, write "0,8" to /sys/module/lowmemorykiller/parameters/adj and +"1024,4096" to /sys/module/lowmemorykiller/parameters/minfree to kill processes +with a oom_adj value of 8 or higher when the free memory drops below 4096 pages +and kill processes with a oom_adj value of 0 or higher when the free memory +drops below 1024 pages. + +The driver considers memory used for caches to be free, but if a large +percentage of the cached memory is locked this can be very inaccurate +and processes may not get killed until the normal oom killer is triggered. + diff --git a/drivers/staging/android/timed_gpio.c b/drivers/staging/android/timed_gpio.c index bea68c9fc94..903270cbbe0 100644 --- a/drivers/staging/android/timed_gpio.c +++ b/drivers/staging/android/timed_gpio.c @@ -18,7 +18,7 @@ #include <linux/platform_device.h> #include <linux/hrtimer.h> #include <linux/err.h> -#include <asm/arch/gpio.h> +#include <linux/gpio.h> #include "timed_gpio.h" @@ -49,7 +49,8 @@ static ssize_t gpio_enable_show(struct device *dev, struct device_attribute *att if (hrtimer_active(&gpio_data->timer)) { ktime_t r = hrtimer_get_remaining(&gpio_data->timer); - remaining = r.tv.sec * 1000 + r.tv.nsec / 1000000; + struct timeval t = ktime_to_timeval(r); + remaining = t.tv_sec * 1000 + t.tv_usec; } else remaining = 0; diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig index b501bfb9c75..b47ca1e7e38 100644 --- a/drivers/staging/comedi/Kconfig +++ b/drivers/staging/comedi/Kconfig @@ -1,6 +1,7 @@ config COMEDI tristate "Data Acquision support (comedi)" default N + depends on m ---help--- Enable support a wide range of data acquision devices for Linux. diff --git a/drivers/staging/meilhaus/Kconfig b/drivers/staging/meilhaus/Kconfig index 6def83fa2c9..923af22a468 100644 --- a/drivers/staging/meilhaus/Kconfig +++ b/drivers/staging/meilhaus/Kconfig @@ -4,6 +4,7 @@ menuconfig MEILHAUS tristate "Meilhaus support" + depends on m ---help--- If you have a Meilhaus card, say Y (or M) here. @@ -18,7 +19,7 @@ if MEILHAUS config ME0600 tristate "Meilhaus ME-600 support" default n - depends on PCI + depends on PCI && m help This driver supports the Meilhaus ME-600 family of boards that do data collection and multipurpose I/O. @@ -29,7 +30,7 @@ config ME0600 config ME0900 tristate "Meilhaus ME-900 support" default n - depends on PCI + depends on PCI && m help This driver supports the Meilhaus ME-900 family of boards that do data collection and multipurpose I/O. @@ -40,7 +41,7 @@ config ME0900 config ME1000 tristate "Meilhaus ME-1000 support" default n - depends on PCI + depends on PCI && m help This driver supports the Meilhaus ME-1000 family of boards that do data collection and multipurpose I/O. @@ -51,7 +52,7 @@ config ME1000 config ME1400 tristate "Meilhaus ME-1400 support" default n - depends on PCI + depends on PCI && m help This driver supports the Meilhaus ME-1400 family of boards that do data collection and multipurpose I/O. @@ -62,7 +63,7 @@ config ME1400 config ME1600 tristate "Meilhaus ME-1600 support" default n - depends on PCI + depends on PCI && m help This driver supports the Meilhaus ME-1600 family of boards that do data collection and multipurpose I/O. @@ -73,7 +74,7 @@ config ME1600 config ME4600 tristate "Meilhaus ME-4600 support" default n - depends on PCI + depends on PCI && m help This driver supports the Meilhaus ME-4600 family of boards that do data collection and multipurpose I/O. @@ -84,7 +85,7 @@ config ME4600 config ME6000 tristate "Meilhaus ME-6000 support" default n - depends on PCI + depends on PCI && m help This driver supports the Meilhaus ME-6000 family of boards that do data collection and multipurpose I/O. @@ -95,7 +96,7 @@ config ME6000 config ME8100 tristate "Meilhaus ME-8100 support" default n - depends on PCI + depends on PCI && m help This driver supports the Meilhaus ME-8100 family of boards that do data collection and multipurpose I/O. @@ -106,7 +107,7 @@ config ME8100 config ME8200 tristate "Meilhaus ME-8200 support" default n - depends on PCI + depends on PCI && m help This driver supports the Meilhaus ME-8200 family of boards that do data collection and multipurpose I/O. @@ -117,7 +118,7 @@ config ME8200 config MEDUMMY tristate "Meilhaus dummy driver" default n - depends on PCI + depends on PCI && m help This provides a dummy driver for the Meilhaus driver package diff --git a/drivers/staging/poch/poch.c b/drivers/staging/poch/poch.c index ec343ef53a8..0d111ddfabb 100644 --- a/drivers/staging/poch/poch.c +++ b/drivers/staging/poch/poch.c @@ -1026,7 +1026,7 @@ static int poch_ioctl(struct inode *inode, struct file *filp, } break; case POCH_IOC_GET_COUNTERS: - if (access_ok(VERIFY_WRITE, argp, sizeof(struct poch_counters))) + if (!access_ok(VERIFY_WRITE, argp, sizeof(struct poch_counters))) return -EFAULT; spin_lock_irq(&channel->counters_lock); diff --git a/drivers/staging/usbip/usbip_common.c b/drivers/staging/usbip/usbip_common.c index 72e209276ea..22f93dd0ba0 100644 --- a/drivers/staging/usbip/usbip_common.c +++ b/drivers/staging/usbip/usbip_common.c @@ -406,8 +406,20 @@ void usbip_start_threads(struct usbip_device *ud) /* * threads are invoked per one device (per one connection). */ - kernel_thread(usbip_thread, (void *)&ud->tcp_rx, 0); - kernel_thread(usbip_thread, (void *)&ud->tcp_tx, 0); + int retval; + + retval = kernel_thread(usbip_thread, (void *)&ud->tcp_rx, 0); + if (retval < 0) { + printk(KERN_ERR "Creating tcp_rx thread for ud %p failed.\n", + ud); + return; + } + retval = kernel_thread(usbip_thread, (void *)&ud->tcp_tx, 0); + if (retval < 0) { + printk(KERN_ERR "Creating tcp_tx thread for ud %p failed.\n", + ud); + return; + } /* confirm threads are starting */ wait_for_completion(&ud->tcp_rx.thread_done); diff --git a/drivers/usb/host/whci/asl.c b/drivers/usb/host/whci/asl.c index 577c0d29849..2291c5f5af5 100644 --- a/drivers/usb/host/whci/asl.c +++ b/drivers/usb/host/whci/asl.c @@ -170,12 +170,17 @@ void asl_stop(struct whc *whc) void asl_update(struct whc *whc, uint32_t wusbcmd) { struct wusbhc *wusbhc = &whc->wusbhc; + long t; mutex_lock(&wusbhc->mutex); if (wusbhc->active) { whc_write_wusbcmd(whc, wusbcmd, wusbcmd); - wait_event(whc->async_list_wq, - (le_readl(whc->base + WUSBCMD) & WUSBCMD_ASYNC_UPDATED) == 0); + t = wait_event_timeout( + whc->async_list_wq, + (le_readl(whc->base + WUSBCMD) & WUSBCMD_ASYNC_UPDATED) == 0, + msecs_to_jiffies(1000)); + if (t == 0) + whc_hw_error(whc, "ASL update timeout"); } mutex_unlock(&wusbhc->mutex); } diff --git a/drivers/usb/host/whci/hw.c b/drivers/usb/host/whci/hw.c index d498e720321..6afa2e37916 100644 --- a/drivers/usb/host/whci/hw.c +++ b/drivers/usb/host/whci/hw.c @@ -87,3 +87,18 @@ out: return ret; } + +/** + * whc_hw_error - recover from a hardware error + * @whc: the WHCI HC that broke. + * @reason: a description of the failure. + * + * Recover from broken hardware with a full reset. + */ +void whc_hw_error(struct whc *whc, const char *reason) +{ + struct wusbhc *wusbhc = &whc->wusbhc; + + dev_err(&whc->umc->dev, "hardware error: %s\n", reason); + wusbhc_reset_all(wusbhc); +} diff --git a/drivers/usb/host/whci/pzl.c b/drivers/usb/host/whci/pzl.c index 2ae5abf69a6..7dc85a0bee7 100644 --- a/drivers/usb/host/whci/pzl.c +++ b/drivers/usb/host/whci/pzl.c @@ -183,12 +183,17 @@ void pzl_stop(struct whc *whc) void pzl_update(struct whc *whc, uint32_t wusbcmd) { struct wusbhc *wusbhc = &whc->wusbhc; + long t; mutex_lock(&wusbhc->mutex); if (wusbhc->active) { whc_write_wusbcmd(whc, wusbcmd, wusbcmd); - wait_event(whc->periodic_list_wq, - (le_readl(whc->base + WUSBCMD) & WUSBCMD_PERIODIC_UPDATED) == 0); + t = wait_event_timeout( + whc->periodic_list_wq, + (le_readl(whc->base + WUSBCMD) & WUSBCMD_PERIODIC_UPDATED) == 0, + msecs_to_jiffies(1000)); + if (t == 0) + whc_hw_error(whc, "PZL update timeout"); } mutex_unlock(&wusbhc->mutex); } diff --git a/drivers/usb/host/whci/whcd.h b/drivers/usb/host/whci/whcd.h index 0f3540f04f5..d3543a181dc 100644 --- a/drivers/usb/host/whci/whcd.h +++ b/drivers/usb/host/whci/whcd.h @@ -137,6 +137,7 @@ void whc_clean_up(struct whc *whc); /* hw.c */ void whc_write_wusbcmd(struct whc *whc, u32 mask, u32 val); int whc_do_gencmd(struct whc *whc, u32 cmd, u32 params, void *addr, size_t len); +void whc_hw_error(struct whc *whc, const char *reason); /* wusb.c */ int whc_wusbhc_start(struct wusbhc *wusbhc); diff --git a/drivers/usb/wusbcore/devconnect.c b/drivers/usb/wusbcore/devconnect.c index e2e7e4bc846..8e18141bb2e 100644 --- a/drivers/usb/wusbcore/devconnect.c +++ b/drivers/usb/wusbcore/devconnect.c @@ -386,6 +386,7 @@ static void __wusbhc_dev_disconnect(struct wusbhc *wusbhc, | USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_HIGH_SPEED); port->change |= USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE; if (wusb_dev) { + dev_dbg(wusbhc->dev, "disconnecting device from port %d\n", wusb_dev->port_idx); if (!list_empty(&wusb_dev->cack_node)) list_del_init(&wusb_dev->cack_node); /* For the one in cack_add() */ diff --git a/drivers/usb/wusbcore/rh.c b/drivers/usb/wusbcore/rh.c index 3937bf6f8ce..9fe4246cecb 100644 --- a/drivers/usb/wusbcore/rh.c +++ b/drivers/usb/wusbcore/rh.c @@ -100,6 +100,9 @@ static int wusbhc_rh_port_reset(struct wusbhc *wusbhc, u8 port_idx) struct wusb_port *port = wusb_port_by_idx(wusbhc, port_idx); struct wusb_dev *wusb_dev = port->wusb_dev; + if (wusb_dev == NULL) + return -ENOTCONN; + port->status |= USB_PORT_STAT_RESET; port->change |= USB_PORT_STAT_C_RESET; diff --git a/drivers/uwb/allocator.c b/drivers/uwb/allocator.c index c8185e6b0cd..c13cec7dcbc 100644 --- a/drivers/uwb/allocator.c +++ b/drivers/uwb/allocator.c @@ -15,7 +15,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <linux/version.h> #include <linux/kernel.h> #include <linux/uwb.h> diff --git a/drivers/uwb/drp.c b/drivers/uwb/drp.c index 2b4f9406789..4f5ca99a04b 100644 --- a/drivers/uwb/drp.c +++ b/drivers/uwb/drp.c @@ -66,14 +66,14 @@ static void uwb_rc_set_drp_cmd_done(struct uwb_rc *rc, void *arg, } else dev_err(&rc->uwb_dev.dev, "SET-DRP-IE: timeout\n"); - spin_lock(&rc->rsvs_lock); + spin_lock_bh(&rc->rsvs_lock); if (rc->set_drp_ie_pending > 1) { rc->set_drp_ie_pending = 0; uwb_rsv_queue_update(rc); } else { rc->set_drp_ie_pending = 0; } - spin_unlock(&rc->rsvs_lock); + spin_unlock_bh(&rc->rsvs_lock); } /** diff --git a/drivers/uwb/rsv.c b/drivers/uwb/rsv.c index ec6eecb32f3..6b76f4bb4cc 100644 --- a/drivers/uwb/rsv.c +++ b/drivers/uwb/rsv.c @@ -114,7 +114,8 @@ void uwb_rsv_dump(char *text, struct uwb_rsv *rsv) devaddr = rsv->target.devaddr; uwb_dev_addr_print(target, sizeof(target), &devaddr); - dev_dbg(dev, "rsv %s -> %s: %s\n", owner, target, uwb_rsv_state_str(rsv->state)); + dev_dbg(dev, "rsv %s %s -> %s: %s\n", + text, owner, target, uwb_rsv_state_str(rsv->state)); } static void uwb_rsv_release(struct kref *kref) @@ -511,8 +512,7 @@ void uwb_rsv_remove(struct uwb_rsv *rsv) if (uwb_rsv_is_owner(rsv)) uwb_rsv_put_stream(rsv); - - del_timer_sync(&rsv->timer); + uwb_dev_put(rsv->owner); if (rsv->target.type == UWB_RSV_TARGET_DEV) uwb_dev_put(rsv->target.dev); @@ -870,7 +870,7 @@ void uwb_rsv_queue_update(struct uwb_rc *rc) */ void uwb_rsv_sched_update(struct uwb_rc *rc) { - spin_lock(&rc->rsvs_lock); + spin_lock_bh(&rc->rsvs_lock); if (!delayed_work_pending(&rc->rsv_update_work)) { if (rc->set_drp_ie_pending > 0) { rc->set_drp_ie_pending++; @@ -879,7 +879,7 @@ void uwb_rsv_sched_update(struct uwb_rc *rc) uwb_rsv_queue_update(rc); } unlock: - spin_unlock(&rc->rsvs_lock); + spin_unlock_bh(&rc->rsvs_lock); } /* @@ -943,13 +943,22 @@ void uwb_rsv_remove_all(struct uwb_rc *rc) mutex_lock(&rc->rsvs_mutex); list_for_each_entry_safe(rsv, t, &rc->reservations, rc_node) { - uwb_rsv_remove(rsv); + if (rsv->state != UWB_RSV_STATE_NONE) + uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE); + del_timer_sync(&rsv->timer); } /* Cancel any postponed update. */ rc->set_drp_ie_pending = 0; mutex_unlock(&rc->rsvs_mutex); cancel_delayed_work_sync(&rc->rsv_update_work); + flush_workqueue(rc->rsv_workq); + + mutex_lock(&rc->rsvs_mutex); + list_for_each_entry_safe(rsv, t, &rc->reservations, rc_node) { + uwb_rsv_remove(rsv); + } + mutex_unlock(&rc->rsvs_mutex); } void uwb_rsv_init(struct uwb_rc *rc) diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index c94f71980c1..f0267706cb4 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -41,7 +41,7 @@ menuconfig FB You need an utility program called fbset to make full use of frame buffer devices. Please read <file:Documentation/fb/framebuffer.txt> and the Framebuffer-HOWTO at - <http://www.tahallah.demon.co.uk/programming/prog.html> for more + <http://www.munted.org.uk/programming/Framebuffer-HOWTO-1.2.html> for more information. Say Y here and to the driver for your graphics board below if you diff --git a/drivers/virtio/virtio_pci.c b/drivers/virtio/virtio_pci.c index bef6b45e8a5..330aacbdec1 100644 --- a/drivers/virtio/virtio_pci.c +++ b/drivers/virtio/virtio_pci.c @@ -192,7 +192,7 @@ static irqreturn_t vp_interrupt(int irq, void *opaque) drv = container_of(vp_dev->vdev.dev.driver, struct virtio_driver, driver); - if (drv->config_changed) + if (drv && drv->config_changed) drv->config_changed(&vp_dev->vdev); } diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index 2ba8f95516a..efa4b363ce7 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c @@ -498,7 +498,7 @@ static ssize_t store_target_kb(struct sys_device *dev, if (!capable(CAP_SYS_ADMIN)) return -EPERM; - target_bytes = memparse(buf, &endchar); + target_bytes = simple_strtoull(buf, &endchar, 0) * 1024; balloon_set_new_target(target_bytes >> PAGE_SHIFT); @@ -508,8 +508,39 @@ static ssize_t store_target_kb(struct sys_device *dev, static SYSDEV_ATTR(target_kb, S_IRUGO | S_IWUSR, show_target_kb, store_target_kb); + +static ssize_t show_target(struct sys_device *dev, struct sysdev_attribute *attr, + char *buf) +{ + return sprintf(buf, "%llu\n", + (u64)balloon_stats.target_pages << PAGE_SHIFT); +} + +static ssize_t store_target(struct sys_device *dev, + struct sysdev_attribute *attr, + const char *buf, + size_t count) +{ + char *endchar; + unsigned long long target_bytes; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + target_bytes = memparse(buf, &endchar); + + balloon_set_new_target(target_bytes >> PAGE_SHIFT); + + return count; +} + +static SYSDEV_ATTR(target, S_IRUGO | S_IWUSR, + show_target, store_target); + + static struct sysdev_attribute *balloon_attrs[] = { &attr_target_kb, + &attr_target, }; static struct attribute *balloon_info_attrs[] = { |