diff options
author | Takashi Iwai <tiwai@suse.de> | 2013-02-05 08:48:03 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2013-02-05 08:48:03 -0500 |
commit | 2faea5274f079630991800bd579f85a621f96ef5 (patch) | |
tree | 4afb9032f0ae3a3e8b539e0abe40cda320989ac3 /drivers | |
parent | 16c5ab1d3a6d1b11ed2966fa33a3a4fecd13a2bc (diff) | |
parent | edac894389f9c9de2a1368c78809c824b343f3a5 (diff) |
Merge branch 'for-linus' into for-next
Merge pending fixes that haven't pulled into 3.8.
Diffstat (limited to 'drivers')
302 files changed, 9456 insertions, 2083 deletions
diff --git a/drivers/acpi/apei/apei-base.c b/drivers/acpi/apei/apei-base.c index 00a783661d0b..46f80e2c92f7 100644 --- a/drivers/acpi/apei/apei-base.c +++ b/drivers/acpi/apei/apei-base.c | |||
@@ -590,6 +590,9 @@ static int apei_check_gar(struct acpi_generic_address *reg, u64 *paddr, | |||
590 | if (bit_width == 32 && bit_offset == 0 && (*paddr & 0x03) == 0 && | 590 | if (bit_width == 32 && bit_offset == 0 && (*paddr & 0x03) == 0 && |
591 | *access_bit_width < 32) | 591 | *access_bit_width < 32) |
592 | *access_bit_width = 32; | 592 | *access_bit_width = 32; |
593 | else if (bit_width == 64 && bit_offset == 0 && (*paddr & 0x07) == 0 && | ||
594 | *access_bit_width < 64) | ||
595 | *access_bit_width = 64; | ||
593 | 596 | ||
594 | if ((bit_width + bit_offset) > *access_bit_width) { | 597 | if ((bit_width + bit_offset) > *access_bit_width) { |
595 | pr_warning(FW_BUG APEI_PFX | 598 | pr_warning(FW_BUG APEI_PFX |
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 95af6f674a6c..35da18113216 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c | |||
@@ -297,7 +297,7 @@ static int acpi_platform_notify(struct device *dev) | |||
297 | if (!ret) { | 297 | if (!ret) { |
298 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 298 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
299 | 299 | ||
300 | acpi_get_name(dev->acpi_handle, ACPI_FULL_PATHNAME, &buffer); | 300 | acpi_get_name(ACPI_HANDLE(dev), ACPI_FULL_PATHNAME, &buffer); |
301 | DBG("Device %s -> %s\n", dev_name(dev), (char *)buffer.pointer); | 301 | DBG("Device %s -> %s\n", dev_name(dev), (char *)buffer.pointer); |
302 | kfree(buffer.pointer); | 302 | kfree(buffer.pointer); |
303 | } else | 303 | } else |
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index f1a5da44591d..ed9a1cc690be 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c | |||
@@ -958,6 +958,9 @@ static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr) | |||
958 | return -EINVAL; | 958 | return -EINVAL; |
959 | } | 959 | } |
960 | 960 | ||
961 | if (!dev) | ||
962 | return -EINVAL; | ||
963 | |||
961 | dev->cpu = pr->id; | 964 | dev->cpu = pr->id; |
962 | 965 | ||
963 | if (max_cstate == 0) | 966 | if (max_cstate == 0) |
@@ -1149,6 +1152,7 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr) | |||
1149 | } | 1152 | } |
1150 | 1153 | ||
1151 | /* Populate Updated C-state information */ | 1154 | /* Populate Updated C-state information */ |
1155 | acpi_processor_get_power_info(pr); | ||
1152 | acpi_processor_setup_cpuidle_states(pr); | 1156 | acpi_processor_setup_cpuidle_states(pr); |
1153 | 1157 | ||
1154 | /* Enable all cpuidle devices */ | 1158 | /* Enable all cpuidle devices */ |
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index 836bfe069042..53e7ac9403a7 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c | |||
@@ -340,6 +340,13 @@ static void amd_fixup_frequency(struct acpi_processor_px *px, int i) | |||
340 | if ((boot_cpu_data.x86 == 0x10 && boot_cpu_data.x86_model < 10) | 340 | if ((boot_cpu_data.x86 == 0x10 && boot_cpu_data.x86_model < 10) |
341 | || boot_cpu_data.x86 == 0x11) { | 341 | || boot_cpu_data.x86 == 0x11) { |
342 | rdmsr(MSR_AMD_PSTATE_DEF_BASE + index, lo, hi); | 342 | rdmsr(MSR_AMD_PSTATE_DEF_BASE + index, lo, hi); |
343 | /* | ||
344 | * MSR C001_0064+: | ||
345 | * Bit 63: PstateEn. Read-write. If set, the P-state is valid. | ||
346 | */ | ||
347 | if (!(hi & BIT(31))) | ||
348 | return; | ||
349 | |||
343 | fid = lo & 0x3f; | 350 | fid = lo & 0x3f; |
344 | did = (lo >> 6) & 7; | 351 | did = (lo >> 6) & 7; |
345 | if (boot_cpu_data.x86 == 0x10) | 352 | if (boot_cpu_data.x86 == 0x10) |
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 7862d17976b7..497912732566 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c | |||
@@ -53,6 +53,7 @@ | |||
53 | 53 | ||
54 | enum { | 54 | enum { |
55 | AHCI_PCI_BAR_STA2X11 = 0, | 55 | AHCI_PCI_BAR_STA2X11 = 0, |
56 | AHCI_PCI_BAR_ENMOTUS = 2, | ||
56 | AHCI_PCI_BAR_STANDARD = 5, | 57 | AHCI_PCI_BAR_STANDARD = 5, |
57 | }; | 58 | }; |
58 | 59 | ||
@@ -410,6 +411,9 @@ static const struct pci_device_id ahci_pci_tbl[] = { | |||
410 | { PCI_VDEVICE(ASMEDIA, 0x0611), board_ahci }, /* ASM1061 */ | 411 | { PCI_VDEVICE(ASMEDIA, 0x0611), board_ahci }, /* ASM1061 */ |
411 | { PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci }, /* ASM1062 */ | 412 | { PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci }, /* ASM1062 */ |
412 | 413 | ||
414 | /* Enmotus */ | ||
415 | { PCI_DEVICE(0x1c44, 0x8000), board_ahci }, | ||
416 | |||
413 | /* Generic, PCI class code for AHCI */ | 417 | /* Generic, PCI class code for AHCI */ |
414 | { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, | 418 | { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, |
415 | PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci }, | 419 | PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci }, |
@@ -1098,9 +1102,11 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1098 | dev_info(&pdev->dev, | 1102 | dev_info(&pdev->dev, |
1099 | "PDC42819 can only drive SATA devices with this driver\n"); | 1103 | "PDC42819 can only drive SATA devices with this driver\n"); |
1100 | 1104 | ||
1101 | /* The Connext uses non-standard BAR */ | 1105 | /* Both Connext and Enmotus devices use non-standard BARs */ |
1102 | if (pdev->vendor == PCI_VENDOR_ID_STMICRO && pdev->device == 0xCC06) | 1106 | if (pdev->vendor == PCI_VENDOR_ID_STMICRO && pdev->device == 0xCC06) |
1103 | ahci_pci_bar = AHCI_PCI_BAR_STA2X11; | 1107 | ahci_pci_bar = AHCI_PCI_BAR_STA2X11; |
1108 | else if (pdev->vendor == 0x1c44 && pdev->device == 0x8000) | ||
1109 | ahci_pci_bar = AHCI_PCI_BAR_ENMOTUS; | ||
1104 | 1110 | ||
1105 | /* acquire resources */ | 1111 | /* acquire resources */ |
1106 | rc = pcim_enable_device(pdev); | 1112 | rc = pcim_enable_device(pdev); |
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 320712a7b9ea..6cd7805e47ca 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c | |||
@@ -1951,13 +1951,13 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep) | |||
1951 | /* Use the nominal value 10 ms if the read MDAT is zero, | 1951 | /* Use the nominal value 10 ms if the read MDAT is zero, |
1952 | * the nominal value of DETO is 20 ms. | 1952 | * the nominal value of DETO is 20 ms. |
1953 | */ | 1953 | */ |
1954 | if (dev->sata_settings[ATA_LOG_DEVSLP_VALID] & | 1954 | if (dev->devslp_timing[ATA_LOG_DEVSLP_VALID] & |
1955 | ATA_LOG_DEVSLP_VALID_MASK) { | 1955 | ATA_LOG_DEVSLP_VALID_MASK) { |
1956 | mdat = dev->sata_settings[ATA_LOG_DEVSLP_MDAT] & | 1956 | mdat = dev->devslp_timing[ATA_LOG_DEVSLP_MDAT] & |
1957 | ATA_LOG_DEVSLP_MDAT_MASK; | 1957 | ATA_LOG_DEVSLP_MDAT_MASK; |
1958 | if (!mdat) | 1958 | if (!mdat) |
1959 | mdat = 10; | 1959 | mdat = 10; |
1960 | deto = dev->sata_settings[ATA_LOG_DEVSLP_DETO]; | 1960 | deto = dev->devslp_timing[ATA_LOG_DEVSLP_DETO]; |
1961 | if (!deto) | 1961 | if (!deto) |
1962 | deto = 20; | 1962 | deto = 20; |
1963 | } else { | 1963 | } else { |
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 9e8b99af400d..46cd3f4c6aaa 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c | |||
@@ -2325,24 +2325,28 @@ int ata_dev_configure(struct ata_device *dev) | |||
2325 | } | 2325 | } |
2326 | } | 2326 | } |
2327 | 2327 | ||
2328 | /* check and mark DevSlp capability */ | 2328 | /* Check and mark DevSlp capability. Get DevSlp timing variables |
2329 | if (ata_id_has_devslp(dev->id)) | 2329 | * from SATA Settings page of Identify Device Data Log. |
2330 | dev->flags |= ATA_DFLAG_DEVSLP; | ||
2331 | |||
2332 | /* Obtain SATA Settings page from Identify Device Data Log, | ||
2333 | * which contains DevSlp timing variables etc. | ||
2334 | * Exclude old devices with ata_id_has_ncq() | ||
2335 | */ | 2330 | */ |
2336 | if (ata_id_has_ncq(dev->id)) { | 2331 | if (ata_id_has_devslp(dev->id)) { |
2332 | u8 sata_setting[ATA_SECT_SIZE]; | ||
2333 | int i, j; | ||
2334 | |||
2335 | dev->flags |= ATA_DFLAG_DEVSLP; | ||
2337 | err_mask = ata_read_log_page(dev, | 2336 | err_mask = ata_read_log_page(dev, |
2338 | ATA_LOG_SATA_ID_DEV_DATA, | 2337 | ATA_LOG_SATA_ID_DEV_DATA, |
2339 | ATA_LOG_SATA_SETTINGS, | 2338 | ATA_LOG_SATA_SETTINGS, |
2340 | dev->sata_settings, | 2339 | sata_setting, |
2341 | 1); | 2340 | 1); |
2342 | if (err_mask) | 2341 | if (err_mask) |
2343 | ata_dev_dbg(dev, | 2342 | ata_dev_dbg(dev, |
2344 | "failed to get Identify Device Data, Emask 0x%x\n", | 2343 | "failed to get Identify Device Data, Emask 0x%x\n", |
2345 | err_mask); | 2344 | err_mask); |
2345 | else | ||
2346 | for (i = 0; i < ATA_LOG_DEVSLP_SIZE; i++) { | ||
2347 | j = ATA_LOG_DEVSLP_OFFSET + i; | ||
2348 | dev->devslp_timing[i] = sata_setting[j]; | ||
2349 | } | ||
2346 | } | 2350 | } |
2347 | 2351 | ||
2348 | dev->cdb_len = 16; | 2352 | dev->cdb_len = 16; |
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index bf039b0e97b7..bcf4437214f5 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c | |||
@@ -2094,7 +2094,7 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, | |||
2094 | */ | 2094 | */ |
2095 | static inline int ata_eh_worth_retry(struct ata_queued_cmd *qc) | 2095 | static inline int ata_eh_worth_retry(struct ata_queued_cmd *qc) |
2096 | { | 2096 | { |
2097 | if (qc->flags & AC_ERR_MEDIA) | 2097 | if (qc->err_mask & AC_ERR_MEDIA) |
2098 | return 0; /* don't retry media errors */ | 2098 | return 0; /* don't retry media errors */ |
2099 | if (qc->flags & ATA_QCFLAG_IO) | 2099 | if (qc->flags & ATA_QCFLAG_IO) |
2100 | return 1; /* otherwise retry anything from fs stack */ | 2100 | return 1; /* otherwise retry anything from fs stack */ |
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 63452943abd1..fb10728f6372 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c | |||
@@ -224,7 +224,7 @@ static void cpu_device_release(struct device *dev) | |||
224 | * by the cpu device. | 224 | * by the cpu device. |
225 | * | 225 | * |
226 | * Never copy this way of doing things, or you too will be made fun of | 226 | * Never copy this way of doing things, or you too will be made fun of |
227 | * on the linux-kerenl list, you have been warned. | 227 | * on the linux-kernel list, you have been warned. |
228 | */ | 228 | */ |
229 | } | 229 | } |
230 | 230 | ||
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index d81460309182..b392b353be39 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c | |||
@@ -305,7 +305,7 @@ static bool fw_read_file_contents(struct file *file, struct firmware_buf *fw_buf | |||
305 | char *buf; | 305 | char *buf; |
306 | 306 | ||
307 | size = fw_file_size(file); | 307 | size = fw_file_size(file); |
308 | if (size < 0) | 308 | if (size <= 0) |
309 | return false; | 309 | return false; |
310 | buf = vmalloc(size); | 310 | buf = vmalloc(size); |
311 | if (!buf) | 311 | if (!buf) |
diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c index 07aad786f817..d9a6c94ce423 100644 --- a/drivers/base/regmap/regmap-debugfs.c +++ b/drivers/base/regmap/regmap-debugfs.c | |||
@@ -56,6 +56,19 @@ static const struct file_operations regmap_name_fops = { | |||
56 | .llseek = default_llseek, | 56 | .llseek = default_llseek, |
57 | }; | 57 | }; |
58 | 58 | ||
59 | static void regmap_debugfs_free_dump_cache(struct regmap *map) | ||
60 | { | ||
61 | struct regmap_debugfs_off_cache *c; | ||
62 | |||
63 | while (!list_empty(&map->debugfs_off_cache)) { | ||
64 | c = list_first_entry(&map->debugfs_off_cache, | ||
65 | struct regmap_debugfs_off_cache, | ||
66 | list); | ||
67 | list_del(&c->list); | ||
68 | kfree(c); | ||
69 | } | ||
70 | } | ||
71 | |||
59 | /* | 72 | /* |
60 | * Work out where the start offset maps into register numbers, bearing | 73 | * Work out where the start offset maps into register numbers, bearing |
61 | * in mind that we suppress hidden registers. | 74 | * in mind that we suppress hidden registers. |
@@ -91,8 +104,10 @@ static unsigned int regmap_debugfs_get_dump_start(struct regmap *map, | |||
91 | /* No cache entry? Start a new one */ | 104 | /* No cache entry? Start a new one */ |
92 | if (!c) { | 105 | if (!c) { |
93 | c = kzalloc(sizeof(*c), GFP_KERNEL); | 106 | c = kzalloc(sizeof(*c), GFP_KERNEL); |
94 | if (!c) | 107 | if (!c) { |
95 | break; | 108 | regmap_debugfs_free_dump_cache(map); |
109 | return base; | ||
110 | } | ||
96 | c->min = p; | 111 | c->min = p; |
97 | c->base_reg = i; | 112 | c->base_reg = i; |
98 | } | 113 | } |
@@ -101,14 +116,32 @@ static unsigned int regmap_debugfs_get_dump_start(struct regmap *map, | |||
101 | } | 116 | } |
102 | } | 117 | } |
103 | 118 | ||
119 | /* Close the last entry off if we didn't scan beyond it */ | ||
120 | if (c) { | ||
121 | c->max = p - 1; | ||
122 | list_add_tail(&c->list, | ||
123 | &map->debugfs_off_cache); | ||
124 | } | ||
125 | |||
126 | /* | ||
127 | * This should never happen; we return above if we fail to | ||
128 | * allocate and we should never be in this code if there are | ||
129 | * no registers at all. | ||
130 | */ | ||
131 | if (list_empty(&map->debugfs_off_cache)) { | ||
132 | WARN_ON(list_empty(&map->debugfs_off_cache)); | ||
133 | return base; | ||
134 | } | ||
135 | |||
104 | /* Find the relevant block */ | 136 | /* Find the relevant block */ |
105 | list_for_each_entry(c, &map->debugfs_off_cache, list) { | 137 | list_for_each_entry(c, &map->debugfs_off_cache, list) { |
106 | if (*pos >= c->min && *pos <= c->max) { | 138 | if (from >= c->min && from <= c->max) { |
107 | *pos = c->min; | 139 | *pos = c->min; |
108 | return c->base_reg; | 140 | return c->base_reg; |
109 | } | 141 | } |
110 | 142 | ||
111 | ret = c->max; | 143 | *pos = c->min; |
144 | ret = c->base_reg; | ||
112 | } | 145 | } |
113 | 146 | ||
114 | return ret; | 147 | return ret; |
@@ -387,16 +420,8 @@ void regmap_debugfs_init(struct regmap *map, const char *name) | |||
387 | 420 | ||
388 | void regmap_debugfs_exit(struct regmap *map) | 421 | void regmap_debugfs_exit(struct regmap *map) |
389 | { | 422 | { |
390 | struct regmap_debugfs_off_cache *c; | ||
391 | |||
392 | debugfs_remove_recursive(map->debugfs); | 423 | debugfs_remove_recursive(map->debugfs); |
393 | while (!list_empty(&map->debugfs_off_cache)) { | 424 | regmap_debugfs_free_dump_cache(map); |
394 | c = list_first_entry(&map->debugfs_off_cache, | ||
395 | struct regmap_debugfs_off_cache, | ||
396 | list); | ||
397 | list_del(&c->list); | ||
398 | kfree(c); | ||
399 | } | ||
400 | kfree(map->debugfs_name); | 425 | kfree(map->debugfs_name); |
401 | } | 426 | } |
402 | 427 | ||
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 42d5cb0f503f..f00b059c057a 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c | |||
@@ -1106,7 +1106,7 @@ EXPORT_SYMBOL_GPL(regmap_raw_write); | |||
1106 | * @val_count: Number of registers to write | 1106 | * @val_count: Number of registers to write |
1107 | * | 1107 | * |
1108 | * This function is intended to be used for writing a large block of | 1108 | * This function is intended to be used for writing a large block of |
1109 | * data to be device either in single transfer or multiple transfer. | 1109 | * data to the device either in single transfer or multiple transfer. |
1110 | * | 1110 | * |
1111 | * A value of zero will be returned on success, a negative errno will | 1111 | * A value of zero will be returned on success, a negative errno will |
1112 | * be returned in error cases. | 1112 | * be returned in error cases. |
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 9d8409c02082..8ad21a25bc0d 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c | |||
@@ -889,6 +889,7 @@ static void virtblk_remove(struct virtio_device *vdev) | |||
889 | { | 889 | { |
890 | struct virtio_blk *vblk = vdev->priv; | 890 | struct virtio_blk *vblk = vdev->priv; |
891 | int index = vblk->index; | 891 | int index = vblk->index; |
892 | int refc; | ||
892 | 893 | ||
893 | /* Prevent config work handler from accessing the device. */ | 894 | /* Prevent config work handler from accessing the device. */ |
894 | mutex_lock(&vblk->config_lock); | 895 | mutex_lock(&vblk->config_lock); |
@@ -903,11 +904,15 @@ static void virtblk_remove(struct virtio_device *vdev) | |||
903 | 904 | ||
904 | flush_work(&vblk->config_work); | 905 | flush_work(&vblk->config_work); |
905 | 906 | ||
907 | refc = atomic_read(&disk_to_dev(vblk->disk)->kobj.kref.refcount); | ||
906 | put_disk(vblk->disk); | 908 | put_disk(vblk->disk); |
907 | mempool_destroy(vblk->pool); | 909 | mempool_destroy(vblk->pool); |
908 | vdev->config->del_vqs(vdev); | 910 | vdev->config->del_vqs(vdev); |
909 | kfree(vblk); | 911 | kfree(vblk); |
910 | ida_simple_remove(&vd_index_ida, index); | 912 | |
913 | /* Only free device id if we don't have any users */ | ||
914 | if (refc == 1) | ||
915 | ida_simple_remove(&vd_index_ida, index); | ||
911 | } | 916 | } |
912 | 917 | ||
913 | #ifdef CONFIG_PM | 918 | #ifdef CONFIG_PM |
diff --git a/drivers/clk/mvebu/clk-cpu.c b/drivers/clk/mvebu/clk-cpu.c index ff004578a119..9dd2551a0a41 100644 --- a/drivers/clk/mvebu/clk-cpu.c +++ b/drivers/clk/mvebu/clk-cpu.c | |||
@@ -124,7 +124,7 @@ void __init of_cpu_clk_setup(struct device_node *node) | |||
124 | 124 | ||
125 | clks = kzalloc(ncpus * sizeof(*clks), GFP_KERNEL); | 125 | clks = kzalloc(ncpus * sizeof(*clks), GFP_KERNEL); |
126 | if (WARN_ON(!clks)) | 126 | if (WARN_ON(!clks)) |
127 | return; | 127 | goto clks_out; |
128 | 128 | ||
129 | for_each_node_by_type(dn, "cpu") { | 129 | for_each_node_by_type(dn, "cpu") { |
130 | struct clk_init_data init; | 130 | struct clk_init_data init; |
@@ -134,11 +134,11 @@ void __init of_cpu_clk_setup(struct device_node *node) | |||
134 | int cpu, err; | 134 | int cpu, err; |
135 | 135 | ||
136 | if (WARN_ON(!clk_name)) | 136 | if (WARN_ON(!clk_name)) |
137 | return; | 137 | goto bail_out; |
138 | 138 | ||
139 | err = of_property_read_u32(dn, "reg", &cpu); | 139 | err = of_property_read_u32(dn, "reg", &cpu); |
140 | if (WARN_ON(err)) | 140 | if (WARN_ON(err)) |
141 | return; | 141 | goto bail_out; |
142 | 142 | ||
143 | sprintf(clk_name, "cpu%d", cpu); | 143 | sprintf(clk_name, "cpu%d", cpu); |
144 | parent_clk = of_clk_get(node, 0); | 144 | parent_clk = of_clk_get(node, 0); |
@@ -167,6 +167,9 @@ void __init of_cpu_clk_setup(struct device_node *node) | |||
167 | return; | 167 | return; |
168 | bail_out: | 168 | bail_out: |
169 | kfree(clks); | 169 | kfree(clks); |
170 | while(ncpus--) | ||
171 | kfree(cpuclk[ncpus].clk_name); | ||
172 | clks_out: | ||
170 | kfree(cpuclk); | 173 | kfree(cpuclk); |
171 | } | 174 | } |
172 | 175 | ||
diff --git a/drivers/cpufreq/Kconfig.x86 b/drivers/cpufreq/Kconfig.x86 index 934854ae5eb4..7227cd734042 100644 --- a/drivers/cpufreq/Kconfig.x86 +++ b/drivers/cpufreq/Kconfig.x86 | |||
@@ -106,7 +106,7 @@ config X86_POWERNOW_K7_ACPI | |||
106 | config X86_POWERNOW_K8 | 106 | config X86_POWERNOW_K8 |
107 | tristate "AMD Opteron/Athlon64 PowerNow!" | 107 | tristate "AMD Opteron/Athlon64 PowerNow!" |
108 | select CPU_FREQ_TABLE | 108 | select CPU_FREQ_TABLE |
109 | depends on ACPI && ACPI_PROCESSOR | 109 | depends on ACPI && ACPI_PROCESSOR && X86_ACPI_CPUFREQ |
110 | help | 110 | help |
111 | This adds the CPUFreq driver for K8/early Opteron/Athlon64 processors. | 111 | This adds the CPUFreq driver for K8/early Opteron/Athlon64 processors. |
112 | Support for K10 and newer processors is now in acpi-cpufreq. | 112 | Support for K10 and newer processors is now in acpi-cpufreq. |
diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index 0d048f6a2b23..7b0d49d78c61 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c | |||
@@ -1030,4 +1030,11 @@ MODULE_PARM_DESC(acpi_pstate_strict, | |||
1030 | late_initcall(acpi_cpufreq_init); | 1030 | late_initcall(acpi_cpufreq_init); |
1031 | module_exit(acpi_cpufreq_exit); | 1031 | module_exit(acpi_cpufreq_exit); |
1032 | 1032 | ||
1033 | static const struct x86_cpu_id acpi_cpufreq_ids[] = { | ||
1034 | X86_FEATURE_MATCH(X86_FEATURE_ACPI), | ||
1035 | X86_FEATURE_MATCH(X86_FEATURE_HW_PSTATE), | ||
1036 | {} | ||
1037 | }; | ||
1038 | MODULE_DEVICE_TABLE(x86cpu, acpi_cpufreq_ids); | ||
1039 | |||
1033 | MODULE_ALIAS("acpi"); | 1040 | MODULE_ALIAS("acpi"); |
diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c index 52bf36d599f5..debc5a7c8db6 100644 --- a/drivers/cpufreq/cpufreq-cpu0.c +++ b/drivers/cpufreq/cpufreq-cpu0.c | |||
@@ -71,12 +71,15 @@ static int cpu0_set_target(struct cpufreq_policy *policy, | |||
71 | } | 71 | } |
72 | 72 | ||
73 | if (cpu_reg) { | 73 | if (cpu_reg) { |
74 | rcu_read_lock(); | ||
74 | opp = opp_find_freq_ceil(cpu_dev, &freq_Hz); | 75 | opp = opp_find_freq_ceil(cpu_dev, &freq_Hz); |
75 | if (IS_ERR(opp)) { | 76 | if (IS_ERR(opp)) { |
77 | rcu_read_unlock(); | ||
76 | pr_err("failed to find OPP for %ld\n", freq_Hz); | 78 | pr_err("failed to find OPP for %ld\n", freq_Hz); |
77 | return PTR_ERR(opp); | 79 | return PTR_ERR(opp); |
78 | } | 80 | } |
79 | volt = opp_get_voltage(opp); | 81 | volt = opp_get_voltage(opp); |
82 | rcu_read_unlock(); | ||
80 | tol = volt * voltage_tolerance / 100; | 83 | tol = volt * voltage_tolerance / 100; |
81 | volt_old = regulator_get_voltage(cpu_reg); | 84 | volt_old = regulator_get_voltage(cpu_reg); |
82 | } | 85 | } |
@@ -236,12 +239,14 @@ static int cpu0_cpufreq_driver_init(void) | |||
236 | */ | 239 | */ |
237 | for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) | 240 | for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) |
238 | ; | 241 | ; |
242 | rcu_read_lock(); | ||
239 | opp = opp_find_freq_exact(cpu_dev, | 243 | opp = opp_find_freq_exact(cpu_dev, |
240 | freq_table[0].frequency * 1000, true); | 244 | freq_table[0].frequency * 1000, true); |
241 | min_uV = opp_get_voltage(opp); | 245 | min_uV = opp_get_voltage(opp); |
242 | opp = opp_find_freq_exact(cpu_dev, | 246 | opp = opp_find_freq_exact(cpu_dev, |
243 | freq_table[i-1].frequency * 1000, true); | 247 | freq_table[i-1].frequency * 1000, true); |
244 | max_uV = opp_get_voltage(opp); | 248 | max_uV = opp_get_voltage(opp); |
249 | rcu_read_unlock(); | ||
245 | ret = regulator_set_voltage_time(cpu_reg, min_uV, max_uV); | 250 | ret = regulator_set_voltage_time(cpu_reg, min_uV, max_uV); |
246 | if (ret > 0) | 251 | if (ret > 0) |
247 | transition_latency += ret * 1000; | 252 | transition_latency += ret * 1000; |
diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c index 1f3417a8322d..97102b05843f 100644 --- a/drivers/cpufreq/omap-cpufreq.c +++ b/drivers/cpufreq/omap-cpufreq.c | |||
@@ -110,13 +110,16 @@ static int omap_target(struct cpufreq_policy *policy, | |||
110 | freq = ret; | 110 | freq = ret; |
111 | 111 | ||
112 | if (mpu_reg) { | 112 | if (mpu_reg) { |
113 | rcu_read_lock(); | ||
113 | opp = opp_find_freq_ceil(mpu_dev, &freq); | 114 | opp = opp_find_freq_ceil(mpu_dev, &freq); |
114 | if (IS_ERR(opp)) { | 115 | if (IS_ERR(opp)) { |
116 | rcu_read_unlock(); | ||
115 | dev_err(mpu_dev, "%s: unable to find MPU OPP for %d\n", | 117 | dev_err(mpu_dev, "%s: unable to find MPU OPP for %d\n", |
116 | __func__, freqs.new); | 118 | __func__, freqs.new); |
117 | return -EINVAL; | 119 | return -EINVAL; |
118 | } | 120 | } |
119 | volt = opp_get_voltage(opp); | 121 | volt = opp_get_voltage(opp); |
122 | rcu_read_unlock(); | ||
120 | tol = volt * OPP_TOLERANCE / 100; | 123 | tol = volt * OPP_TOLERANCE / 100; |
121 | volt_old = regulator_get_voltage(mpu_reg); | 124 | volt_old = regulator_get_voltage(mpu_reg); |
122 | } | 125 | } |
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index fb4a7dd57f94..e1f6860e069c 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c | |||
@@ -69,24 +69,15 @@ int cpuidle_play_dead(void) | |||
69 | { | 69 | { |
70 | struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices); | 70 | struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices); |
71 | struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev); | 71 | struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev); |
72 | int i, dead_state = -1; | 72 | int i; |
73 | int power_usage = INT_MAX; | ||
74 | 73 | ||
75 | if (!drv) | 74 | if (!drv) |
76 | return -ENODEV; | 75 | return -ENODEV; |
77 | 76 | ||
78 | /* Find lowest-power state that supports long-term idle */ | 77 | /* Find lowest-power state that supports long-term idle */ |
79 | for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) { | 78 | for (i = drv->state_count - 1; i >= CPUIDLE_DRIVER_STATE_START; i--) |
80 | struct cpuidle_state *s = &drv->states[i]; | 79 | if (drv->states[i].enter_dead) |
81 | 80 | return drv->states[i].enter_dead(dev, i); | |
82 | if (s->power_usage < power_usage && s->enter_dead) { | ||
83 | power_usage = s->power_usage; | ||
84 | dead_state = i; | ||
85 | } | ||
86 | } | ||
87 | |||
88 | if (dead_state != -1) | ||
89 | return drv->states[dead_state].enter_dead(dev, dead_state); | ||
90 | 81 | ||
91 | return -ENODEV; | 82 | return -ENODEV; |
92 | } | 83 | } |
diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c index c2b281afe0ed..422c7b69ba7c 100644 --- a/drivers/cpuidle/driver.c +++ b/drivers/cpuidle/driver.c | |||
@@ -19,34 +19,9 @@ DEFINE_SPINLOCK(cpuidle_driver_lock); | |||
19 | static void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu); | 19 | static void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu); |
20 | static struct cpuidle_driver * __cpuidle_get_cpu_driver(int cpu); | 20 | static struct cpuidle_driver * __cpuidle_get_cpu_driver(int cpu); |
21 | 21 | ||
22 | static void set_power_states(struct cpuidle_driver *drv) | ||
23 | { | ||
24 | int i; | ||
25 | |||
26 | /* | ||
27 | * cpuidle driver should set the drv->power_specified bit | ||
28 | * before registering if the driver provides | ||
29 | * power_usage numbers. | ||
30 | * | ||
31 | * If power_specified is not set, | ||
32 | * we fill in power_usage with decreasing values as the | ||
33 | * cpuidle code has an implicit assumption that state Cn | ||
34 | * uses less power than C(n-1). | ||
35 | * | ||
36 | * With CONFIG_ARCH_HAS_CPU_RELAX, C0 is already assigned | ||
37 | * an power value of -1. So we use -2, -3, etc, for other | ||
38 | * c-states. | ||
39 | */ | ||
40 | for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) | ||
41 | drv->states[i].power_usage = -1 - i; | ||
42 | } | ||
43 | |||
44 | static void __cpuidle_driver_init(struct cpuidle_driver *drv) | 22 | static void __cpuidle_driver_init(struct cpuidle_driver *drv) |
45 | { | 23 | { |
46 | drv->refcnt = 0; | 24 | drv->refcnt = 0; |
47 | |||
48 | if (!drv->power_specified) | ||
49 | set_power_states(drv); | ||
50 | } | 25 | } |
51 | 26 | ||
52 | static int __cpuidle_register_driver(struct cpuidle_driver *drv, int cpu) | 27 | static int __cpuidle_register_driver(struct cpuidle_driver *drv, int cpu) |
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index 20ea33afdda1..fe343a06b7da 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c | |||
@@ -312,7 +312,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) | |||
312 | { | 312 | { |
313 | struct menu_device *data = &__get_cpu_var(menu_devices); | 313 | struct menu_device *data = &__get_cpu_var(menu_devices); |
314 | int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY); | 314 | int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY); |
315 | int power_usage = INT_MAX; | ||
316 | int i; | 315 | int i; |
317 | int multiplier; | 316 | int multiplier; |
318 | struct timespec t; | 317 | struct timespec t; |
@@ -383,11 +382,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) | |||
383 | if (s->exit_latency * multiplier > data->predicted_us) | 382 | if (s->exit_latency * multiplier > data->predicted_us) |
384 | continue; | 383 | continue; |
385 | 384 | ||
386 | if (s->power_usage < power_usage) { | 385 | data->last_state_idx = i; |
387 | power_usage = s->power_usage; | 386 | data->exit_us = s->exit_latency; |
388 | data->last_state_idx = i; | ||
389 | data->exit_us = s->exit_latency; | ||
390 | } | ||
391 | } | 387 | } |
392 | 388 | ||
393 | /* not deepest C-state chosen for low predicted residency */ | 389 | /* not deepest C-state chosen for low predicted residency */ |
diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index 340942946106..428754af6236 100644 --- a/drivers/cpuidle/sysfs.c +++ b/drivers/cpuidle/sysfs.c | |||
@@ -374,7 +374,7 @@ static int cpuidle_add_state_sysfs(struct cpuidle_device *device) | |||
374 | struct cpuidle_driver *drv = cpuidle_get_cpu_driver(device); | 374 | struct cpuidle_driver *drv = cpuidle_get_cpu_driver(device); |
375 | 375 | ||
376 | /* state statistics */ | 376 | /* state statistics */ |
377 | for (i = 0; i < drv->state_count; i++) { | 377 | for (i = 0; i < device->state_count; i++) { |
378 | kobj = kzalloc(sizeof(struct cpuidle_state_kobj), GFP_KERNEL); | 378 | kobj = kzalloc(sizeof(struct cpuidle_state_kobj), GFP_KERNEL); |
379 | if (!kobj) | 379 | if (!kobj) |
380 | goto error_state; | 380 | goto error_state; |
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 53766f39aadd..3b367973a802 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c | |||
@@ -994,6 +994,11 @@ module_exit(devfreq_exit); | |||
994 | * @freq: The frequency given to target function | 994 | * @freq: The frequency given to target function |
995 | * @flags: Flags handed from devfreq framework. | 995 | * @flags: Flags handed from devfreq framework. |
996 | * | 996 | * |
997 | * Locking: This function must be called under rcu_read_lock(). opp is a rcu | ||
998 | * protected pointer. The reason for the same is that the opp pointer which is | ||
999 | * returned will remain valid for use with opp_get_{voltage, freq} only while | ||
1000 | * under the locked area. The pointer returned must be used prior to unlocking | ||
1001 | * with rcu_read_unlock() to maintain the integrity of the pointer. | ||
997 | */ | 1002 | */ |
998 | struct opp *devfreq_recommended_opp(struct device *dev, unsigned long *freq, | 1003 | struct opp *devfreq_recommended_opp(struct device *dev, unsigned long *freq, |
999 | u32 flags) | 1004 | u32 flags) |
diff --git a/drivers/devfreq/exynos4_bus.c b/drivers/devfreq/exynos4_bus.c index 80c745e83082..46d94e9e95b5 100644 --- a/drivers/devfreq/exynos4_bus.c +++ b/drivers/devfreq/exynos4_bus.c | |||
@@ -73,6 +73,16 @@ enum busclk_level_idx { | |||
73 | #define EX4210_LV_NUM (LV_2 + 1) | 73 | #define EX4210_LV_NUM (LV_2 + 1) |
74 | #define EX4x12_LV_NUM (LV_4 + 1) | 74 | #define EX4x12_LV_NUM (LV_4 + 1) |
75 | 75 | ||
76 | /** | ||
77 | * struct busfreq_opp_info - opp information for bus | ||
78 | * @rate: Frequency in hertz | ||
79 | * @volt: Voltage in microvolts corresponding to this OPP | ||
80 | */ | ||
81 | struct busfreq_opp_info { | ||
82 | unsigned long rate; | ||
83 | unsigned long volt; | ||
84 | }; | ||
85 | |||
76 | struct busfreq_data { | 86 | struct busfreq_data { |
77 | enum exynos4_busf_type type; | 87 | enum exynos4_busf_type type; |
78 | struct device *dev; | 88 | struct device *dev; |
@@ -80,7 +90,7 @@ struct busfreq_data { | |||
80 | bool disabled; | 90 | bool disabled; |
81 | struct regulator *vdd_int; | 91 | struct regulator *vdd_int; |
82 | struct regulator *vdd_mif; /* Exynos4412/4212 only */ | 92 | struct regulator *vdd_mif; /* Exynos4412/4212 only */ |
83 | struct opp *curr_opp; | 93 | struct busfreq_opp_info curr_oppinfo; |
84 | struct exynos4_ppmu dmc[2]; | 94 | struct exynos4_ppmu dmc[2]; |
85 | 95 | ||
86 | struct notifier_block pm_notifier; | 96 | struct notifier_block pm_notifier; |
@@ -296,13 +306,14 @@ static unsigned int exynos4x12_clkdiv_sclkip[][3] = { | |||
296 | }; | 306 | }; |
297 | 307 | ||
298 | 308 | ||
299 | static int exynos4210_set_busclk(struct busfreq_data *data, struct opp *opp) | 309 | static int exynos4210_set_busclk(struct busfreq_data *data, |
310 | struct busfreq_opp_info *oppi) | ||
300 | { | 311 | { |
301 | unsigned int index; | 312 | unsigned int index; |
302 | unsigned int tmp; | 313 | unsigned int tmp; |
303 | 314 | ||
304 | for (index = LV_0; index < EX4210_LV_NUM; index++) | 315 | for (index = LV_0; index < EX4210_LV_NUM; index++) |
305 | if (opp_get_freq(opp) == exynos4210_busclk_table[index].clk) | 316 | if (oppi->rate == exynos4210_busclk_table[index].clk) |
306 | break; | 317 | break; |
307 | 318 | ||
308 | if (index == EX4210_LV_NUM) | 319 | if (index == EX4210_LV_NUM) |
@@ -361,13 +372,14 @@ static int exynos4210_set_busclk(struct busfreq_data *data, struct opp *opp) | |||
361 | return 0; | 372 | return 0; |
362 | } | 373 | } |
363 | 374 | ||
364 | static int exynos4x12_set_busclk(struct busfreq_data *data, struct opp *opp) | 375 | static int exynos4x12_set_busclk(struct busfreq_data *data, |
376 | struct busfreq_opp_info *oppi) | ||
365 | { | 377 | { |
366 | unsigned int index; | 378 | unsigned int index; |
367 | unsigned int tmp; | 379 | unsigned int tmp; |
368 | 380 | ||
369 | for (index = LV_0; index < EX4x12_LV_NUM; index++) | 381 | for (index = LV_0; index < EX4x12_LV_NUM; index++) |
370 | if (opp_get_freq(opp) == exynos4x12_mifclk_table[index].clk) | 382 | if (oppi->rate == exynos4x12_mifclk_table[index].clk) |
371 | break; | 383 | break; |
372 | 384 | ||
373 | if (index == EX4x12_LV_NUM) | 385 | if (index == EX4x12_LV_NUM) |
@@ -576,11 +588,12 @@ static int exynos4x12_get_intspec(unsigned long mifclk) | |||
576 | return -EINVAL; | 588 | return -EINVAL; |
577 | } | 589 | } |
578 | 590 | ||
579 | static int exynos4_bus_setvolt(struct busfreq_data *data, struct opp *opp, | 591 | static int exynos4_bus_setvolt(struct busfreq_data *data, |
580 | struct opp *oldopp) | 592 | struct busfreq_opp_info *oppi, |
593 | struct busfreq_opp_info *oldoppi) | ||
581 | { | 594 | { |
582 | int err = 0, tmp; | 595 | int err = 0, tmp; |
583 | unsigned long volt = opp_get_voltage(opp); | 596 | unsigned long volt = oppi->volt; |
584 | 597 | ||
585 | switch (data->type) { | 598 | switch (data->type) { |
586 | case TYPE_BUSF_EXYNOS4210: | 599 | case TYPE_BUSF_EXYNOS4210: |
@@ -595,11 +608,11 @@ static int exynos4_bus_setvolt(struct busfreq_data *data, struct opp *opp, | |||
595 | if (err) | 608 | if (err) |
596 | break; | 609 | break; |
597 | 610 | ||
598 | tmp = exynos4x12_get_intspec(opp_get_freq(opp)); | 611 | tmp = exynos4x12_get_intspec(oppi->rate); |
599 | if (tmp < 0) { | 612 | if (tmp < 0) { |
600 | err = tmp; | 613 | err = tmp; |
601 | regulator_set_voltage(data->vdd_mif, | 614 | regulator_set_voltage(data->vdd_mif, |
602 | opp_get_voltage(oldopp), | 615 | oldoppi->volt, |
603 | MAX_SAFEVOLT); | 616 | MAX_SAFEVOLT); |
604 | break; | 617 | break; |
605 | } | 618 | } |
@@ -609,7 +622,7 @@ static int exynos4_bus_setvolt(struct busfreq_data *data, struct opp *opp, | |||
609 | /* Try to recover */ | 622 | /* Try to recover */ |
610 | if (err) | 623 | if (err) |
611 | regulator_set_voltage(data->vdd_mif, | 624 | regulator_set_voltage(data->vdd_mif, |
612 | opp_get_voltage(oldopp), | 625 | oldoppi->volt, |
613 | MAX_SAFEVOLT); | 626 | MAX_SAFEVOLT); |
614 | break; | 627 | break; |
615 | default: | 628 | default: |
@@ -626,17 +639,26 @@ static int exynos4_bus_target(struct device *dev, unsigned long *_freq, | |||
626 | struct platform_device *pdev = container_of(dev, struct platform_device, | 639 | struct platform_device *pdev = container_of(dev, struct platform_device, |
627 | dev); | 640 | dev); |
628 | struct busfreq_data *data = platform_get_drvdata(pdev); | 641 | struct busfreq_data *data = platform_get_drvdata(pdev); |
629 | struct opp *opp = devfreq_recommended_opp(dev, _freq, flags); | 642 | struct opp *opp; |
630 | unsigned long freq = opp_get_freq(opp); | 643 | unsigned long freq; |
631 | unsigned long old_freq = opp_get_freq(data->curr_opp); | 644 | unsigned long old_freq = data->curr_oppinfo.rate; |
645 | struct busfreq_opp_info new_oppinfo; | ||
632 | 646 | ||
633 | if (IS_ERR(opp)) | 647 | rcu_read_lock(); |
648 | opp = devfreq_recommended_opp(dev, _freq, flags); | ||
649 | if (IS_ERR(opp)) { | ||
650 | rcu_read_unlock(); | ||
634 | return PTR_ERR(opp); | 651 | return PTR_ERR(opp); |
652 | } | ||
653 | new_oppinfo.rate = opp_get_freq(opp); | ||
654 | new_oppinfo.volt = opp_get_voltage(opp); | ||
655 | rcu_read_unlock(); | ||
656 | freq = new_oppinfo.rate; | ||
635 | 657 | ||
636 | if (old_freq == freq) | 658 | if (old_freq == freq) |
637 | return 0; | 659 | return 0; |
638 | 660 | ||
639 | dev_dbg(dev, "targetting %lukHz %luuV\n", freq, opp_get_voltage(opp)); | 661 | dev_dbg(dev, "targetting %lukHz %luuV\n", freq, new_oppinfo.volt); |
640 | 662 | ||
641 | mutex_lock(&data->lock); | 663 | mutex_lock(&data->lock); |
642 | 664 | ||
@@ -644,17 +666,18 @@ static int exynos4_bus_target(struct device *dev, unsigned long *_freq, | |||
644 | goto out; | 666 | goto out; |
645 | 667 | ||
646 | if (old_freq < freq) | 668 | if (old_freq < freq) |
647 | err = exynos4_bus_setvolt(data, opp, data->curr_opp); | 669 | err = exynos4_bus_setvolt(data, &new_oppinfo, |
670 | &data->curr_oppinfo); | ||
648 | if (err) | 671 | if (err) |
649 | goto out; | 672 | goto out; |
650 | 673 | ||
651 | if (old_freq != freq) { | 674 | if (old_freq != freq) { |
652 | switch (data->type) { | 675 | switch (data->type) { |
653 | case TYPE_BUSF_EXYNOS4210: | 676 | case TYPE_BUSF_EXYNOS4210: |
654 | err = exynos4210_set_busclk(data, opp); | 677 | err = exynos4210_set_busclk(data, &new_oppinfo); |
655 | break; | 678 | break; |
656 | case TYPE_BUSF_EXYNOS4x12: | 679 | case TYPE_BUSF_EXYNOS4x12: |
657 | err = exynos4x12_set_busclk(data, opp); | 680 | err = exynos4x12_set_busclk(data, &new_oppinfo); |
658 | break; | 681 | break; |
659 | default: | 682 | default: |
660 | err = -EINVAL; | 683 | err = -EINVAL; |
@@ -664,11 +687,12 @@ static int exynos4_bus_target(struct device *dev, unsigned long *_freq, | |||
664 | goto out; | 687 | goto out; |
665 | 688 | ||
666 | if (old_freq > freq) | 689 | if (old_freq > freq) |
667 | err = exynos4_bus_setvolt(data, opp, data->curr_opp); | 690 | err = exynos4_bus_setvolt(data, &new_oppinfo, |
691 | &data->curr_oppinfo); | ||
668 | if (err) | 692 | if (err) |
669 | goto out; | 693 | goto out; |
670 | 694 | ||
671 | data->curr_opp = opp; | 695 | data->curr_oppinfo = new_oppinfo; |
672 | out: | 696 | out: |
673 | mutex_unlock(&data->lock); | 697 | mutex_unlock(&data->lock); |
674 | return err; | 698 | return err; |
@@ -702,7 +726,7 @@ static int exynos4_bus_get_dev_status(struct device *dev, | |||
702 | 726 | ||
703 | exynos4_read_ppmu(data); | 727 | exynos4_read_ppmu(data); |
704 | busier_dmc = exynos4_get_busier_dmc(data); | 728 | busier_dmc = exynos4_get_busier_dmc(data); |
705 | stat->current_frequency = opp_get_freq(data->curr_opp); | 729 | stat->current_frequency = data->curr_oppinfo.rate; |
706 | 730 | ||
707 | if (busier_dmc) | 731 | if (busier_dmc) |
708 | addr = S5P_VA_DMC1; | 732 | addr = S5P_VA_DMC1; |
@@ -933,6 +957,7 @@ static int exynos4_busfreq_pm_notifier_event(struct notifier_block *this, | |||
933 | struct busfreq_data *data = container_of(this, struct busfreq_data, | 957 | struct busfreq_data *data = container_of(this, struct busfreq_data, |
934 | pm_notifier); | 958 | pm_notifier); |
935 | struct opp *opp; | 959 | struct opp *opp; |
960 | struct busfreq_opp_info new_oppinfo; | ||
936 | unsigned long maxfreq = ULONG_MAX; | 961 | unsigned long maxfreq = ULONG_MAX; |
937 | int err = 0; | 962 | int err = 0; |
938 | 963 | ||
@@ -943,18 +968,29 @@ static int exynos4_busfreq_pm_notifier_event(struct notifier_block *this, | |||
943 | 968 | ||
944 | data->disabled = true; | 969 | data->disabled = true; |
945 | 970 | ||
971 | rcu_read_lock(); | ||
946 | opp = opp_find_freq_floor(data->dev, &maxfreq); | 972 | opp = opp_find_freq_floor(data->dev, &maxfreq); |
973 | if (IS_ERR(opp)) { | ||
974 | rcu_read_unlock(); | ||
975 | dev_err(data->dev, "%s: unable to find a min freq\n", | ||
976 | __func__); | ||
977 | return PTR_ERR(opp); | ||
978 | } | ||
979 | new_oppinfo.rate = opp_get_freq(opp); | ||
980 | new_oppinfo.volt = opp_get_voltage(opp); | ||
981 | rcu_read_unlock(); | ||
947 | 982 | ||
948 | err = exynos4_bus_setvolt(data, opp, data->curr_opp); | 983 | err = exynos4_bus_setvolt(data, &new_oppinfo, |
984 | &data->curr_oppinfo); | ||
949 | if (err) | 985 | if (err) |
950 | goto unlock; | 986 | goto unlock; |
951 | 987 | ||
952 | switch (data->type) { | 988 | switch (data->type) { |
953 | case TYPE_BUSF_EXYNOS4210: | 989 | case TYPE_BUSF_EXYNOS4210: |
954 | err = exynos4210_set_busclk(data, opp); | 990 | err = exynos4210_set_busclk(data, &new_oppinfo); |
955 | break; | 991 | break; |
956 | case TYPE_BUSF_EXYNOS4x12: | 992 | case TYPE_BUSF_EXYNOS4x12: |
957 | err = exynos4x12_set_busclk(data, opp); | 993 | err = exynos4x12_set_busclk(data, &new_oppinfo); |
958 | break; | 994 | break; |
959 | default: | 995 | default: |
960 | err = -EINVAL; | 996 | err = -EINVAL; |
@@ -962,7 +998,7 @@ static int exynos4_busfreq_pm_notifier_event(struct notifier_block *this, | |||
962 | if (err) | 998 | if (err) |
963 | goto unlock; | 999 | goto unlock; |
964 | 1000 | ||
965 | data->curr_opp = opp; | 1001 | data->curr_oppinfo = new_oppinfo; |
966 | unlock: | 1002 | unlock: |
967 | mutex_unlock(&data->lock); | 1003 | mutex_unlock(&data->lock); |
968 | if (err) | 1004 | if (err) |
@@ -1027,13 +1063,17 @@ static int exynos4_busfreq_probe(struct platform_device *pdev) | |||
1027 | } | 1063 | } |
1028 | } | 1064 | } |
1029 | 1065 | ||
1066 | rcu_read_lock(); | ||
1030 | opp = opp_find_freq_floor(dev, &exynos4_devfreq_profile.initial_freq); | 1067 | opp = opp_find_freq_floor(dev, &exynos4_devfreq_profile.initial_freq); |
1031 | if (IS_ERR(opp)) { | 1068 | if (IS_ERR(opp)) { |
1069 | rcu_read_unlock(); | ||
1032 | dev_err(dev, "Invalid initial frequency %lu kHz.\n", | 1070 | dev_err(dev, "Invalid initial frequency %lu kHz.\n", |
1033 | exynos4_devfreq_profile.initial_freq); | 1071 | exynos4_devfreq_profile.initial_freq); |
1034 | return PTR_ERR(opp); | 1072 | return PTR_ERR(opp); |
1035 | } | 1073 | } |
1036 | data->curr_opp = opp; | 1074 | data->curr_oppinfo.rate = opp_get_freq(opp); |
1075 | data->curr_oppinfo.volt = opp_get_voltage(opp); | ||
1076 | rcu_read_unlock(); | ||
1037 | 1077 | ||
1038 | platform_set_drvdata(pdev, data); | 1078 | platform_set_drvdata(pdev, data); |
1039 | 1079 | ||
diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c index dbf0e6f8de8a..a7dcf78b1ff8 100644 --- a/drivers/dma/imx-dma.c +++ b/drivers/dma/imx-dma.c | |||
@@ -684,9 +684,8 @@ static int imxdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, | |||
684 | break; | 684 | break; |
685 | } | 685 | } |
686 | 686 | ||
687 | imxdmac->hw_chaining = 1; | 687 | imxdmac->hw_chaining = 0; |
688 | if (!imxdma_hw_chain(imxdmac)) | 688 | |
689 | return -EINVAL; | ||
690 | imxdmac->ccr_from_device = (mode | IMX_DMA_TYPE_FIFO) | | 689 | imxdmac->ccr_from_device = (mode | IMX_DMA_TYPE_FIFO) | |
691 | ((IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR) << 2) | | 690 | ((IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR) << 2) | |
692 | CCR_REN; | 691 | CCR_REN; |
diff --git a/drivers/dma/ioat/dma_v3.c b/drivers/dma/ioat/dma_v3.c index e5fc944de1f0..3e9d66920eb3 100644 --- a/drivers/dma/ioat/dma_v3.c +++ b/drivers/dma/ioat/dma_v3.c | |||
@@ -951,7 +951,7 @@ static int ioat_xor_val_self_test(struct ioatdma_device *device) | |||
951 | goto free_resources; | 951 | goto free_resources; |
952 | } | 952 | } |
953 | } | 953 | } |
954 | dma_sync_single_for_device(dev, dest_dma, PAGE_SIZE, DMA_TO_DEVICE); | 954 | dma_sync_single_for_device(dev, dest_dma, PAGE_SIZE, DMA_FROM_DEVICE); |
955 | 955 | ||
956 | /* skip validate if the capability is not present */ | 956 | /* skip validate if the capability is not present */ |
957 | if (!dma_has_cap(DMA_XOR_VAL, dma_chan->device->cap_mask)) | 957 | if (!dma_has_cap(DMA_XOR_VAL, dma_chan->device->cap_mask)) |
diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c index c39e61bc8172..3cad856fe67f 100644 --- a/drivers/dma/tegra20-apb-dma.c +++ b/drivers/dma/tegra20-apb-dma.c | |||
@@ -266,6 +266,7 @@ static struct tegra_dma_desc *tegra_dma_desc_get( | |||
266 | if (async_tx_test_ack(&dma_desc->txd)) { | 266 | if (async_tx_test_ack(&dma_desc->txd)) { |
267 | list_del(&dma_desc->node); | 267 | list_del(&dma_desc->node); |
268 | spin_unlock_irqrestore(&tdc->lock, flags); | 268 | spin_unlock_irqrestore(&tdc->lock, flags); |
269 | dma_desc->txd.flags = 0; | ||
269 | return dma_desc; | 270 | return dma_desc; |
270 | } | 271 | } |
271 | } | 272 | } |
@@ -1050,7 +1051,9 @@ struct dma_async_tx_descriptor *tegra_dma_prep_dma_cyclic( | |||
1050 | TEGRA_APBDMA_AHBSEQ_WRAP_SHIFT; | 1051 | TEGRA_APBDMA_AHBSEQ_WRAP_SHIFT; |
1051 | ahb_seq |= TEGRA_APBDMA_AHBSEQ_BUS_WIDTH_32; | 1052 | ahb_seq |= TEGRA_APBDMA_AHBSEQ_BUS_WIDTH_32; |
1052 | 1053 | ||
1053 | csr |= TEGRA_APBDMA_CSR_FLOW | TEGRA_APBDMA_CSR_IE_EOC; | 1054 | csr |= TEGRA_APBDMA_CSR_FLOW; |
1055 | if (flags & DMA_PREP_INTERRUPT) | ||
1056 | csr |= TEGRA_APBDMA_CSR_IE_EOC; | ||
1054 | csr |= tdc->dma_sconfig.slave_id << TEGRA_APBDMA_CSR_REQ_SEL_SHIFT; | 1057 | csr |= tdc->dma_sconfig.slave_id << TEGRA_APBDMA_CSR_REQ_SEL_SHIFT; |
1055 | 1058 | ||
1056 | apb_seq |= TEGRA_APBDMA_APBSEQ_WRAP_WORD_1; | 1059 | apb_seq |= TEGRA_APBDMA_APBSEQ_WRAP_WORD_1; |
@@ -1095,7 +1098,8 @@ struct dma_async_tx_descriptor *tegra_dma_prep_dma_cyclic( | |||
1095 | mem += len; | 1098 | mem += len; |
1096 | } | 1099 | } |
1097 | sg_req->last_sg = true; | 1100 | sg_req->last_sg = true; |
1098 | dma_desc->txd.flags = 0; | 1101 | if (flags & DMA_CTRL_ACK) |
1102 | dma_desc->txd.flags = DMA_CTRL_ACK; | ||
1099 | 1103 | ||
1100 | /* | 1104 | /* |
1101 | * Make sure that mode should not be conflicting with currently | 1105 | * Make sure that mode should not be conflicting with currently |
diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 7d9bd94be8d2..6819d63cb167 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c | |||
@@ -547,7 +547,6 @@ static int mvebu_gpio_probe(struct platform_device *pdev) | |||
547 | mvchip->membase = devm_request_and_ioremap(&pdev->dev, res); | 547 | mvchip->membase = devm_request_and_ioremap(&pdev->dev, res); |
548 | if (! mvchip->membase) { | 548 | if (! mvchip->membase) { |
549 | dev_err(&pdev->dev, "Cannot ioremap\n"); | 549 | dev_err(&pdev->dev, "Cannot ioremap\n"); |
550 | kfree(mvchip->chip.label); | ||
551 | return -ENOMEM; | 550 | return -ENOMEM; |
552 | } | 551 | } |
553 | 552 | ||
@@ -557,14 +556,12 @@ static int mvebu_gpio_probe(struct platform_device *pdev) | |||
557 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); | 556 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
558 | if (! res) { | 557 | if (! res) { |
559 | dev_err(&pdev->dev, "Cannot get memory resource\n"); | 558 | dev_err(&pdev->dev, "Cannot get memory resource\n"); |
560 | kfree(mvchip->chip.label); | ||
561 | return -ENODEV; | 559 | return -ENODEV; |
562 | } | 560 | } |
563 | 561 | ||
564 | mvchip->percpu_membase = devm_request_and_ioremap(&pdev->dev, res); | 562 | mvchip->percpu_membase = devm_request_and_ioremap(&pdev->dev, res); |
565 | if (! mvchip->percpu_membase) { | 563 | if (! mvchip->percpu_membase) { |
566 | dev_err(&pdev->dev, "Cannot ioremap\n"); | 564 | dev_err(&pdev->dev, "Cannot ioremap\n"); |
567 | kfree(mvchip->chip.label); | ||
568 | return -ENOMEM; | 565 | return -ENOMEM; |
569 | } | 566 | } |
570 | } | 567 | } |
@@ -625,7 +622,6 @@ static int mvebu_gpio_probe(struct platform_device *pdev) | |||
625 | mvchip->irqbase = irq_alloc_descs(-1, 0, ngpios, -1); | 622 | mvchip->irqbase = irq_alloc_descs(-1, 0, ngpios, -1); |
626 | if (mvchip->irqbase < 0) { | 623 | if (mvchip->irqbase < 0) { |
627 | dev_err(&pdev->dev, "no irqs\n"); | 624 | dev_err(&pdev->dev, "no irqs\n"); |
628 | kfree(mvchip->chip.label); | ||
629 | return -ENOMEM; | 625 | return -ENOMEM; |
630 | } | 626 | } |
631 | 627 | ||
@@ -633,7 +629,6 @@ static int mvebu_gpio_probe(struct platform_device *pdev) | |||
633 | mvchip->membase, handle_level_irq); | 629 | mvchip->membase, handle_level_irq); |
634 | if (! gc) { | 630 | if (! gc) { |
635 | dev_err(&pdev->dev, "Cannot allocate generic irq_chip\n"); | 631 | dev_err(&pdev->dev, "Cannot allocate generic irq_chip\n"); |
636 | kfree(mvchip->chip.label); | ||
637 | return -ENOMEM; | 632 | return -ENOMEM; |
638 | } | 633 | } |
639 | 634 | ||
@@ -668,7 +663,6 @@ static int mvebu_gpio_probe(struct platform_device *pdev) | |||
668 | irq_remove_generic_chip(gc, IRQ_MSK(ngpios), IRQ_NOREQUEST, | 663 | irq_remove_generic_chip(gc, IRQ_MSK(ngpios), IRQ_NOREQUEST, |
669 | IRQ_LEVEL | IRQ_NOPROBE); | 664 | IRQ_LEVEL | IRQ_NOPROBE); |
670 | kfree(gc); | 665 | kfree(gc); |
671 | kfree(mvchip->chip.label); | ||
672 | return -ENODEV; | 666 | return -ENODEV; |
673 | } | 667 | } |
674 | 668 | ||
diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c index 01f7fe955590..76be7eed79de 100644 --- a/drivers/gpio/gpio-samsung.c +++ b/drivers/gpio/gpio-samsung.c | |||
@@ -32,7 +32,6 @@ | |||
32 | 32 | ||
33 | #include <mach/hardware.h> | 33 | #include <mach/hardware.h> |
34 | #include <mach/map.h> | 34 | #include <mach/map.h> |
35 | #include <mach/regs-clock.h> | ||
36 | #include <mach/regs-gpio.h> | 35 | #include <mach/regs-gpio.h> |
37 | 36 | ||
38 | #include <plat/cpu.h> | 37 | #include <plat/cpu.h> |
@@ -446,7 +445,7 @@ static struct samsung_gpio_cfg s3c24xx_gpiocfg_banka = { | |||
446 | }; | 445 | }; |
447 | #endif | 446 | #endif |
448 | 447 | ||
449 | #if defined(CONFIG_ARCH_EXYNOS4) || defined(CONFIG_ARCH_EXYNOS5) | 448 | #if defined(CONFIG_ARCH_EXYNOS4) || defined(CONFIG_SOC_EXYNOS5250) |
450 | static struct samsung_gpio_cfg exynos_gpio_cfg = { | 449 | static struct samsung_gpio_cfg exynos_gpio_cfg = { |
451 | .set_pull = exynos_gpio_setpull, | 450 | .set_pull = exynos_gpio_setpull, |
452 | .get_pull = exynos_gpio_getpull, | 451 | .get_pull = exynos_gpio_getpull, |
@@ -2446,7 +2445,7 @@ static struct samsung_gpio_chip exynos4_gpios_3[] = { | |||
2446 | }; | 2445 | }; |
2447 | #endif | 2446 | #endif |
2448 | 2447 | ||
2449 | #ifdef CONFIG_ARCH_EXYNOS5 | 2448 | #ifdef CONFIG_SOC_EXYNOS5250 |
2450 | static struct samsung_gpio_chip exynos5_gpios_1[] = { | 2449 | static struct samsung_gpio_chip exynos5_gpios_1[] = { |
2451 | { | 2450 | { |
2452 | .chip = { | 2451 | .chip = { |
@@ -2614,7 +2613,7 @@ static struct samsung_gpio_chip exynos5_gpios_1[] = { | |||
2614 | }; | 2613 | }; |
2615 | #endif | 2614 | #endif |
2616 | 2615 | ||
2617 | #ifdef CONFIG_ARCH_EXYNOS5 | 2616 | #ifdef CONFIG_SOC_EXYNOS5250 |
2618 | static struct samsung_gpio_chip exynos5_gpios_2[] = { | 2617 | static struct samsung_gpio_chip exynos5_gpios_2[] = { |
2619 | { | 2618 | { |
2620 | .chip = { | 2619 | .chip = { |
@@ -2675,7 +2674,7 @@ static struct samsung_gpio_chip exynos5_gpios_2[] = { | |||
2675 | }; | 2674 | }; |
2676 | #endif | 2675 | #endif |
2677 | 2676 | ||
2678 | #ifdef CONFIG_ARCH_EXYNOS5 | 2677 | #ifdef CONFIG_SOC_EXYNOS5250 |
2679 | static struct samsung_gpio_chip exynos5_gpios_3[] = { | 2678 | static struct samsung_gpio_chip exynos5_gpios_3[] = { |
2680 | { | 2679 | { |
2681 | .chip = { | 2680 | .chip = { |
@@ -2711,7 +2710,7 @@ static struct samsung_gpio_chip exynos5_gpios_3[] = { | |||
2711 | }; | 2710 | }; |
2712 | #endif | 2711 | #endif |
2713 | 2712 | ||
2714 | #ifdef CONFIG_ARCH_EXYNOS5 | 2713 | #ifdef CONFIG_SOC_EXYNOS5250 |
2715 | static struct samsung_gpio_chip exynos5_gpios_4[] = { | 2714 | static struct samsung_gpio_chip exynos5_gpios_4[] = { |
2716 | { | 2715 | { |
2717 | .chip = { | 2716 | .chip = { |
@@ -3010,7 +3009,7 @@ static __init int samsung_gpiolib_init(void) | |||
3010 | int i, nr_chips; | 3009 | int i, nr_chips; |
3011 | int group = 0; | 3010 | int group = 0; |
3012 | 3011 | ||
3013 | #ifdef CONFIG_PINCTRL_SAMSUNG | 3012 | #if defined(CONFIG_PINCTRL_EXYNOS) || defined(CONFIG_PINCTRL_EXYNOS5440) |
3014 | /* | 3013 | /* |
3015 | * This gpio driver includes support for device tree support and there | 3014 | * This gpio driver includes support for device tree support and there |
3016 | * are platforms using it. In order to maintain compatibility with those | 3015 | * are platforms using it. In order to maintain compatibility with those |
@@ -3026,6 +3025,7 @@ static __init int samsung_gpiolib_init(void) | |||
3026 | static const struct of_device_id exynos_pinctrl_ids[] = { | 3025 | static const struct of_device_id exynos_pinctrl_ids[] = { |
3027 | { .compatible = "samsung,pinctrl-exynos4210", }, | 3026 | { .compatible = "samsung,pinctrl-exynos4210", }, |
3028 | { .compatible = "samsung,pinctrl-exynos4x12", }, | 3027 | { .compatible = "samsung,pinctrl-exynos4x12", }, |
3028 | { .compatible = "samsung,pinctrl-exynos5440", }, | ||
3029 | }; | 3029 | }; |
3030 | for_each_matching_node(pctrl_np, exynos_pinctrl_ids) | 3030 | for_each_matching_node(pctrl_np, exynos_pinctrl_ids) |
3031 | if (pctrl_np && of_device_is_available(pctrl_np)) | 3031 | if (pctrl_np && of_device_is_available(pctrl_np)) |
diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index 2bf9670ba29b..2aa331499f81 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c | |||
@@ -221,11 +221,13 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node, | |||
221 | 221 | ||
222 | BUG_ON(!hole_node->hole_follows || node->allocated); | 222 | BUG_ON(!hole_node->hole_follows || node->allocated); |
223 | 223 | ||
224 | if (mm->color_adjust) | ||
225 | mm->color_adjust(hole_node, color, &adj_start, &adj_end); | ||
226 | |||
227 | if (adj_start < start) | 224 | if (adj_start < start) |
228 | adj_start = start; | 225 | adj_start = start; |
226 | if (adj_end > end) | ||
227 | adj_end = end; | ||
228 | |||
229 | if (mm->color_adjust) | ||
230 | mm->color_adjust(hole_node, color, &adj_start, &adj_end); | ||
229 | 231 | ||
230 | if (alignment) { | 232 | if (alignment) { |
231 | unsigned tmp = adj_start % alignment; | 233 | unsigned tmp = adj_start % alignment; |
@@ -506,7 +508,7 @@ void drm_mm_init_scan(struct drm_mm *mm, | |||
506 | mm->scan_size = size; | 508 | mm->scan_size = size; |
507 | mm->scanned_blocks = 0; | 509 | mm->scanned_blocks = 0; |
508 | mm->scan_hit_start = 0; | 510 | mm->scan_hit_start = 0; |
509 | mm->scan_hit_size = 0; | 511 | mm->scan_hit_end = 0; |
510 | mm->scan_check_range = 0; | 512 | mm->scan_check_range = 0; |
511 | mm->prev_scanned_node = NULL; | 513 | mm->prev_scanned_node = NULL; |
512 | } | 514 | } |
@@ -533,7 +535,7 @@ void drm_mm_init_scan_with_range(struct drm_mm *mm, | |||
533 | mm->scan_size = size; | 535 | mm->scan_size = size; |
534 | mm->scanned_blocks = 0; | 536 | mm->scanned_blocks = 0; |
535 | mm->scan_hit_start = 0; | 537 | mm->scan_hit_start = 0; |
536 | mm->scan_hit_size = 0; | 538 | mm->scan_hit_end = 0; |
537 | mm->scan_start = start; | 539 | mm->scan_start = start; |
538 | mm->scan_end = end; | 540 | mm->scan_end = end; |
539 | mm->scan_check_range = 1; | 541 | mm->scan_check_range = 1; |
@@ -552,8 +554,7 @@ int drm_mm_scan_add_block(struct drm_mm_node *node) | |||
552 | struct drm_mm *mm = node->mm; | 554 | struct drm_mm *mm = node->mm; |
553 | struct drm_mm_node *prev_node; | 555 | struct drm_mm_node *prev_node; |
554 | unsigned long hole_start, hole_end; | 556 | unsigned long hole_start, hole_end; |
555 | unsigned long adj_start; | 557 | unsigned long adj_start, adj_end; |
556 | unsigned long adj_end; | ||
557 | 558 | ||
558 | mm->scanned_blocks++; | 559 | mm->scanned_blocks++; |
559 | 560 | ||
@@ -570,14 +571,8 @@ int drm_mm_scan_add_block(struct drm_mm_node *node) | |||
570 | node->node_list.next = &mm->prev_scanned_node->node_list; | 571 | node->node_list.next = &mm->prev_scanned_node->node_list; |
571 | mm->prev_scanned_node = node; | 572 | mm->prev_scanned_node = node; |
572 | 573 | ||
573 | hole_start = drm_mm_hole_node_start(prev_node); | 574 | adj_start = hole_start = drm_mm_hole_node_start(prev_node); |
574 | hole_end = drm_mm_hole_node_end(prev_node); | 575 | adj_end = hole_end = drm_mm_hole_node_end(prev_node); |
575 | |||
576 | adj_start = hole_start; | ||
577 | adj_end = hole_end; | ||
578 | |||
579 | if (mm->color_adjust) | ||
580 | mm->color_adjust(prev_node, mm->scan_color, &adj_start, &adj_end); | ||
581 | 576 | ||
582 | if (mm->scan_check_range) { | 577 | if (mm->scan_check_range) { |
583 | if (adj_start < mm->scan_start) | 578 | if (adj_start < mm->scan_start) |
@@ -586,11 +581,14 @@ int drm_mm_scan_add_block(struct drm_mm_node *node) | |||
586 | adj_end = mm->scan_end; | 581 | adj_end = mm->scan_end; |
587 | } | 582 | } |
588 | 583 | ||
584 | if (mm->color_adjust) | ||
585 | mm->color_adjust(prev_node, mm->scan_color, | ||
586 | &adj_start, &adj_end); | ||
587 | |||
589 | if (check_free_hole(adj_start, adj_end, | 588 | if (check_free_hole(adj_start, adj_end, |
590 | mm->scan_size, mm->scan_alignment)) { | 589 | mm->scan_size, mm->scan_alignment)) { |
591 | mm->scan_hit_start = hole_start; | 590 | mm->scan_hit_start = hole_start; |
592 | mm->scan_hit_size = hole_end; | 591 | mm->scan_hit_end = hole_end; |
593 | |||
594 | return 1; | 592 | return 1; |
595 | } | 593 | } |
596 | 594 | ||
@@ -626,19 +624,10 @@ int drm_mm_scan_remove_block(struct drm_mm_node *node) | |||
626 | node_list); | 624 | node_list); |
627 | 625 | ||
628 | prev_node->hole_follows = node->scanned_preceeds_hole; | 626 | prev_node->hole_follows = node->scanned_preceeds_hole; |
629 | INIT_LIST_HEAD(&node->node_list); | ||
630 | list_add(&node->node_list, &prev_node->node_list); | 627 | list_add(&node->node_list, &prev_node->node_list); |
631 | 628 | ||
632 | /* Only need to check for containement because start&size for the | 629 | return (drm_mm_hole_node_end(node) > mm->scan_hit_start && |
633 | * complete resulting free block (not just the desired part) is | 630 | node->start < mm->scan_hit_end); |
634 | * stored. */ | ||
635 | if (node->start >= mm->scan_hit_start && | ||
636 | node->start + node->size | ||
637 | <= mm->scan_hit_start + mm->scan_hit_size) { | ||
638 | return 1; | ||
639 | } | ||
640 | |||
641 | return 0; | ||
642 | } | 631 | } |
643 | EXPORT_SYMBOL(drm_mm_scan_remove_block); | 632 | EXPORT_SYMBOL(drm_mm_scan_remove_block); |
644 | 633 | ||
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index e6a11ca85eaf..7944d301518a 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c | |||
@@ -641,6 +641,7 @@ static void i915_ring_error_state(struct seq_file *m, | |||
641 | seq_printf(m, "%s command stream:\n", ring_str(ring)); | 641 | seq_printf(m, "%s command stream:\n", ring_str(ring)); |
642 | seq_printf(m, " HEAD: 0x%08x\n", error->head[ring]); | 642 | seq_printf(m, " HEAD: 0x%08x\n", error->head[ring]); |
643 | seq_printf(m, " TAIL: 0x%08x\n", error->tail[ring]); | 643 | seq_printf(m, " TAIL: 0x%08x\n", error->tail[ring]); |
644 | seq_printf(m, " CTL: 0x%08x\n", error->ctl[ring]); | ||
644 | seq_printf(m, " ACTHD: 0x%08x\n", error->acthd[ring]); | 645 | seq_printf(m, " ACTHD: 0x%08x\n", error->acthd[ring]); |
645 | seq_printf(m, " IPEIR: 0x%08x\n", error->ipeir[ring]); | 646 | seq_printf(m, " IPEIR: 0x%08x\n", error->ipeir[ring]); |
646 | seq_printf(m, " IPEHR: 0x%08x\n", error->ipehr[ring]); | 647 | seq_printf(m, " IPEHR: 0x%08x\n", error->ipehr[ring]); |
@@ -693,6 +694,8 @@ static int i915_error_state(struct seq_file *m, void *unused) | |||
693 | seq_printf(m, "EIR: 0x%08x\n", error->eir); | 694 | seq_printf(m, "EIR: 0x%08x\n", error->eir); |
694 | seq_printf(m, "IER: 0x%08x\n", error->ier); | 695 | seq_printf(m, "IER: 0x%08x\n", error->ier); |
695 | seq_printf(m, "PGTBL_ER: 0x%08x\n", error->pgtbl_er); | 696 | seq_printf(m, "PGTBL_ER: 0x%08x\n", error->pgtbl_er); |
697 | seq_printf(m, "FORCEWAKE: 0x%08x\n", error->forcewake); | ||
698 | seq_printf(m, "DERRMR: 0x%08x\n", error->derrmr); | ||
696 | seq_printf(m, "CCID: 0x%08x\n", error->ccid); | 699 | seq_printf(m, "CCID: 0x%08x\n", error->ccid); |
697 | 700 | ||
698 | for (i = 0; i < dev_priv->num_fence_regs; i++) | 701 | for (i = 0; i < dev_priv->num_fence_regs; i++) |
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ed3059575576..12ab3bdea54d 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
@@ -188,10 +188,13 @@ struct drm_i915_error_state { | |||
188 | u32 pgtbl_er; | 188 | u32 pgtbl_er; |
189 | u32 ier; | 189 | u32 ier; |
190 | u32 ccid; | 190 | u32 ccid; |
191 | u32 derrmr; | ||
192 | u32 forcewake; | ||
191 | bool waiting[I915_NUM_RINGS]; | 193 | bool waiting[I915_NUM_RINGS]; |
192 | u32 pipestat[I915_MAX_PIPES]; | 194 | u32 pipestat[I915_MAX_PIPES]; |
193 | u32 tail[I915_NUM_RINGS]; | 195 | u32 tail[I915_NUM_RINGS]; |
194 | u32 head[I915_NUM_RINGS]; | 196 | u32 head[I915_NUM_RINGS]; |
197 | u32 ctl[I915_NUM_RINGS]; | ||
195 | u32 ipeir[I915_NUM_RINGS]; | 198 | u32 ipeir[I915_NUM_RINGS]; |
196 | u32 ipehr[I915_NUM_RINGS]; | 199 | u32 ipehr[I915_NUM_RINGS]; |
197 | u32 instdone[I915_NUM_RINGS]; | 200 | u32 instdone[I915_NUM_RINGS]; |
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index da3c82e301b1..8febea6daa08 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c | |||
@@ -1717,7 +1717,8 @@ i915_gem_object_put_pages(struct drm_i915_gem_object *obj) | |||
1717 | } | 1717 | } |
1718 | 1718 | ||
1719 | static long | 1719 | static long |
1720 | i915_gem_purge(struct drm_i915_private *dev_priv, long target) | 1720 | __i915_gem_shrink(struct drm_i915_private *dev_priv, long target, |
1721 | bool purgeable_only) | ||
1721 | { | 1722 | { |
1722 | struct drm_i915_gem_object *obj, *next; | 1723 | struct drm_i915_gem_object *obj, *next; |
1723 | long count = 0; | 1724 | long count = 0; |
@@ -1725,7 +1726,7 @@ i915_gem_purge(struct drm_i915_private *dev_priv, long target) | |||
1725 | list_for_each_entry_safe(obj, next, | 1726 | list_for_each_entry_safe(obj, next, |
1726 | &dev_priv->mm.unbound_list, | 1727 | &dev_priv->mm.unbound_list, |
1727 | gtt_list) { | 1728 | gtt_list) { |
1728 | if (i915_gem_object_is_purgeable(obj) && | 1729 | if ((i915_gem_object_is_purgeable(obj) || !purgeable_only) && |
1729 | i915_gem_object_put_pages(obj) == 0) { | 1730 | i915_gem_object_put_pages(obj) == 0) { |
1730 | count += obj->base.size >> PAGE_SHIFT; | 1731 | count += obj->base.size >> PAGE_SHIFT; |
1731 | if (count >= target) | 1732 | if (count >= target) |
@@ -1736,7 +1737,7 @@ i915_gem_purge(struct drm_i915_private *dev_priv, long target) | |||
1736 | list_for_each_entry_safe(obj, next, | 1737 | list_for_each_entry_safe(obj, next, |
1737 | &dev_priv->mm.inactive_list, | 1738 | &dev_priv->mm.inactive_list, |
1738 | mm_list) { | 1739 | mm_list) { |
1739 | if (i915_gem_object_is_purgeable(obj) && | 1740 | if ((i915_gem_object_is_purgeable(obj) || !purgeable_only) && |
1740 | i915_gem_object_unbind(obj) == 0 && | 1741 | i915_gem_object_unbind(obj) == 0 && |
1741 | i915_gem_object_put_pages(obj) == 0) { | 1742 | i915_gem_object_put_pages(obj) == 0) { |
1742 | count += obj->base.size >> PAGE_SHIFT; | 1743 | count += obj->base.size >> PAGE_SHIFT; |
@@ -1748,6 +1749,12 @@ i915_gem_purge(struct drm_i915_private *dev_priv, long target) | |||
1748 | return count; | 1749 | return count; |
1749 | } | 1750 | } |
1750 | 1751 | ||
1752 | static long | ||
1753 | i915_gem_purge(struct drm_i915_private *dev_priv, long target) | ||
1754 | { | ||
1755 | return __i915_gem_shrink(dev_priv, target, true); | ||
1756 | } | ||
1757 | |||
1751 | static void | 1758 | static void |
1752 | i915_gem_shrink_all(struct drm_i915_private *dev_priv) | 1759 | i915_gem_shrink_all(struct drm_i915_private *dev_priv) |
1753 | { | 1760 | { |
@@ -3522,14 +3529,15 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data, | |||
3522 | goto out; | 3529 | goto out; |
3523 | } | 3530 | } |
3524 | 3531 | ||
3525 | obj->user_pin_count++; | 3532 | if (obj->user_pin_count == 0) { |
3526 | obj->pin_filp = file; | ||
3527 | if (obj->user_pin_count == 1) { | ||
3528 | ret = i915_gem_object_pin(obj, args->alignment, true, false); | 3533 | ret = i915_gem_object_pin(obj, args->alignment, true, false); |
3529 | if (ret) | 3534 | if (ret) |
3530 | goto out; | 3535 | goto out; |
3531 | } | 3536 | } |
3532 | 3537 | ||
3538 | obj->user_pin_count++; | ||
3539 | obj->pin_filp = file; | ||
3540 | |||
3533 | /* XXX - flush the CPU caches for pinned objects | 3541 | /* XXX - flush the CPU caches for pinned objects |
3534 | * as the X server doesn't manage domains yet | 3542 | * as the X server doesn't manage domains yet |
3535 | */ | 3543 | */ |
@@ -4395,6 +4403,9 @@ i915_gem_inactive_shrink(struct shrinker *shrinker, struct shrink_control *sc) | |||
4395 | if (nr_to_scan) { | 4403 | if (nr_to_scan) { |
4396 | nr_to_scan -= i915_gem_purge(dev_priv, nr_to_scan); | 4404 | nr_to_scan -= i915_gem_purge(dev_priv, nr_to_scan); |
4397 | if (nr_to_scan > 0) | 4405 | if (nr_to_scan > 0) |
4406 | nr_to_scan -= __i915_gem_shrink(dev_priv, nr_to_scan, | ||
4407 | false); | ||
4408 | if (nr_to_scan > 0) | ||
4398 | i915_gem_shrink_all(dev_priv); | 4409 | i915_gem_shrink_all(dev_priv); |
4399 | } | 4410 | } |
4400 | 4411 | ||
@@ -4402,7 +4413,7 @@ i915_gem_inactive_shrink(struct shrinker *shrinker, struct shrink_control *sc) | |||
4402 | list_for_each_entry(obj, &dev_priv->mm.unbound_list, gtt_list) | 4413 | list_for_each_entry(obj, &dev_priv->mm.unbound_list, gtt_list) |
4403 | if (obj->pages_pin_count == 0) | 4414 | if (obj->pages_pin_count == 0) |
4404 | cnt += obj->base.size >> PAGE_SHIFT; | 4415 | cnt += obj->base.size >> PAGE_SHIFT; |
4405 | list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) | 4416 | list_for_each_entry(obj, &dev_priv->mm.inactive_list, gtt_list) |
4406 | if (obj->pin_count == 0 && obj->pages_pin_count == 0) | 4417 | if (obj->pin_count == 0 && obj->pages_pin_count == 0) |
4407 | cnt += obj->base.size >> PAGE_SHIFT; | 4418 | cnt += obj->base.size >> PAGE_SHIFT; |
4408 | 4419 | ||
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index d6a994a07393..26d08bb58218 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c | |||
@@ -539,6 +539,8 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, | |||
539 | total = 0; | 539 | total = 0; |
540 | for (i = 0; i < count; i++) { | 540 | for (i = 0; i < count; i++) { |
541 | struct drm_i915_gem_relocation_entry __user *user_relocs; | 541 | struct drm_i915_gem_relocation_entry __user *user_relocs; |
542 | u64 invalid_offset = (u64)-1; | ||
543 | int j; | ||
542 | 544 | ||
543 | user_relocs = (void __user *)(uintptr_t)exec[i].relocs_ptr; | 545 | user_relocs = (void __user *)(uintptr_t)exec[i].relocs_ptr; |
544 | 546 | ||
@@ -549,6 +551,25 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, | |||
549 | goto err; | 551 | goto err; |
550 | } | 552 | } |
551 | 553 | ||
554 | /* As we do not update the known relocation offsets after | ||
555 | * relocating (due to the complexities in lock handling), | ||
556 | * we need to mark them as invalid now so that we force the | ||
557 | * relocation processing next time. Just in case the target | ||
558 | * object is evicted and then rebound into its old | ||
559 | * presumed_offset before the next execbuffer - if that | ||
560 | * happened we would make the mistake of assuming that the | ||
561 | * relocations were valid. | ||
562 | */ | ||
563 | for (j = 0; j < exec[i].relocation_count; j++) { | ||
564 | if (copy_to_user(&user_relocs[j].presumed_offset, | ||
565 | &invalid_offset, | ||
566 | sizeof(invalid_offset))) { | ||
567 | ret = -EFAULT; | ||
568 | mutex_lock(&dev->struct_mutex); | ||
569 | goto err; | ||
570 | } | ||
571 | } | ||
572 | |||
552 | reloc_offset[i] = total; | 573 | reloc_offset[i] = total; |
553 | total += exec[i].relocation_count; | 574 | total += exec[i].relocation_count; |
554 | } | 575 | } |
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 2220dec3e5d9..fe843389c7b4 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c | |||
@@ -1157,6 +1157,7 @@ static void i915_record_ring_state(struct drm_device *dev, | |||
1157 | error->acthd[ring->id] = intel_ring_get_active_head(ring); | 1157 | error->acthd[ring->id] = intel_ring_get_active_head(ring); |
1158 | error->head[ring->id] = I915_READ_HEAD(ring); | 1158 | error->head[ring->id] = I915_READ_HEAD(ring); |
1159 | error->tail[ring->id] = I915_READ_TAIL(ring); | 1159 | error->tail[ring->id] = I915_READ_TAIL(ring); |
1160 | error->ctl[ring->id] = I915_READ_CTL(ring); | ||
1160 | 1161 | ||
1161 | error->cpu_ring_head[ring->id] = ring->head; | 1162 | error->cpu_ring_head[ring->id] = ring->head; |
1162 | error->cpu_ring_tail[ring->id] = ring->tail; | 1163 | error->cpu_ring_tail[ring->id] = ring->tail; |
@@ -1251,6 +1252,16 @@ static void i915_capture_error_state(struct drm_device *dev) | |||
1251 | else | 1252 | else |
1252 | error->ier = I915_READ(IER); | 1253 | error->ier = I915_READ(IER); |
1253 | 1254 | ||
1255 | if (INTEL_INFO(dev)->gen >= 6) | ||
1256 | error->derrmr = I915_READ(DERRMR); | ||
1257 | |||
1258 | if (IS_VALLEYVIEW(dev)) | ||
1259 | error->forcewake = I915_READ(FORCEWAKE_VLV); | ||
1260 | else if (INTEL_INFO(dev)->gen >= 7) | ||
1261 | error->forcewake = I915_READ(FORCEWAKE_MT); | ||
1262 | else if (INTEL_INFO(dev)->gen == 6) | ||
1263 | error->forcewake = I915_READ(FORCEWAKE); | ||
1264 | |||
1254 | for_each_pipe(pipe) | 1265 | for_each_pipe(pipe) |
1255 | error->pipestat[pipe] = I915_READ(PIPESTAT(pipe)); | 1266 | error->pipestat[pipe] = I915_READ(PIPESTAT(pipe)); |
1256 | 1267 | ||
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 186ee5c85b51..b401788e1791 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h | |||
@@ -512,6 +512,8 @@ | |||
512 | #define GEN7_ERR_INT 0x44040 | 512 | #define GEN7_ERR_INT 0x44040 |
513 | #define ERR_INT_MMIO_UNCLAIMED (1<<13) | 513 | #define ERR_INT_MMIO_UNCLAIMED (1<<13) |
514 | 514 | ||
515 | #define DERRMR 0x44050 | ||
516 | |||
515 | /* GM45+ chicken bits -- debug workaround bits that may be required | 517 | /* GM45+ chicken bits -- debug workaround bits that may be required |
516 | * for various sorts of correct behavior. The top 16 bits of each are | 518 | * for various sorts of correct behavior. The top 16 bits of each are |
517 | * the enables for writing to the corresponding low bit. | 519 | * the enables for writing to the corresponding low bit. |
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a9fb046b94a1..da1ad9c80bb5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
@@ -8598,19 +8598,30 @@ int intel_framebuffer_init(struct drm_device *dev, | |||
8598 | { | 8598 | { |
8599 | int ret; | 8599 | int ret; |
8600 | 8600 | ||
8601 | if (obj->tiling_mode == I915_TILING_Y) | 8601 | if (obj->tiling_mode == I915_TILING_Y) { |
8602 | DRM_DEBUG("hardware does not support tiling Y\n"); | ||
8602 | return -EINVAL; | 8603 | return -EINVAL; |
8604 | } | ||
8603 | 8605 | ||
8604 | if (mode_cmd->pitches[0] & 63) | 8606 | if (mode_cmd->pitches[0] & 63) { |
8607 | DRM_DEBUG("pitch (%d) must be at least 64 byte aligned\n", | ||
8608 | mode_cmd->pitches[0]); | ||
8605 | return -EINVAL; | 8609 | return -EINVAL; |
8610 | } | ||
8606 | 8611 | ||
8607 | /* FIXME <= Gen4 stride limits are bit unclear */ | 8612 | /* FIXME <= Gen4 stride limits are bit unclear */ |
8608 | if (mode_cmd->pitches[0] > 32768) | 8613 | if (mode_cmd->pitches[0] > 32768) { |
8614 | DRM_DEBUG("pitch (%d) must be at less than 32768\n", | ||
8615 | mode_cmd->pitches[0]); | ||
8609 | return -EINVAL; | 8616 | return -EINVAL; |
8617 | } | ||
8610 | 8618 | ||
8611 | if (obj->tiling_mode != I915_TILING_NONE && | 8619 | if (obj->tiling_mode != I915_TILING_NONE && |
8612 | mode_cmd->pitches[0] != obj->stride) | 8620 | mode_cmd->pitches[0] != obj->stride) { |
8621 | DRM_DEBUG("pitch (%d) must match tiling stride (%d)\n", | ||
8622 | mode_cmd->pitches[0], obj->stride); | ||
8613 | return -EINVAL; | 8623 | return -EINVAL; |
8624 | } | ||
8614 | 8625 | ||
8615 | /* Reject formats not supported by any plane early. */ | 8626 | /* Reject formats not supported by any plane early. */ |
8616 | switch (mode_cmd->pixel_format) { | 8627 | switch (mode_cmd->pixel_format) { |
@@ -8621,8 +8632,10 @@ int intel_framebuffer_init(struct drm_device *dev, | |||
8621 | break; | 8632 | break; |
8622 | case DRM_FORMAT_XRGB1555: | 8633 | case DRM_FORMAT_XRGB1555: |
8623 | case DRM_FORMAT_ARGB1555: | 8634 | case DRM_FORMAT_ARGB1555: |
8624 | if (INTEL_INFO(dev)->gen > 3) | 8635 | if (INTEL_INFO(dev)->gen > 3) { |
8636 | DRM_DEBUG("invalid format: 0x%08x\n", mode_cmd->pixel_format); | ||
8625 | return -EINVAL; | 8637 | return -EINVAL; |
8638 | } | ||
8626 | break; | 8639 | break; |
8627 | case DRM_FORMAT_XBGR8888: | 8640 | case DRM_FORMAT_XBGR8888: |
8628 | case DRM_FORMAT_ABGR8888: | 8641 | case DRM_FORMAT_ABGR8888: |
@@ -8630,18 +8643,22 @@ int intel_framebuffer_init(struct drm_device *dev, | |||
8630 | case DRM_FORMAT_ARGB2101010: | 8643 | case DRM_FORMAT_ARGB2101010: |
8631 | case DRM_FORMAT_XBGR2101010: | 8644 | case DRM_FORMAT_XBGR2101010: |
8632 | case DRM_FORMAT_ABGR2101010: | 8645 | case DRM_FORMAT_ABGR2101010: |
8633 | if (INTEL_INFO(dev)->gen < 4) | 8646 | if (INTEL_INFO(dev)->gen < 4) { |
8647 | DRM_DEBUG("invalid format: 0x%08x\n", mode_cmd->pixel_format); | ||
8634 | return -EINVAL; | 8648 | return -EINVAL; |
8649 | } | ||
8635 | break; | 8650 | break; |
8636 | case DRM_FORMAT_YUYV: | 8651 | case DRM_FORMAT_YUYV: |
8637 | case DRM_FORMAT_UYVY: | 8652 | case DRM_FORMAT_UYVY: |
8638 | case DRM_FORMAT_YVYU: | 8653 | case DRM_FORMAT_YVYU: |
8639 | case DRM_FORMAT_VYUY: | 8654 | case DRM_FORMAT_VYUY: |
8640 | if (INTEL_INFO(dev)->gen < 6) | 8655 | if (INTEL_INFO(dev)->gen < 5) { |
8656 | DRM_DEBUG("invalid format: 0x%08x\n", mode_cmd->pixel_format); | ||
8641 | return -EINVAL; | 8657 | return -EINVAL; |
8658 | } | ||
8642 | break; | 8659 | break; |
8643 | default: | 8660 | default: |
8644 | DRM_DEBUG_KMS("unsupported pixel format 0x%08x\n", mode_cmd->pixel_format); | 8661 | DRM_DEBUG("unsupported pixel format 0x%08x\n", mode_cmd->pixel_format); |
8645 | return -EINVAL; | 8662 | return -EINVAL; |
8646 | } | 8663 | } |
8647 | 8664 | ||
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 1b63d55318a0..fb3715b4b09d 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c | |||
@@ -2579,7 +2579,8 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect | |||
2579 | 2579 | ||
2580 | static void | 2580 | static void |
2581 | intel_dp_init_panel_power_sequencer(struct drm_device *dev, | 2581 | intel_dp_init_panel_power_sequencer(struct drm_device *dev, |
2582 | struct intel_dp *intel_dp) | 2582 | struct intel_dp *intel_dp, |
2583 | struct edp_power_seq *out) | ||
2583 | { | 2584 | { |
2584 | struct drm_i915_private *dev_priv = dev->dev_private; | 2585 | struct drm_i915_private *dev_priv = dev->dev_private; |
2585 | struct edp_power_seq cur, vbt, spec, final; | 2586 | struct edp_power_seq cur, vbt, spec, final; |
@@ -2650,16 +2651,35 @@ intel_dp_init_panel_power_sequencer(struct drm_device *dev, | |||
2650 | intel_dp->panel_power_cycle_delay = get_delay(t11_t12); | 2651 | intel_dp->panel_power_cycle_delay = get_delay(t11_t12); |
2651 | #undef get_delay | 2652 | #undef get_delay |
2652 | 2653 | ||
2654 | DRM_DEBUG_KMS("panel power up delay %d, power down delay %d, power cycle delay %d\n", | ||
2655 | intel_dp->panel_power_up_delay, intel_dp->panel_power_down_delay, | ||
2656 | intel_dp->panel_power_cycle_delay); | ||
2657 | |||
2658 | DRM_DEBUG_KMS("backlight on delay %d, off delay %d\n", | ||
2659 | intel_dp->backlight_on_delay, intel_dp->backlight_off_delay); | ||
2660 | |||
2661 | if (out) | ||
2662 | *out = final; | ||
2663 | } | ||
2664 | |||
2665 | static void | ||
2666 | intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev, | ||
2667 | struct intel_dp *intel_dp, | ||
2668 | struct edp_power_seq *seq) | ||
2669 | { | ||
2670 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
2671 | u32 pp_on, pp_off, pp_div; | ||
2672 | |||
2653 | /* And finally store the new values in the power sequencer. */ | 2673 | /* And finally store the new values in the power sequencer. */ |
2654 | pp_on = (final.t1_t3 << PANEL_POWER_UP_DELAY_SHIFT) | | 2674 | pp_on = (seq->t1_t3 << PANEL_POWER_UP_DELAY_SHIFT) | |
2655 | (final.t8 << PANEL_LIGHT_ON_DELAY_SHIFT); | 2675 | (seq->t8 << PANEL_LIGHT_ON_DELAY_SHIFT); |
2656 | pp_off = (final.t9 << PANEL_LIGHT_OFF_DELAY_SHIFT) | | 2676 | pp_off = (seq->t9 << PANEL_LIGHT_OFF_DELAY_SHIFT) | |
2657 | (final.t10 << PANEL_POWER_DOWN_DELAY_SHIFT); | 2677 | (seq->t10 << PANEL_POWER_DOWN_DELAY_SHIFT); |
2658 | /* Compute the divisor for the pp clock, simply match the Bspec | 2678 | /* Compute the divisor for the pp clock, simply match the Bspec |
2659 | * formula. */ | 2679 | * formula. */ |
2660 | pp_div = ((100 * intel_pch_rawclk(dev))/2 - 1) | 2680 | pp_div = ((100 * intel_pch_rawclk(dev))/2 - 1) |
2661 | << PP_REFERENCE_DIVIDER_SHIFT; | 2681 | << PP_REFERENCE_DIVIDER_SHIFT; |
2662 | pp_div |= (DIV_ROUND_UP(final.t11_t12, 1000) | 2682 | pp_div |= (DIV_ROUND_UP(seq->t11_t12, 1000) |
2663 | << PANEL_POWER_CYCLE_DELAY_SHIFT); | 2683 | << PANEL_POWER_CYCLE_DELAY_SHIFT); |
2664 | 2684 | ||
2665 | /* Haswell doesn't have any port selection bits for the panel | 2685 | /* Haswell doesn't have any port selection bits for the panel |
@@ -2675,14 +2695,6 @@ intel_dp_init_panel_power_sequencer(struct drm_device *dev, | |||
2675 | I915_WRITE(PCH_PP_OFF_DELAYS, pp_off); | 2695 | I915_WRITE(PCH_PP_OFF_DELAYS, pp_off); |
2676 | I915_WRITE(PCH_PP_DIVISOR, pp_div); | 2696 | I915_WRITE(PCH_PP_DIVISOR, pp_div); |
2677 | 2697 | ||
2678 | |||
2679 | DRM_DEBUG_KMS("panel power up delay %d, power down delay %d, power cycle delay %d\n", | ||
2680 | intel_dp->panel_power_up_delay, intel_dp->panel_power_down_delay, | ||
2681 | intel_dp->panel_power_cycle_delay); | ||
2682 | |||
2683 | DRM_DEBUG_KMS("backlight on delay %d, off delay %d\n", | ||
2684 | intel_dp->backlight_on_delay, intel_dp->backlight_off_delay); | ||
2685 | |||
2686 | DRM_DEBUG_KMS("panel power sequencer register settings: PP_ON %#x, PP_OFF %#x, PP_DIV %#x\n", | 2698 | DRM_DEBUG_KMS("panel power sequencer register settings: PP_ON %#x, PP_OFF %#x, PP_DIV %#x\n", |
2687 | I915_READ(PCH_PP_ON_DELAYS), | 2699 | I915_READ(PCH_PP_ON_DELAYS), |
2688 | I915_READ(PCH_PP_OFF_DELAYS), | 2700 | I915_READ(PCH_PP_OFF_DELAYS), |
@@ -2699,6 +2711,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, | |||
2699 | struct drm_device *dev = intel_encoder->base.dev; | 2711 | struct drm_device *dev = intel_encoder->base.dev; |
2700 | struct drm_i915_private *dev_priv = dev->dev_private; | 2712 | struct drm_i915_private *dev_priv = dev->dev_private; |
2701 | struct drm_display_mode *fixed_mode = NULL; | 2713 | struct drm_display_mode *fixed_mode = NULL; |
2714 | struct edp_power_seq power_seq = { 0 }; | ||
2702 | enum port port = intel_dig_port->port; | 2715 | enum port port = intel_dig_port->port; |
2703 | const char *name = NULL; | 2716 | const char *name = NULL; |
2704 | int type; | 2717 | int type; |
@@ -2771,7 +2784,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, | |||
2771 | } | 2784 | } |
2772 | 2785 | ||
2773 | if (is_edp(intel_dp)) | 2786 | if (is_edp(intel_dp)) |
2774 | intel_dp_init_panel_power_sequencer(dev, intel_dp); | 2787 | intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq); |
2775 | 2788 | ||
2776 | intel_dp_i2c_init(intel_dp, intel_connector, name); | 2789 | intel_dp_i2c_init(intel_dp, intel_connector, name); |
2777 | 2790 | ||
@@ -2798,6 +2811,10 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, | |||
2798 | return; | 2811 | return; |
2799 | } | 2812 | } |
2800 | 2813 | ||
2814 | /* We now know it's not a ghost, init power sequence regs. */ | ||
2815 | intel_dp_init_panel_power_sequencer_registers(dev, intel_dp, | ||
2816 | &power_seq); | ||
2817 | |||
2801 | ironlake_edp_panel_vdd_on(intel_dp); | 2818 | ironlake_edp_panel_vdd_on(intel_dp); |
2802 | edid = drm_get_edid(connector, &intel_dp->adapter); | 2819 | edid = drm_get_edid(connector, &intel_dp->adapter); |
2803 | if (edid) { | 2820 | if (edid) { |
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index b9a660a53677..17aee74258ad 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c | |||
@@ -776,14 +776,6 @@ static const struct dmi_system_id intel_no_lvds[] = { | |||
776 | }, | 776 | }, |
777 | { | 777 | { |
778 | .callback = intel_no_lvds_dmi_callback, | 778 | .callback = intel_no_lvds_dmi_callback, |
779 | .ident = "ZOTAC ZBOXSD-ID12/ID13", | ||
780 | .matches = { | ||
781 | DMI_MATCH(DMI_BOARD_VENDOR, "ZOTAC"), | ||
782 | DMI_MATCH(DMI_BOARD_NAME, "ZBOXSD-ID12/ID13"), | ||
783 | }, | ||
784 | }, | ||
785 | { | ||
786 | .callback = intel_no_lvds_dmi_callback, | ||
787 | .ident = "Gigabyte GA-D525TUD", | 779 | .ident = "Gigabyte GA-D525TUD", |
788 | .matches = { | 780 | .matches = { |
789 | DMI_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co., Ltd."), | 781 | DMI_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co., Ltd."), |
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index e6f54ffab3ba..3280cffe50f4 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c | |||
@@ -44,6 +44,14 @@ | |||
44 | * i915.i915_enable_fbc parameter | 44 | * i915.i915_enable_fbc parameter |
45 | */ | 45 | */ |
46 | 46 | ||
47 | static bool intel_crtc_active(struct drm_crtc *crtc) | ||
48 | { | ||
49 | /* Be paranoid as we can arrive here with only partial | ||
50 | * state retrieved from the hardware during setup. | ||
51 | */ | ||
52 | return to_intel_crtc(crtc)->active && crtc->fb && crtc->mode.clock; | ||
53 | } | ||
54 | |||
47 | static void i8xx_disable_fbc(struct drm_device *dev) | 55 | static void i8xx_disable_fbc(struct drm_device *dev) |
48 | { | 56 | { |
49 | struct drm_i915_private *dev_priv = dev->dev_private; | 57 | struct drm_i915_private *dev_priv = dev->dev_private; |
@@ -405,9 +413,8 @@ void intel_update_fbc(struct drm_device *dev) | |||
405 | * - going to an unsupported config (interlace, pixel multiply, etc.) | 413 | * - going to an unsupported config (interlace, pixel multiply, etc.) |
406 | */ | 414 | */ |
407 | list_for_each_entry(tmp_crtc, &dev->mode_config.crtc_list, head) { | 415 | list_for_each_entry(tmp_crtc, &dev->mode_config.crtc_list, head) { |
408 | if (to_intel_crtc(tmp_crtc)->active && | 416 | if (intel_crtc_active(tmp_crtc) && |
409 | !to_intel_crtc(tmp_crtc)->primary_disabled && | 417 | !to_intel_crtc(tmp_crtc)->primary_disabled) { |
410 | tmp_crtc->fb) { | ||
411 | if (crtc) { | 418 | if (crtc) { |
412 | DRM_DEBUG_KMS("more than one pipe active, disabling compression\n"); | 419 | DRM_DEBUG_KMS("more than one pipe active, disabling compression\n"); |
413 | dev_priv->no_fbc_reason = FBC_MULTIPLE_PIPES; | 420 | dev_priv->no_fbc_reason = FBC_MULTIPLE_PIPES; |
@@ -992,7 +999,7 @@ static struct drm_crtc *single_enabled_crtc(struct drm_device *dev) | |||
992 | struct drm_crtc *crtc, *enabled = NULL; | 999 | struct drm_crtc *crtc, *enabled = NULL; |
993 | 1000 | ||
994 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | 1001 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
995 | if (to_intel_crtc(crtc)->active && crtc->fb) { | 1002 | if (intel_crtc_active(crtc)) { |
996 | if (enabled) | 1003 | if (enabled) |
997 | return NULL; | 1004 | return NULL; |
998 | enabled = crtc; | 1005 | enabled = crtc; |
@@ -1086,7 +1093,7 @@ static bool g4x_compute_wm0(struct drm_device *dev, | |||
1086 | int entries, tlb_miss; | 1093 | int entries, tlb_miss; |
1087 | 1094 | ||
1088 | crtc = intel_get_crtc_for_plane(dev, plane); | 1095 | crtc = intel_get_crtc_for_plane(dev, plane); |
1089 | if (crtc->fb == NULL || !to_intel_crtc(crtc)->active) { | 1096 | if (!intel_crtc_active(crtc)) { |
1090 | *cursor_wm = cursor->guard_size; | 1097 | *cursor_wm = cursor->guard_size; |
1091 | *plane_wm = display->guard_size; | 1098 | *plane_wm = display->guard_size; |
1092 | return false; | 1099 | return false; |
@@ -1215,7 +1222,7 @@ static bool vlv_compute_drain_latency(struct drm_device *dev, | |||
1215 | int entries; | 1222 | int entries; |
1216 | 1223 | ||
1217 | crtc = intel_get_crtc_for_plane(dev, plane); | 1224 | crtc = intel_get_crtc_for_plane(dev, plane); |
1218 | if (crtc->fb == NULL || !to_intel_crtc(crtc)->active) | 1225 | if (!intel_crtc_active(crtc)) |
1219 | return false; | 1226 | return false; |
1220 | 1227 | ||
1221 | clock = crtc->mode.clock; /* VESA DOT Clock */ | 1228 | clock = crtc->mode.clock; /* VESA DOT Clock */ |
@@ -1476,7 +1483,7 @@ static void i9xx_update_wm(struct drm_device *dev) | |||
1476 | 1483 | ||
1477 | fifo_size = dev_priv->display.get_fifo_size(dev, 0); | 1484 | fifo_size = dev_priv->display.get_fifo_size(dev, 0); |
1478 | crtc = intel_get_crtc_for_plane(dev, 0); | 1485 | crtc = intel_get_crtc_for_plane(dev, 0); |
1479 | if (to_intel_crtc(crtc)->active && crtc->fb) { | 1486 | if (intel_crtc_active(crtc)) { |
1480 | int cpp = crtc->fb->bits_per_pixel / 8; | 1487 | int cpp = crtc->fb->bits_per_pixel / 8; |
1481 | if (IS_GEN2(dev)) | 1488 | if (IS_GEN2(dev)) |
1482 | cpp = 4; | 1489 | cpp = 4; |
@@ -1490,7 +1497,7 @@ static void i9xx_update_wm(struct drm_device *dev) | |||
1490 | 1497 | ||
1491 | fifo_size = dev_priv->display.get_fifo_size(dev, 1); | 1498 | fifo_size = dev_priv->display.get_fifo_size(dev, 1); |
1492 | crtc = intel_get_crtc_for_plane(dev, 1); | 1499 | crtc = intel_get_crtc_for_plane(dev, 1); |
1493 | if (to_intel_crtc(crtc)->active && crtc->fb) { | 1500 | if (intel_crtc_active(crtc)) { |
1494 | int cpp = crtc->fb->bits_per_pixel / 8; | 1501 | int cpp = crtc->fb->bits_per_pixel / 8; |
1495 | if (IS_GEN2(dev)) | 1502 | if (IS_GEN2(dev)) |
1496 | cpp = 4; | 1503 | cpp = 4; |
@@ -2044,7 +2051,7 @@ sandybridge_compute_sprite_wm(struct drm_device *dev, int plane, | |||
2044 | int entries, tlb_miss; | 2051 | int entries, tlb_miss; |
2045 | 2052 | ||
2046 | crtc = intel_get_crtc_for_plane(dev, plane); | 2053 | crtc = intel_get_crtc_for_plane(dev, plane); |
2047 | if (crtc->fb == NULL || !to_intel_crtc(crtc)->active) { | 2054 | if (!intel_crtc_active(crtc)) { |
2048 | *sprite_wm = display->guard_size; | 2055 | *sprite_wm = display->guard_size; |
2049 | return false; | 2056 | return false; |
2050 | } | 2057 | } |
@@ -4243,7 +4250,8 @@ static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) | |||
4243 | static void __gen6_gt_force_wake_mt_reset(struct drm_i915_private *dev_priv) | 4250 | static void __gen6_gt_force_wake_mt_reset(struct drm_i915_private *dev_priv) |
4244 | { | 4251 | { |
4245 | I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_DISABLE(0xffff)); | 4252 | I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_DISABLE(0xffff)); |
4246 | POSTING_READ(ECOBUS); /* something from same cacheline, but !FORCEWAKE */ | 4253 | /* something from same cacheline, but !FORCEWAKE_MT */ |
4254 | POSTING_READ(ECOBUS); | ||
4247 | } | 4255 | } |
4248 | 4256 | ||
4249 | static void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv) | 4257 | static void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv) |
@@ -4260,7 +4268,8 @@ static void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv) | |||
4260 | DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n"); | 4268 | DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n"); |
4261 | 4269 | ||
4262 | I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL)); | 4270 | I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL)); |
4263 | POSTING_READ(ECOBUS); /* something from same cacheline, but !FORCEWAKE */ | 4271 | /* something from same cacheline, but !FORCEWAKE_MT */ |
4272 | POSTING_READ(ECOBUS); | ||
4264 | 4273 | ||
4265 | if (wait_for_atomic((I915_READ_NOTRACE(forcewake_ack) & 1), | 4274 | if (wait_for_atomic((I915_READ_NOTRACE(forcewake_ack) & 1), |
4266 | FORCEWAKE_ACK_TIMEOUT_MS)) | 4275 | FORCEWAKE_ACK_TIMEOUT_MS)) |
@@ -4297,14 +4306,16 @@ void gen6_gt_check_fifodbg(struct drm_i915_private *dev_priv) | |||
4297 | static void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) | 4306 | static void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) |
4298 | { | 4307 | { |
4299 | I915_WRITE_NOTRACE(FORCEWAKE, 0); | 4308 | I915_WRITE_NOTRACE(FORCEWAKE, 0); |
4300 | /* gen6_gt_check_fifodbg doubles as the POSTING_READ */ | 4309 | /* something from same cacheline, but !FORCEWAKE */ |
4310 | POSTING_READ(ECOBUS); | ||
4301 | gen6_gt_check_fifodbg(dev_priv); | 4311 | gen6_gt_check_fifodbg(dev_priv); |
4302 | } | 4312 | } |
4303 | 4313 | ||
4304 | static void __gen6_gt_force_wake_mt_put(struct drm_i915_private *dev_priv) | 4314 | static void __gen6_gt_force_wake_mt_put(struct drm_i915_private *dev_priv) |
4305 | { | 4315 | { |
4306 | I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL)); | 4316 | I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL)); |
4307 | /* gen6_gt_check_fifodbg doubles as the POSTING_READ */ | 4317 | /* something from same cacheline, but !FORCEWAKE_MT */ |
4318 | POSTING_READ(ECOBUS); | ||
4308 | gen6_gt_check_fifodbg(dev_priv); | 4319 | gen6_gt_check_fifodbg(dev_priv); |
4309 | } | 4320 | } |
4310 | 4321 | ||
@@ -4344,6 +4355,8 @@ int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv) | |||
4344 | static void vlv_force_wake_reset(struct drm_i915_private *dev_priv) | 4355 | static void vlv_force_wake_reset(struct drm_i915_private *dev_priv) |
4345 | { | 4356 | { |
4346 | I915_WRITE_NOTRACE(FORCEWAKE_VLV, _MASKED_BIT_DISABLE(0xffff)); | 4357 | I915_WRITE_NOTRACE(FORCEWAKE_VLV, _MASKED_BIT_DISABLE(0xffff)); |
4358 | /* something from same cacheline, but !FORCEWAKE_VLV */ | ||
4359 | POSTING_READ(FORCEWAKE_ACK_VLV); | ||
4347 | } | 4360 | } |
4348 | 4361 | ||
4349 | static void vlv_force_wake_get(struct drm_i915_private *dev_priv) | 4362 | static void vlv_force_wake_get(struct drm_i915_private *dev_priv) |
@@ -4364,7 +4377,8 @@ static void vlv_force_wake_get(struct drm_i915_private *dev_priv) | |||
4364 | static void vlv_force_wake_put(struct drm_i915_private *dev_priv) | 4377 | static void vlv_force_wake_put(struct drm_i915_private *dev_priv) |
4365 | { | 4378 | { |
4366 | I915_WRITE_NOTRACE(FORCEWAKE_VLV, _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL)); | 4379 | I915_WRITE_NOTRACE(FORCEWAKE_VLV, _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL)); |
4367 | /* The below doubles as a POSTING_READ */ | 4380 | /* something from same cacheline, but !FORCEWAKE_VLV */ |
4381 | POSTING_READ(FORCEWAKE_ACK_VLV); | ||
4368 | gen6_gt_check_fifodbg(dev_priv); | 4382 | gen6_gt_check_fifodbg(dev_priv); |
4369 | } | 4383 | } |
4370 | 4384 | ||
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 827dcd4edf1c..d7b060e0a231 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c | |||
@@ -120,11 +120,10 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, | |||
120 | I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]); | 120 | I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]); |
121 | I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x); | 121 | I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x); |
122 | 122 | ||
123 | linear_offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8); | 123 | linear_offset = y * fb->pitches[0] + x * pixel_size; |
124 | sprsurf_offset = | 124 | sprsurf_offset = |
125 | intel_gen4_compute_offset_xtiled(&x, &y, | 125 | intel_gen4_compute_offset_xtiled(&x, &y, |
126 | fb->bits_per_pixel / 8, | 126 | pixel_size, fb->pitches[0]); |
127 | fb->pitches[0]); | ||
128 | linear_offset -= sprsurf_offset; | 127 | linear_offset -= sprsurf_offset; |
129 | 128 | ||
130 | /* HSW consolidates SPRTILEOFF and SPRLINOFF into a single SPROFFSET | 129 | /* HSW consolidates SPRTILEOFF and SPRLINOFF into a single SPROFFSET |
@@ -286,11 +285,10 @@ ilk_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, | |||
286 | I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]); | 285 | I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]); |
287 | I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x); | 286 | I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x); |
288 | 287 | ||
289 | linear_offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8); | 288 | linear_offset = y * fb->pitches[0] + x * pixel_size; |
290 | dvssurf_offset = | 289 | dvssurf_offset = |
291 | intel_gen4_compute_offset_xtiled(&x, &y, | 290 | intel_gen4_compute_offset_xtiled(&x, &y, |
292 | fb->bits_per_pixel / 8, | 291 | pixel_size, fb->pitches[0]); |
293 | fb->pitches[0]); | ||
294 | linear_offset -= dvssurf_offset; | 292 | linear_offset -= dvssurf_offset; |
295 | 293 | ||
296 | if (obj->tiling_mode != I915_TILING_NONE) | 294 | if (obj->tiling_mode != I915_TILING_NONE) |
diff --git a/drivers/gpu/drm/nouveau/core/core/client.c b/drivers/gpu/drm/nouveau/core/core/client.c index c617f0480071..8bbb58f94a19 100644 --- a/drivers/gpu/drm/nouveau/core/core/client.c +++ b/drivers/gpu/drm/nouveau/core/core/client.c | |||
@@ -66,10 +66,8 @@ nouveau_client_create_(const char *name, u64 devname, const char *cfg, | |||
66 | 66 | ||
67 | ret = nouveau_handle_create(nv_object(client), ~0, ~0, | 67 | ret = nouveau_handle_create(nv_object(client), ~0, ~0, |
68 | nv_object(client), &client->root); | 68 | nv_object(client), &client->root); |
69 | if (ret) { | 69 | if (ret) |
70 | nouveau_namedb_destroy(&client->base); | ||
71 | return ret; | 70 | return ret; |
72 | } | ||
73 | 71 | ||
74 | /* prevent init/fini being called, os in in charge of this */ | 72 | /* prevent init/fini being called, os in in charge of this */ |
75 | atomic_set(&nv_object(client)->usecount, 2); | 73 | atomic_set(&nv_object(client)->usecount, 2); |
diff --git a/drivers/gpu/drm/nouveau/core/core/handle.c b/drivers/gpu/drm/nouveau/core/core/handle.c index b8d2cbf8a7a7..264c2b338ac3 100644 --- a/drivers/gpu/drm/nouveau/core/core/handle.c +++ b/drivers/gpu/drm/nouveau/core/core/handle.c | |||
@@ -109,7 +109,7 @@ nouveau_handle_create(struct nouveau_object *parent, u32 _parent, u32 _handle, | |||
109 | while (!nv_iclass(namedb, NV_NAMEDB_CLASS)) | 109 | while (!nv_iclass(namedb, NV_NAMEDB_CLASS)) |
110 | namedb = namedb->parent; | 110 | namedb = namedb->parent; |
111 | 111 | ||
112 | handle = *phandle = kzalloc(sizeof(*handle), GFP_KERNEL); | 112 | handle = kzalloc(sizeof(*handle), GFP_KERNEL); |
113 | if (!handle) | 113 | if (!handle) |
114 | return -ENOMEM; | 114 | return -ENOMEM; |
115 | 115 | ||
@@ -146,6 +146,9 @@ nouveau_handle_create(struct nouveau_object *parent, u32 _parent, u32 _handle, | |||
146 | } | 146 | } |
147 | 147 | ||
148 | hprintk(handle, TRACE, "created\n"); | 148 | hprintk(handle, TRACE, "created\n"); |
149 | |||
150 | *phandle = handle; | ||
151 | |||
149 | return 0; | 152 | return 0; |
150 | } | 153 | } |
151 | 154 | ||
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c index 0f09af135415..ca1a7d76a95b 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c | |||
@@ -851,20 +851,23 @@ exec_script(struct nv50_disp_priv *priv, int head, int id) | |||
851 | for (i = 0; !(ctrl & (1 << head)) && i < 3; i++) | 851 | for (i = 0; !(ctrl & (1 << head)) && i < 3; i++) |
852 | ctrl = nv_rd32(priv, 0x610b5c + (i * 8)); | 852 | ctrl = nv_rd32(priv, 0x610b5c + (i * 8)); |
853 | 853 | ||
854 | if (nv_device(priv)->chipset < 0x90 || | 854 | if (!(ctrl & (1 << head))) { |
855 | nv_device(priv)->chipset == 0x92 || | 855 | if (nv_device(priv)->chipset < 0x90 || |
856 | nv_device(priv)->chipset == 0xa0) { | 856 | nv_device(priv)->chipset == 0x92 || |
857 | for (i = 0; !(ctrl & (1 << head)) && i < 2; i++) | 857 | nv_device(priv)->chipset == 0xa0) { |
858 | ctrl = nv_rd32(priv, 0x610b74 + (i * 8)); | 858 | for (i = 0; !(ctrl & (1 << head)) && i < 2; i++) |
859 | i += 3; | 859 | ctrl = nv_rd32(priv, 0x610b74 + (i * 8)); |
860 | } else { | 860 | i += 4; |
861 | for (i = 0; !(ctrl & (1 << head)) && i < 4; i++) | 861 | } else { |
862 | ctrl = nv_rd32(priv, 0x610798 + (i * 8)); | 862 | for (i = 0; !(ctrl & (1 << head)) && i < 4; i++) |
863 | i += 3; | 863 | ctrl = nv_rd32(priv, 0x610798 + (i * 8)); |
864 | i += 4; | ||
865 | } | ||
864 | } | 866 | } |
865 | 867 | ||
866 | if (!(ctrl & (1 << head))) | 868 | if (!(ctrl & (1 << head))) |
867 | return false; | 869 | return false; |
870 | i--; | ||
868 | 871 | ||
869 | data = exec_lookup(priv, head, i, ctrl, &dcb, &ver, &hdr, &cnt, &len, &info); | 872 | data = exec_lookup(priv, head, i, ctrl, &dcb, &ver, &hdr, &cnt, &len, &info); |
870 | if (data) { | 873 | if (data) { |
@@ -898,20 +901,23 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, | |||
898 | for (i = 0; !(ctrl & (1 << head)) && i < 3; i++) | 901 | for (i = 0; !(ctrl & (1 << head)) && i < 3; i++) |
899 | ctrl = nv_rd32(priv, 0x610b58 + (i * 8)); | 902 | ctrl = nv_rd32(priv, 0x610b58 + (i * 8)); |
900 | 903 | ||
901 | if (nv_device(priv)->chipset < 0x90 || | 904 | if (!(ctrl & (1 << head))) { |
902 | nv_device(priv)->chipset == 0x92 || | 905 | if (nv_device(priv)->chipset < 0x90 || |
903 | nv_device(priv)->chipset == 0xa0) { | 906 | nv_device(priv)->chipset == 0x92 || |
904 | for (i = 0; !(ctrl & (1 << head)) && i < 2; i++) | 907 | nv_device(priv)->chipset == 0xa0) { |
905 | ctrl = nv_rd32(priv, 0x610b70 + (i * 8)); | 908 | for (i = 0; !(ctrl & (1 << head)) && i < 2; i++) |
906 | i += 3; | 909 | ctrl = nv_rd32(priv, 0x610b70 + (i * 8)); |
907 | } else { | 910 | i += 4; |
908 | for (i = 0; !(ctrl & (1 << head)) && i < 4; i++) | 911 | } else { |
909 | ctrl = nv_rd32(priv, 0x610794 + (i * 8)); | 912 | for (i = 0; !(ctrl & (1 << head)) && i < 4; i++) |
910 | i += 3; | 913 | ctrl = nv_rd32(priv, 0x610794 + (i * 8)); |
914 | i += 4; | ||
915 | } | ||
911 | } | 916 | } |
912 | 917 | ||
913 | if (!(ctrl & (1 << head))) | 918 | if (!(ctrl & (1 << head))) |
914 | return 0x0000; | 919 | return 0x0000; |
920 | i--; | ||
915 | 921 | ||
916 | data = exec_lookup(priv, head, i, ctrl, outp, &ver, &hdr, &cnt, &len, &info1); | 922 | data = exec_lookup(priv, head, i, ctrl, outp, &ver, &hdr, &cnt, &len, &info1); |
917 | if (!data) | 923 | if (!data) |
diff --git a/drivers/gpu/drm/nouveau/core/include/core/client.h b/drivers/gpu/drm/nouveau/core/include/core/client.h index 0193532ceac9..63acc0346ff2 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/client.h +++ b/drivers/gpu/drm/nouveau/core/include/core/client.h | |||
@@ -36,6 +36,9 @@ nouveau_client(void *obj) | |||
36 | 36 | ||
37 | int nouveau_client_create_(const char *name, u64 device, const char *cfg, | 37 | int nouveau_client_create_(const char *name, u64 device, const char *cfg, |
38 | const char *dbg, int, void **); | 38 | const char *dbg, int, void **); |
39 | #define nouveau_client_destroy(p) \ | ||
40 | nouveau_namedb_destroy(&(p)->base) | ||
41 | |||
39 | int nouveau_client_init(struct nouveau_client *); | 42 | int nouveau_client_init(struct nouveau_client *); |
40 | int nouveau_client_fini(struct nouveau_client *, bool suspend); | 43 | int nouveau_client_fini(struct nouveau_client *, bool suspend); |
41 | 44 | ||
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/pll.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/pll.h index c345097592f2..b2f3d4d0aa49 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/pll.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/pll.h | |||
@@ -38,6 +38,8 @@ enum nvbios_pll_type { | |||
38 | PLL_UNK42 = 0x42, | 38 | PLL_UNK42 = 0x42, |
39 | PLL_VPLL0 = 0x80, | 39 | PLL_VPLL0 = 0x80, |
40 | PLL_VPLL1 = 0x81, | 40 | PLL_VPLL1 = 0x81, |
41 | PLL_VPLL2 = 0x82, | ||
42 | PLL_VPLL3 = 0x83, | ||
41 | PLL_MAX = 0xff | 43 | PLL_MAX = 0xff |
42 | }; | 44 | }; |
43 | 45 | ||
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c index 2917d552689b..690ed438b2ad 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c | |||
@@ -1534,7 +1534,6 @@ init_io(struct nvbios_init *init) | |||
1534 | mdelay(10); | 1534 | mdelay(10); |
1535 | init_wr32(init, 0x614100, 0x10000018); | 1535 | init_wr32(init, 0x614100, 0x10000018); |
1536 | init_wr32(init, 0x614900, 0x10000018); | 1536 | init_wr32(init, 0x614900, 0x10000018); |
1537 | return; | ||
1538 | } | 1537 | } |
1539 | 1538 | ||
1540 | value = init_rdport(init, port) & mask; | 1539 | value = init_rdport(init, port) & mask; |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c index f6962c9b6c36..7c9626258a46 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c | |||
@@ -52,6 +52,8 @@ nvc0_clock_pll_set(struct nouveau_clock *clk, u32 type, u32 freq) | |||
52 | switch (info.type) { | 52 | switch (info.type) { |
53 | case PLL_VPLL0: | 53 | case PLL_VPLL0: |
54 | case PLL_VPLL1: | 54 | case PLL_VPLL1: |
55 | case PLL_VPLL2: | ||
56 | case PLL_VPLL3: | ||
55 | nv_mask(priv, info.reg + 0x0c, 0x00000000, 0x00000100); | 57 | nv_mask(priv, info.reg + 0x0c, 0x00000000, 0x00000100); |
56 | nv_wr32(priv, info.reg + 0x04, (P << 16) | (N << 8) | M); | 58 | nv_wr32(priv, info.reg + 0x04, (P << 16) | (N << 8) | M); |
57 | nv_wr32(priv, info.reg + 0x10, fN << 16); | 59 | nv_wr32(priv, info.reg + 0x10, fN << 16); |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c index 306bdf121452..7606ed15b6fa 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c | |||
@@ -145,14 +145,14 @@ nvc0_fb_vram_new(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin, | |||
145 | mem->memtype = type; | 145 | mem->memtype = type; |
146 | mem->size = size; | 146 | mem->size = size; |
147 | 147 | ||
148 | mutex_lock(&mm->mutex); | 148 | mutex_lock(&pfb->base.mutex); |
149 | do { | 149 | do { |
150 | if (back) | 150 | if (back) |
151 | ret = nouveau_mm_tail(mm, 1, size, ncmin, align, &r); | 151 | ret = nouveau_mm_tail(mm, 1, size, ncmin, align, &r); |
152 | else | 152 | else |
153 | ret = nouveau_mm_head(mm, 1, size, ncmin, align, &r); | 153 | ret = nouveau_mm_head(mm, 1, size, ncmin, align, &r); |
154 | if (ret) { | 154 | if (ret) { |
155 | mutex_unlock(&mm->mutex); | 155 | mutex_unlock(&pfb->base.mutex); |
156 | pfb->ram.put(pfb, &mem); | 156 | pfb->ram.put(pfb, &mem); |
157 | return ret; | 157 | return ret; |
158 | } | 158 | } |
@@ -160,7 +160,7 @@ nvc0_fb_vram_new(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin, | |||
160 | list_add_tail(&r->rl_entry, &mem->regions); | 160 | list_add_tail(&r->rl_entry, &mem->regions); |
161 | size -= r->length; | 161 | size -= r->length; |
162 | } while (size); | 162 | } while (size); |
163 | mutex_unlock(&mm->mutex); | 163 | mutex_unlock(&pfb->base.mutex); |
164 | 164 | ||
165 | r = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry); | 165 | r = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry); |
166 | mem->offset = (u64)r->offset << 12; | 166 | mem->offset = (u64)r->offset << 12; |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/instmem/base.c b/drivers/gpu/drm/nouveau/core/subdev/instmem/base.c index 1188227ca6aa..6565f3dbbe04 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/instmem/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/instmem/base.c | |||
@@ -40,15 +40,21 @@ nouveau_instobj_create_(struct nouveau_object *parent, | |||
40 | if (ret) | 40 | if (ret) |
41 | return ret; | 41 | return ret; |
42 | 42 | ||
43 | mutex_lock(&imem->base.mutex); | ||
43 | list_add(&iobj->head, &imem->list); | 44 | list_add(&iobj->head, &imem->list); |
45 | mutex_unlock(&imem->base.mutex); | ||
44 | return 0; | 46 | return 0; |
45 | } | 47 | } |
46 | 48 | ||
47 | void | 49 | void |
48 | nouveau_instobj_destroy(struct nouveau_instobj *iobj) | 50 | nouveau_instobj_destroy(struct nouveau_instobj *iobj) |
49 | { | 51 | { |
50 | if (iobj->head.prev) | 52 | struct nouveau_subdev *subdev = nv_subdev(iobj->base.engine); |
51 | list_del(&iobj->head); | 53 | |
54 | mutex_lock(&subdev->mutex); | ||
55 | list_del(&iobj->head); | ||
56 | mutex_unlock(&subdev->mutex); | ||
57 | |||
52 | return nouveau_object_destroy(&iobj->base); | 58 | return nouveau_object_destroy(&iobj->base); |
53 | } | 59 | } |
54 | 60 | ||
@@ -88,6 +94,8 @@ nouveau_instmem_init(struct nouveau_instmem *imem) | |||
88 | if (ret) | 94 | if (ret) |
89 | return ret; | 95 | return ret; |
90 | 96 | ||
97 | mutex_lock(&imem->base.mutex); | ||
98 | |||
91 | list_for_each_entry(iobj, &imem->list, head) { | 99 | list_for_each_entry(iobj, &imem->list, head) { |
92 | if (iobj->suspend) { | 100 | if (iobj->suspend) { |
93 | for (i = 0; i < iobj->size; i += 4) | 101 | for (i = 0; i < iobj->size; i += 4) |
@@ -97,6 +105,8 @@ nouveau_instmem_init(struct nouveau_instmem *imem) | |||
97 | } | 105 | } |
98 | } | 106 | } |
99 | 107 | ||
108 | mutex_unlock(&imem->base.mutex); | ||
109 | |||
100 | return 0; | 110 | return 0; |
101 | } | 111 | } |
102 | 112 | ||
@@ -104,17 +114,26 @@ int | |||
104 | nouveau_instmem_fini(struct nouveau_instmem *imem, bool suspend) | 114 | nouveau_instmem_fini(struct nouveau_instmem *imem, bool suspend) |
105 | { | 115 | { |
106 | struct nouveau_instobj *iobj; | 116 | struct nouveau_instobj *iobj; |
107 | int i; | 117 | int i, ret = 0; |
108 | 118 | ||
109 | if (suspend) { | 119 | if (suspend) { |
120 | mutex_lock(&imem->base.mutex); | ||
121 | |||
110 | list_for_each_entry(iobj, &imem->list, head) { | 122 | list_for_each_entry(iobj, &imem->list, head) { |
111 | iobj->suspend = vmalloc(iobj->size); | 123 | iobj->suspend = vmalloc(iobj->size); |
112 | if (iobj->suspend) { | 124 | if (!iobj->suspend) { |
113 | for (i = 0; i < iobj->size; i += 4) | 125 | ret = -ENOMEM; |
114 | iobj->suspend[i / 4] = nv_ro32(iobj, i); | 126 | break; |
115 | } else | 127 | } |
116 | return -ENOMEM; | 128 | |
129 | for (i = 0; i < iobj->size; i += 4) | ||
130 | iobj->suspend[i / 4] = nv_ro32(iobj, i); | ||
117 | } | 131 | } |
132 | |||
133 | mutex_unlock(&imem->base.mutex); | ||
134 | |||
135 | if (ret) | ||
136 | return ret; | ||
118 | } | 137 | } |
119 | 138 | ||
120 | return nouveau_subdev_fini(&imem->base, suspend); | 139 | return nouveau_subdev_fini(&imem->base, suspend); |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/base.c b/drivers/gpu/drm/nouveau/core/subdev/vm/base.c index 082c11b75acb..77c67fc970e6 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/vm/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/vm/base.c | |||
@@ -352,7 +352,7 @@ nouveau_vm_create(struct nouveau_vmmgr *vmm, u64 offset, u64 length, | |||
352 | u64 mm_length = (offset + length) - mm_offset; | 352 | u64 mm_length = (offset + length) - mm_offset; |
353 | int ret; | 353 | int ret; |
354 | 354 | ||
355 | vm = *pvm = kzalloc(sizeof(*vm), GFP_KERNEL); | 355 | vm = kzalloc(sizeof(*vm), GFP_KERNEL); |
356 | if (!vm) | 356 | if (!vm) |
357 | return -ENOMEM; | 357 | return -ENOMEM; |
358 | 358 | ||
@@ -376,6 +376,8 @@ nouveau_vm_create(struct nouveau_vmmgr *vmm, u64 offset, u64 length, | |||
376 | return ret; | 376 | return ret; |
377 | } | 377 | } |
378 | 378 | ||
379 | *pvm = vm; | ||
380 | |||
379 | return 0; | 381 | return 0; |
380 | } | 382 | } |
381 | 383 | ||
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index ac340ba32017..e620ba8271b4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c | |||
@@ -127,12 +127,26 @@ nouveau_connector_ddc_detect(struct drm_connector *connector, | |||
127 | struct nouveau_encoder **pnv_encoder) | 127 | struct nouveau_encoder **pnv_encoder) |
128 | { | 128 | { |
129 | struct drm_device *dev = connector->dev; | 129 | struct drm_device *dev = connector->dev; |
130 | struct nouveau_connector *nv_connector = nouveau_connector(connector); | ||
130 | struct nouveau_drm *drm = nouveau_drm(dev); | 131 | struct nouveau_drm *drm = nouveau_drm(dev); |
132 | struct nouveau_gpio *gpio = nouveau_gpio(drm->device); | ||
131 | struct nouveau_i2c *i2c = nouveau_i2c(drm->device); | 133 | struct nouveau_i2c *i2c = nouveau_i2c(drm->device); |
132 | int i; | 134 | struct nouveau_i2c_port *port = NULL; |
135 | int i, panel = -ENODEV; | ||
136 | |||
137 | /* eDP panels need powering on by us (if the VBIOS doesn't default it | ||
138 | * to on) before doing any AUX channel transactions. LVDS panel power | ||
139 | * is handled by the SOR itself, and not required for LVDS DDC. | ||
140 | */ | ||
141 | if (nv_connector->type == DCB_CONNECTOR_eDP) { | ||
142 | panel = gpio->get(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff); | ||
143 | if (panel == 0) { | ||
144 | gpio->set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, 1); | ||
145 | msleep(300); | ||
146 | } | ||
147 | } | ||
133 | 148 | ||
134 | for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { | 149 | for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { |
135 | struct nouveau_i2c_port *port = NULL; | ||
136 | struct nouveau_encoder *nv_encoder; | 150 | struct nouveau_encoder *nv_encoder; |
137 | struct drm_mode_object *obj; | 151 | struct drm_mode_object *obj; |
138 | int id; | 152 | int id; |
@@ -150,11 +164,19 @@ nouveau_connector_ddc_detect(struct drm_connector *connector, | |||
150 | port = i2c->find(i2c, nv_encoder->dcb->i2c_index); | 164 | port = i2c->find(i2c, nv_encoder->dcb->i2c_index); |
151 | if (port && nv_probe_i2c(port, 0x50)) { | 165 | if (port && nv_probe_i2c(port, 0x50)) { |
152 | *pnv_encoder = nv_encoder; | 166 | *pnv_encoder = nv_encoder; |
153 | return port; | 167 | break; |
154 | } | 168 | } |
169 | |||
170 | port = NULL; | ||
155 | } | 171 | } |
156 | 172 | ||
157 | return NULL; | 173 | /* eDP panel not detected, restore panel power GPIO to previous |
174 | * state to avoid confusing the SOR for other output types. | ||
175 | */ | ||
176 | if (!port && panel == 0) | ||
177 | gpio->set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, panel); | ||
178 | |||
179 | return port; | ||
158 | } | 180 | } |
159 | 181 | ||
160 | static struct nouveau_encoder * | 182 | static struct nouveau_encoder * |
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index e4188f24fc75..508b00a2ce0d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c | |||
@@ -225,15 +225,6 @@ nouveau_display_init(struct drm_device *dev) | |||
225 | if (ret) | 225 | if (ret) |
226 | return ret; | 226 | return ret; |
227 | 227 | ||
228 | /* power on internal panel if it's not already. the init tables of | ||
229 | * some vbios default this to off for some reason, causing the | ||
230 | * panel to not work after resume | ||
231 | */ | ||
232 | if (gpio && gpio->get(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff) == 0) { | ||
233 | gpio->set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, 1); | ||
234 | msleep(300); | ||
235 | } | ||
236 | |||
237 | /* enable polling for external displays */ | 228 | /* enable polling for external displays */ |
238 | drm_kms_helper_poll_enable(dev); | 229 | drm_kms_helper_poll_enable(dev); |
239 | 230 | ||
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 180a45e3b525..8b090f1eb51d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c | |||
@@ -84,11 +84,16 @@ nouveau_cli_create(struct pci_dev *pdev, const char *name, | |||
84 | struct nouveau_cli *cli; | 84 | struct nouveau_cli *cli; |
85 | int ret; | 85 | int ret; |
86 | 86 | ||
87 | *pcli = NULL; | ||
87 | ret = nouveau_client_create_(name, nouveau_name(pdev), nouveau_config, | 88 | ret = nouveau_client_create_(name, nouveau_name(pdev), nouveau_config, |
88 | nouveau_debug, size, pcli); | 89 | nouveau_debug, size, pcli); |
89 | cli = *pcli; | 90 | cli = *pcli; |
90 | if (ret) | 91 | if (ret) { |
92 | if (cli) | ||
93 | nouveau_client_destroy(&cli->base); | ||
94 | *pcli = NULL; | ||
91 | return ret; | 95 | return ret; |
96 | } | ||
92 | 97 | ||
93 | mutex_init(&cli->mutex); | 98 | mutex_init(&cli->mutex); |
94 | return 0; | 99 | return 0; |
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.h b/drivers/gpu/drm/nouveau/nouveau_fence.h index bedafd1c9539..cdb83acdffe2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.h +++ b/drivers/gpu/drm/nouveau/nouveau_fence.h | |||
@@ -60,6 +60,7 @@ u32 nv10_fence_read(struct nouveau_channel *); | |||
60 | void nv10_fence_context_del(struct nouveau_channel *); | 60 | void nv10_fence_context_del(struct nouveau_channel *); |
61 | void nv10_fence_destroy(struct nouveau_drm *); | 61 | void nv10_fence_destroy(struct nouveau_drm *); |
62 | int nv10_fence_create(struct nouveau_drm *); | 62 | int nv10_fence_create(struct nouveau_drm *); |
63 | void nv17_fence_resume(struct nouveau_drm *drm); | ||
63 | 64 | ||
64 | int nv50_fence_create(struct nouveau_drm *); | 65 | int nv50_fence_create(struct nouveau_drm *); |
65 | int nv84_fence_create(struct nouveau_drm *); | 66 | int nv84_fence_create(struct nouveau_drm *); |
diff --git a/drivers/gpu/drm/nouveau/nv04_dfp.c b/drivers/gpu/drm/nouveau/nv04_dfp.c index 184cdf806761..39ffc07f906b 100644 --- a/drivers/gpu/drm/nouveau/nv04_dfp.c +++ b/drivers/gpu/drm/nouveau/nv04_dfp.c | |||
@@ -505,7 +505,7 @@ static void nv04_dfp_update_backlight(struct drm_encoder *encoder, int mode) | |||
505 | 505 | ||
506 | static inline bool is_powersaving_dpms(int mode) | 506 | static inline bool is_powersaving_dpms(int mode) |
507 | { | 507 | { |
508 | return (mode != DRM_MODE_DPMS_ON); | 508 | return mode != DRM_MODE_DPMS_ON && mode != NV_DPMS_CLEARED; |
509 | } | 509 | } |
510 | 510 | ||
511 | static void nv04_lvds_dpms(struct drm_encoder *encoder, int mode) | 511 | static void nv04_lvds_dpms(struct drm_encoder *encoder, int mode) |
diff --git a/drivers/gpu/drm/nouveau/nv10_fence.c b/drivers/gpu/drm/nouveau/nv10_fence.c index 7ae7f97a6d4d..03017f24d593 100644 --- a/drivers/gpu/drm/nouveau/nv10_fence.c +++ b/drivers/gpu/drm/nouveau/nv10_fence.c | |||
@@ -162,6 +162,13 @@ nv10_fence_destroy(struct nouveau_drm *drm) | |||
162 | kfree(priv); | 162 | kfree(priv); |
163 | } | 163 | } |
164 | 164 | ||
165 | void nv17_fence_resume(struct nouveau_drm *drm) | ||
166 | { | ||
167 | struct nv10_fence_priv *priv = drm->fence; | ||
168 | |||
169 | nouveau_bo_wr32(priv->bo, 0, priv->sequence); | ||
170 | } | ||
171 | |||
165 | int | 172 | int |
166 | nv10_fence_create(struct nouveau_drm *drm) | 173 | nv10_fence_create(struct nouveau_drm *drm) |
167 | { | 174 | { |
@@ -197,6 +204,7 @@ nv10_fence_create(struct nouveau_drm *drm) | |||
197 | if (ret == 0) { | 204 | if (ret == 0) { |
198 | nouveau_bo_wr32(priv->bo, 0x000, 0x00000000); | 205 | nouveau_bo_wr32(priv->bo, 0x000, 0x00000000); |
199 | priv->base.sync = nv17_fence_sync; | 206 | priv->base.sync = nv17_fence_sync; |
207 | priv->base.resume = nv17_fence_resume; | ||
200 | } | 208 | } |
201 | } | 209 | } |
202 | 210 | ||
diff --git a/drivers/gpu/drm/nouveau/nv50_fence.c b/drivers/gpu/drm/nouveau/nv50_fence.c index c20f2727ea0b..d889f3ac0d41 100644 --- a/drivers/gpu/drm/nouveau/nv50_fence.c +++ b/drivers/gpu/drm/nouveau/nv50_fence.c | |||
@@ -122,6 +122,7 @@ nv50_fence_create(struct nouveau_drm *drm) | |||
122 | if (ret == 0) { | 122 | if (ret == 0) { |
123 | nouveau_bo_wr32(priv->bo, 0x000, 0x00000000); | 123 | nouveau_bo_wr32(priv->bo, 0x000, 0x00000000); |
124 | priv->base.sync = nv17_fence_sync; | 124 | priv->base.sync = nv17_fence_sync; |
125 | priv->base.resume = nv17_fence_resume; | ||
125 | } | 126 | } |
126 | 127 | ||
127 | if (ret) | 128 | if (ret) |
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 061fa0a28900..4d0e60adbc6d 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c | |||
@@ -2401,6 +2401,12 @@ static int evergreen_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask) | |||
2401 | { | 2401 | { |
2402 | struct evergreen_mc_save save; | 2402 | struct evergreen_mc_save save; |
2403 | 2403 | ||
2404 | if (!(RREG32(GRBM_STATUS) & GUI_ACTIVE)) | ||
2405 | reset_mask &= ~(RADEON_RESET_GFX | RADEON_RESET_COMPUTE); | ||
2406 | |||
2407 | if (RREG32(DMA_STATUS_REG) & DMA_IDLE) | ||
2408 | reset_mask &= ~RADEON_RESET_DMA; | ||
2409 | |||
2404 | if (reset_mask == 0) | 2410 | if (reset_mask == 0) |
2405 | return 0; | 2411 | return 0; |
2406 | 2412 | ||
diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index 896f1cbc58a5..59acabb45c9b 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c | |||
@@ -1409,6 +1409,12 @@ static int cayman_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask) | |||
1409 | { | 1409 | { |
1410 | struct evergreen_mc_save save; | 1410 | struct evergreen_mc_save save; |
1411 | 1411 | ||
1412 | if (!(RREG32(GRBM_STATUS) & GUI_ACTIVE)) | ||
1413 | reset_mask &= ~(RADEON_RESET_GFX | RADEON_RESET_COMPUTE); | ||
1414 | |||
1415 | if (RREG32(DMA_STATUS_REG) & DMA_IDLE) | ||
1416 | reset_mask &= ~RADEON_RESET_DMA; | ||
1417 | |||
1412 | if (reset_mask == 0) | 1418 | if (reset_mask == 0) |
1413 | return 0; | 1419 | return 0; |
1414 | 1420 | ||
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 537e259b3837..3cb9d6089373 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c | |||
@@ -1378,6 +1378,12 @@ static int r600_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask) | |||
1378 | { | 1378 | { |
1379 | struct rv515_mc_save save; | 1379 | struct rv515_mc_save save; |
1380 | 1380 | ||
1381 | if (!(RREG32(GRBM_STATUS) & GUI_ACTIVE)) | ||
1382 | reset_mask &= ~(RADEON_RESET_GFX | RADEON_RESET_COMPUTE); | ||
1383 | |||
1384 | if (RREG32(DMA_STATUS_REG) & DMA_IDLE) | ||
1385 | reset_mask &= ~RADEON_RESET_DMA; | ||
1386 | |||
1381 | if (reset_mask == 0) | 1387 | if (reset_mask == 0) |
1382 | return 0; | 1388 | return 0; |
1383 | 1389 | ||
diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c index 03191a56eb44..69ec24ab8d63 100644 --- a/drivers/gpu/drm/radeon/r600_cs.c +++ b/drivers/gpu/drm/radeon/r600_cs.c | |||
@@ -2476,8 +2476,10 @@ static void r600_cs_parser_fini(struct radeon_cs_parser *parser, int error) | |||
2476 | kfree(parser->relocs); | 2476 | kfree(parser->relocs); |
2477 | for (i = 0; i < parser->nchunks; i++) { | 2477 | for (i = 0; i < parser->nchunks; i++) { |
2478 | kfree(parser->chunks[i].kdata); | 2478 | kfree(parser->chunks[i].kdata); |
2479 | kfree(parser->chunks[i].kpage[0]); | 2479 | if (parser->rdev && (parser->rdev->flags & RADEON_IS_AGP)) { |
2480 | kfree(parser->chunks[i].kpage[1]); | 2480 | kfree(parser->chunks[i].kpage[0]); |
2481 | kfree(parser->chunks[i].kpage[1]); | ||
2482 | } | ||
2481 | } | 2483 | } |
2482 | kfree(parser->chunks); | 2484 | kfree(parser->chunks); |
2483 | kfree(parser->chunks_array); | 2485 | kfree(parser->chunks_array); |
@@ -2561,16 +2563,16 @@ int r600_dma_cs_next_reloc(struct radeon_cs_parser *p, | |||
2561 | struct radeon_cs_chunk *relocs_chunk; | 2563 | struct radeon_cs_chunk *relocs_chunk; |
2562 | unsigned idx; | 2564 | unsigned idx; |
2563 | 2565 | ||
2566 | *cs_reloc = NULL; | ||
2564 | if (p->chunk_relocs_idx == -1) { | 2567 | if (p->chunk_relocs_idx == -1) { |
2565 | DRM_ERROR("No relocation chunk !\n"); | 2568 | DRM_ERROR("No relocation chunk !\n"); |
2566 | return -EINVAL; | 2569 | return -EINVAL; |
2567 | } | 2570 | } |
2568 | *cs_reloc = NULL; | ||
2569 | relocs_chunk = &p->chunks[p->chunk_relocs_idx]; | 2571 | relocs_chunk = &p->chunks[p->chunk_relocs_idx]; |
2570 | idx = p->dma_reloc_idx; | 2572 | idx = p->dma_reloc_idx; |
2571 | if (idx >= relocs_chunk->length_dw) { | 2573 | if (idx >= p->nrelocs) { |
2572 | DRM_ERROR("Relocs at %d after relocations chunk end %d !\n", | 2574 | DRM_ERROR("Relocs at %d after relocations chunk end %d !\n", |
2573 | idx, relocs_chunk->length_dw); | 2575 | idx, p->nrelocs); |
2574 | return -EINVAL; | 2576 | return -EINVAL; |
2575 | } | 2577 | } |
2576 | *cs_reloc = p->relocs_ptr[idx]; | 2578 | *cs_reloc = p->relocs_ptr[idx]; |
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 34e52304a525..a08f657329a0 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h | |||
@@ -324,7 +324,6 @@ struct radeon_bo { | |||
324 | struct list_head list; | 324 | struct list_head list; |
325 | /* Protected by tbo.reserved */ | 325 | /* Protected by tbo.reserved */ |
326 | u32 placements[3]; | 326 | u32 placements[3]; |
327 | u32 busy_placements[3]; | ||
328 | struct ttm_placement placement; | 327 | struct ttm_placement placement; |
329 | struct ttm_buffer_object tbo; | 328 | struct ttm_buffer_object tbo; |
330 | struct ttm_bo_kmap_obj kmap; | 329 | struct ttm_bo_kmap_obj kmap; |
@@ -654,6 +653,8 @@ struct radeon_ring { | |||
654 | u32 ptr_reg_mask; | 653 | u32 ptr_reg_mask; |
655 | u32 nop; | 654 | u32 nop; |
656 | u32 idx; | 655 | u32 idx; |
656 | u64 last_semaphore_signal_addr; | ||
657 | u64 last_semaphore_wait_addr; | ||
657 | }; | 658 | }; |
658 | 659 | ||
659 | /* | 660 | /* |
diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index 396baba0141a..469661fd1903 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c | |||
@@ -279,13 +279,13 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data) | |||
279 | p->chunks[p->chunk_ib_idx].length_dw); | 279 | p->chunks[p->chunk_ib_idx].length_dw); |
280 | return -EINVAL; | 280 | return -EINVAL; |
281 | } | 281 | } |
282 | if ((p->rdev->flags & RADEON_IS_AGP)) { | 282 | if (p->rdev && (p->rdev->flags & RADEON_IS_AGP)) { |
283 | p->chunks[p->chunk_ib_idx].kpage[0] = kmalloc(PAGE_SIZE, GFP_KERNEL); | 283 | p->chunks[p->chunk_ib_idx].kpage[0] = kmalloc(PAGE_SIZE, GFP_KERNEL); |
284 | p->chunks[p->chunk_ib_idx].kpage[1] = kmalloc(PAGE_SIZE, GFP_KERNEL); | 284 | p->chunks[p->chunk_ib_idx].kpage[1] = kmalloc(PAGE_SIZE, GFP_KERNEL); |
285 | if (p->chunks[p->chunk_ib_idx].kpage[0] == NULL || | 285 | if (p->chunks[p->chunk_ib_idx].kpage[0] == NULL || |
286 | p->chunks[p->chunk_ib_idx].kpage[1] == NULL) { | 286 | p->chunks[p->chunk_ib_idx].kpage[1] == NULL) { |
287 | kfree(p->chunks[i].kpage[0]); | 287 | kfree(p->chunks[p->chunk_ib_idx].kpage[0]); |
288 | kfree(p->chunks[i].kpage[1]); | 288 | kfree(p->chunks[p->chunk_ib_idx].kpage[1]); |
289 | return -ENOMEM; | 289 | return -ENOMEM; |
290 | } | 290 | } |
291 | } | 291 | } |
@@ -583,7 +583,8 @@ static int radeon_cs_update_pages(struct radeon_cs_parser *p, int pg_idx) | |||
583 | struct radeon_cs_chunk *ibc = &p->chunks[p->chunk_ib_idx]; | 583 | struct radeon_cs_chunk *ibc = &p->chunks[p->chunk_ib_idx]; |
584 | int i; | 584 | int i; |
585 | int size = PAGE_SIZE; | 585 | int size = PAGE_SIZE; |
586 | bool copy1 = (p->rdev->flags & RADEON_IS_AGP) ? false : true; | 586 | bool copy1 = (p->rdev && (p->rdev->flags & RADEON_IS_AGP)) ? |
587 | false : true; | ||
587 | 588 | ||
588 | for (i = ibc->last_copied_page + 1; i < pg_idx; i++) { | 589 | for (i = ibc->last_copied_page + 1; i < pg_idx; i++) { |
589 | if (DRM_COPY_FROM_USER(p->ib.ptr + (i * (PAGE_SIZE/4)), | 590 | if (DRM_COPY_FROM_USER(p->ib.ptr + (i * (PAGE_SIZE/4)), |
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index dff6cf77f953..d9bf96ee299a 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c | |||
@@ -69,9 +69,10 @@ | |||
69 | * 2.26.0 - r600-eg: fix htile size computation | 69 | * 2.26.0 - r600-eg: fix htile size computation |
70 | * 2.27.0 - r600-SI: Add CS ioctl support for async DMA | 70 | * 2.27.0 - r600-SI: Add CS ioctl support for async DMA |
71 | * 2.28.0 - r600-eg: Add MEM_WRITE packet support | 71 | * 2.28.0 - r600-eg: Add MEM_WRITE packet support |
72 | * 2.29.0 - R500 FP16 color clear registers | ||
72 | */ | 73 | */ |
73 | #define KMS_DRIVER_MAJOR 2 | 74 | #define KMS_DRIVER_MAJOR 2 |
74 | #define KMS_DRIVER_MINOR 28 | 75 | #define KMS_DRIVER_MINOR 29 |
75 | #define KMS_DRIVER_PATCHLEVEL 0 | 76 | #define KMS_DRIVER_PATCHLEVEL 0 |
76 | int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags); | 77 | int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags); |
77 | int radeon_driver_unload_kms(struct drm_device *dev); | 78 | int radeon_driver_unload_kms(struct drm_device *dev); |
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c index f5ba2241dacc..62cd512f5c8d 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c | |||
@@ -640,6 +640,14 @@ static enum drm_connector_status radeon_legacy_primary_dac_detect(struct drm_enc | |||
640 | enum drm_connector_status found = connector_status_disconnected; | 640 | enum drm_connector_status found = connector_status_disconnected; |
641 | bool color = true; | 641 | bool color = true; |
642 | 642 | ||
643 | /* just don't bother on RN50 those chip are often connected to remoting | ||
644 | * console hw and often we get failure to load detect those. So to make | ||
645 | * everyone happy report the encoder as always connected. | ||
646 | */ | ||
647 | if (ASIC_IS_RN50(rdev)) { | ||
648 | return connector_status_connected; | ||
649 | } | ||
650 | |||
643 | /* save the regs we need */ | 651 | /* save the regs we need */ |
644 | vclk_ecp_cntl = RREG32_PLL(RADEON_VCLK_ECP_CNTL); | 652 | vclk_ecp_cntl = RREG32_PLL(RADEON_VCLK_ECP_CNTL); |
645 | crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL); | 653 | crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL); |
diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 883c95d8d90f..d3aface2d12d 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c | |||
@@ -84,6 +84,7 @@ void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain) | |||
84 | rbo->placement.fpfn = 0; | 84 | rbo->placement.fpfn = 0; |
85 | rbo->placement.lpfn = 0; | 85 | rbo->placement.lpfn = 0; |
86 | rbo->placement.placement = rbo->placements; | 86 | rbo->placement.placement = rbo->placements; |
87 | rbo->placement.busy_placement = rbo->placements; | ||
87 | if (domain & RADEON_GEM_DOMAIN_VRAM) | 88 | if (domain & RADEON_GEM_DOMAIN_VRAM) |
88 | rbo->placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | | 89 | rbo->placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | |
89 | TTM_PL_FLAG_VRAM; | 90 | TTM_PL_FLAG_VRAM; |
@@ -104,14 +105,6 @@ void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain) | |||
104 | if (!c) | 105 | if (!c) |
105 | rbo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; | 106 | rbo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; |
106 | rbo->placement.num_placement = c; | 107 | rbo->placement.num_placement = c; |
107 | |||
108 | c = 0; | ||
109 | rbo->placement.busy_placement = rbo->busy_placements; | ||
110 | if (rbo->rdev->flags & RADEON_IS_AGP) { | ||
111 | rbo->busy_placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_TT; | ||
112 | } else { | ||
113 | rbo->busy_placements[c++] = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_TT; | ||
114 | } | ||
115 | rbo->placement.num_busy_placement = c; | 108 | rbo->placement.num_busy_placement = c; |
116 | } | 109 | } |
117 | 110 | ||
@@ -357,6 +350,7 @@ int radeon_bo_list_validate(struct list_head *head) | |||
357 | { | 350 | { |
358 | struct radeon_bo_list *lobj; | 351 | struct radeon_bo_list *lobj; |
359 | struct radeon_bo *bo; | 352 | struct radeon_bo *bo; |
353 | u32 domain; | ||
360 | int r; | 354 | int r; |
361 | 355 | ||
362 | r = ttm_eu_reserve_buffers(head); | 356 | r = ttm_eu_reserve_buffers(head); |
@@ -366,9 +360,17 @@ int radeon_bo_list_validate(struct list_head *head) | |||
366 | list_for_each_entry(lobj, head, tv.head) { | 360 | list_for_each_entry(lobj, head, tv.head) { |
367 | bo = lobj->bo; | 361 | bo = lobj->bo; |
368 | if (!bo->pin_count) { | 362 | if (!bo->pin_count) { |
363 | domain = lobj->wdomain ? lobj->wdomain : lobj->rdomain; | ||
364 | |||
365 | retry: | ||
366 | radeon_ttm_placement_from_domain(bo, domain); | ||
369 | r = ttm_bo_validate(&bo->tbo, &bo->placement, | 367 | r = ttm_bo_validate(&bo->tbo, &bo->placement, |
370 | true, false); | 368 | true, false); |
371 | if (unlikely(r)) { | 369 | if (unlikely(r)) { |
370 | if (r != -ERESTARTSYS && domain == RADEON_GEM_DOMAIN_VRAM) { | ||
371 | domain |= RADEON_GEM_DOMAIN_GTT; | ||
372 | goto retry; | ||
373 | } | ||
372 | return r; | 374 | return r; |
373 | } | 375 | } |
374 | } | 376 | } |
diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index 141f2b6a9cf2..2430d80b1871 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c | |||
@@ -784,6 +784,8 @@ static int radeon_debugfs_ring_info(struct seq_file *m, void *data) | |||
784 | } | 784 | } |
785 | seq_printf(m, "driver's copy of the wptr: 0x%08x [%5d]\n", ring->wptr, ring->wptr); | 785 | seq_printf(m, "driver's copy of the wptr: 0x%08x [%5d]\n", ring->wptr, ring->wptr); |
786 | seq_printf(m, "driver's copy of the rptr: 0x%08x [%5d]\n", ring->rptr, ring->rptr); | 786 | seq_printf(m, "driver's copy of the rptr: 0x%08x [%5d]\n", ring->rptr, ring->rptr); |
787 | seq_printf(m, "last semaphore signal addr : 0x%016llx\n", ring->last_semaphore_signal_addr); | ||
788 | seq_printf(m, "last semaphore wait addr : 0x%016llx\n", ring->last_semaphore_wait_addr); | ||
787 | seq_printf(m, "%u free dwords in ring\n", ring->ring_free_dw); | 789 | seq_printf(m, "%u free dwords in ring\n", ring->ring_free_dw); |
788 | seq_printf(m, "%u dwords in ring\n", count); | 790 | seq_printf(m, "%u dwords in ring\n", count); |
789 | /* print 8 dw before current rptr as often it's the last executed | 791 | /* print 8 dw before current rptr as often it's the last executed |
diff --git a/drivers/gpu/drm/radeon/radeon_semaphore.c b/drivers/gpu/drm/radeon/radeon_semaphore.c index 97f3ece81cd2..8dcc20f53d73 100644 --- a/drivers/gpu/drm/radeon/radeon_semaphore.c +++ b/drivers/gpu/drm/radeon/radeon_semaphore.c | |||
@@ -95,6 +95,10 @@ int radeon_semaphore_sync_rings(struct radeon_device *rdev, | |||
95 | /* we assume caller has already allocated space on waiters ring */ | 95 | /* we assume caller has already allocated space on waiters ring */ |
96 | radeon_semaphore_emit_wait(rdev, waiter, semaphore); | 96 | radeon_semaphore_emit_wait(rdev, waiter, semaphore); |
97 | 97 | ||
98 | /* for debugging lockup only, used by sysfs debug files */ | ||
99 | rdev->ring[signaler].last_semaphore_signal_addr = semaphore->gpu_addr; | ||
100 | rdev->ring[waiter].last_semaphore_wait_addr = semaphore->gpu_addr; | ||
101 | |||
98 | return 0; | 102 | return 0; |
99 | } | 103 | } |
100 | 104 | ||
diff --git a/drivers/gpu/drm/radeon/reg_srcs/rv515 b/drivers/gpu/drm/radeon/reg_srcs/rv515 index 911a8fbd32bb..78d5e99d759d 100644 --- a/drivers/gpu/drm/radeon/reg_srcs/rv515 +++ b/drivers/gpu/drm/radeon/reg_srcs/rv515 | |||
@@ -324,6 +324,8 @@ rv515 0x6d40 | |||
324 | 0x46AC US_OUT_FMT_2 | 324 | 0x46AC US_OUT_FMT_2 |
325 | 0x46B0 US_OUT_FMT_3 | 325 | 0x46B0 US_OUT_FMT_3 |
326 | 0x46B4 US_W_FMT | 326 | 0x46B4 US_W_FMT |
327 | 0x46C0 RB3D_COLOR_CLEAR_VALUE_AR | ||
328 | 0x46C4 RB3D_COLOR_CLEAR_VALUE_GB | ||
327 | 0x4BC0 FG_FOG_BLEND | 329 | 0x4BC0 FG_FOG_BLEND |
328 | 0x4BC4 FG_FOG_FACTOR | 330 | 0x4BC4 FG_FOG_FACTOR |
329 | 0x4BC8 FG_FOG_COLOR_R | 331 | 0x4BC8 FG_FOG_COLOR_R |
diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 3240a3d64f30..ae8b48205a6c 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c | |||
@@ -2215,6 +2215,12 @@ static int si_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask) | |||
2215 | { | 2215 | { |
2216 | struct evergreen_mc_save save; | 2216 | struct evergreen_mc_save save; |
2217 | 2217 | ||
2218 | if (!(RREG32(GRBM_STATUS) & GUI_ACTIVE)) | ||
2219 | reset_mask &= ~(RADEON_RESET_GFX | RADEON_RESET_COMPUTE); | ||
2220 | |||
2221 | if (RREG32(DMA_STATUS_REG) & DMA_IDLE) | ||
2222 | reset_mask &= ~RADEON_RESET_DMA; | ||
2223 | |||
2218 | if (reset_mask == 0) | 2224 | if (reset_mask == 0) |
2219 | return 0; | 2225 | return 0; |
2220 | 2226 | ||
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 33d20be87db5..52b20b12c83a 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c | |||
@@ -434,6 +434,7 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo, | |||
434 | bo->mem = tmp_mem; | 434 | bo->mem = tmp_mem; |
435 | bdev->driver->move_notify(bo, mem); | 435 | bdev->driver->move_notify(bo, mem); |
436 | bo->mem = *mem; | 436 | bo->mem = *mem; |
437 | *mem = tmp_mem; | ||
437 | } | 438 | } |
438 | 439 | ||
439 | goto out_err; | 440 | goto out_err; |
diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c index d73d6e3e17b2..44420fca7dfa 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c | |||
@@ -344,8 +344,12 @@ int ttm_bo_move_memcpy(struct ttm_buffer_object *bo, | |||
344 | 344 | ||
345 | if (ttm->state == tt_unpopulated) { | 345 | if (ttm->state == tt_unpopulated) { |
346 | ret = ttm->bdev->driver->ttm_tt_populate(ttm); | 346 | ret = ttm->bdev->driver->ttm_tt_populate(ttm); |
347 | if (ret) | 347 | if (ret) { |
348 | /* if we fail here don't nuke the mm node | ||
349 | * as the bo still owns it */ | ||
350 | old_copy.mm_node = NULL; | ||
348 | goto out1; | 351 | goto out1; |
352 | } | ||
349 | } | 353 | } |
350 | 354 | ||
351 | add = 0; | 355 | add = 0; |
@@ -371,8 +375,11 @@ int ttm_bo_move_memcpy(struct ttm_buffer_object *bo, | |||
371 | prot); | 375 | prot); |
372 | } else | 376 | } else |
373 | ret = ttm_copy_io_page(new_iomap, old_iomap, page); | 377 | ret = ttm_copy_io_page(new_iomap, old_iomap, page); |
374 | if (ret) | 378 | if (ret) { |
379 | /* failing here, means keep old copy as-is */ | ||
380 | old_copy.mm_node = NULL; | ||
375 | goto out1; | 381 | goto out1; |
382 | } | ||
376 | } | 383 | } |
377 | mb(); | 384 | mb(); |
378 | out2: | 385 | out2: |
diff --git a/drivers/gpu/drm/udl/udl_connector.c b/drivers/gpu/drm/udl/udl_connector.c index 512f44add89f..fe5cdbcf2636 100644 --- a/drivers/gpu/drm/udl/udl_connector.c +++ b/drivers/gpu/drm/udl/udl_connector.c | |||
@@ -22,13 +22,17 @@ | |||
22 | static u8 *udl_get_edid(struct udl_device *udl) | 22 | static u8 *udl_get_edid(struct udl_device *udl) |
23 | { | 23 | { |
24 | u8 *block; | 24 | u8 *block; |
25 | char rbuf[3]; | 25 | char *rbuf; |
26 | int ret, i; | 26 | int ret, i; |
27 | 27 | ||
28 | block = kmalloc(EDID_LENGTH, GFP_KERNEL); | 28 | block = kmalloc(EDID_LENGTH, GFP_KERNEL); |
29 | if (block == NULL) | 29 | if (block == NULL) |
30 | return NULL; | 30 | return NULL; |
31 | 31 | ||
32 | rbuf = kmalloc(2, GFP_KERNEL); | ||
33 | if (rbuf == NULL) | ||
34 | goto error; | ||
35 | |||
32 | for (i = 0; i < EDID_LENGTH; i++) { | 36 | for (i = 0; i < EDID_LENGTH; i++) { |
33 | ret = usb_control_msg(udl->ddev->usbdev, | 37 | ret = usb_control_msg(udl->ddev->usbdev, |
34 | usb_rcvctrlpipe(udl->ddev->usbdev, 0), (0x02), | 38 | usb_rcvctrlpipe(udl->ddev->usbdev, 0), (0x02), |
@@ -36,16 +40,17 @@ static u8 *udl_get_edid(struct udl_device *udl) | |||
36 | HZ); | 40 | HZ); |
37 | if (ret < 1) { | 41 | if (ret < 1) { |
38 | DRM_ERROR("Read EDID byte %d failed err %x\n", i, ret); | 42 | DRM_ERROR("Read EDID byte %d failed err %x\n", i, ret); |
39 | i--; | ||
40 | goto error; | 43 | goto error; |
41 | } | 44 | } |
42 | block[i] = rbuf[1]; | 45 | block[i] = rbuf[1]; |
43 | } | 46 | } |
44 | 47 | ||
48 | kfree(rbuf); | ||
45 | return block; | 49 | return block; |
46 | 50 | ||
47 | error: | 51 | error: |
48 | kfree(block); | 52 | kfree(block); |
53 | kfree(rbuf); | ||
49 | return NULL; | 54 | return NULL; |
50 | } | 55 | } |
51 | 56 | ||
@@ -57,6 +62,14 @@ static int udl_get_modes(struct drm_connector *connector) | |||
57 | 62 | ||
58 | edid = (struct edid *)udl_get_edid(udl); | 63 | edid = (struct edid *)udl_get_edid(udl); |
59 | 64 | ||
65 | /* | ||
66 | * We only read the main block, but if the monitor reports extension | ||
67 | * blocks then the drm edid code expects them to be present, so patch | ||
68 | * the extension count to 0. | ||
69 | */ | ||
70 | edid->checksum += edid->extensions; | ||
71 | edid->extensions = 0; | ||
72 | |||
60 | drm_mode_connector_update_edid_property(connector, edid); | 73 | drm_mode_connector_update_edid_property(connector, edid); |
61 | ret = drm_add_edid_modes(connector, edid); | 74 | ret = drm_add_edid_modes(connector, edid); |
62 | kfree(edid); | 75 | kfree(edid); |
diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c index f6c0011a0337..dd289fd179ca 100644 --- a/drivers/hv/hv_balloon.c +++ b/drivers/hv/hv_balloon.c | |||
@@ -403,7 +403,7 @@ struct dm_info_header { | |||
403 | */ | 403 | */ |
404 | 404 | ||
405 | struct dm_info_msg { | 405 | struct dm_info_msg { |
406 | struct dm_info_header header; | 406 | struct dm_header hdr; |
407 | __u32 reserved; | 407 | __u32 reserved; |
408 | __u32 info_size; | 408 | __u32 info_size; |
409 | __u8 info[]; | 409 | __u8 info[]; |
@@ -503,13 +503,17 @@ static void hot_add_req(struct hv_dynmem_device *dm, struct dm_hot_add *msg) | |||
503 | 503 | ||
504 | static void process_info(struct hv_dynmem_device *dm, struct dm_info_msg *msg) | 504 | static void process_info(struct hv_dynmem_device *dm, struct dm_info_msg *msg) |
505 | { | 505 | { |
506 | switch (msg->header.type) { | 506 | struct dm_info_header *info_hdr; |
507 | |||
508 | info_hdr = (struct dm_info_header *)msg->info; | ||
509 | |||
510 | switch (info_hdr->type) { | ||
507 | case INFO_TYPE_MAX_PAGE_CNT: | 511 | case INFO_TYPE_MAX_PAGE_CNT: |
508 | pr_info("Received INFO_TYPE_MAX_PAGE_CNT\n"); | 512 | pr_info("Received INFO_TYPE_MAX_PAGE_CNT\n"); |
509 | pr_info("Data Size is %d\n", msg->header.data_size); | 513 | pr_info("Data Size is %d\n", info_hdr->data_size); |
510 | break; | 514 | break; |
511 | default: | 515 | default: |
512 | pr_info("Received Unknown type: %d\n", msg->header.type); | 516 | pr_info("Received Unknown type: %d\n", info_hdr->type); |
513 | } | 517 | } |
514 | } | 518 | } |
515 | 519 | ||
@@ -879,7 +883,7 @@ static int balloon_probe(struct hv_device *dev, | |||
879 | balloon_onchannelcallback, dev); | 883 | balloon_onchannelcallback, dev); |
880 | 884 | ||
881 | if (ret) | 885 | if (ret) |
882 | return ret; | 886 | goto probe_error0; |
883 | 887 | ||
884 | dm_device.dev = dev; | 888 | dm_device.dev = dev; |
885 | dm_device.state = DM_INITIALIZING; | 889 | dm_device.state = DM_INITIALIZING; |
@@ -891,7 +895,7 @@ static int balloon_probe(struct hv_device *dev, | |||
891 | kthread_run(dm_thread_func, &dm_device, "hv_balloon"); | 895 | kthread_run(dm_thread_func, &dm_device, "hv_balloon"); |
892 | if (IS_ERR(dm_device.thread)) { | 896 | if (IS_ERR(dm_device.thread)) { |
893 | ret = PTR_ERR(dm_device.thread); | 897 | ret = PTR_ERR(dm_device.thread); |
894 | goto probe_error0; | 898 | goto probe_error1; |
895 | } | 899 | } |
896 | 900 | ||
897 | hv_set_drvdata(dev, &dm_device); | 901 | hv_set_drvdata(dev, &dm_device); |
@@ -914,12 +918,12 @@ static int balloon_probe(struct hv_device *dev, | |||
914 | VM_PKT_DATA_INBAND, | 918 | VM_PKT_DATA_INBAND, |
915 | VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); | 919 | VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); |
916 | if (ret) | 920 | if (ret) |
917 | goto probe_error1; | 921 | goto probe_error2; |
918 | 922 | ||
919 | t = wait_for_completion_timeout(&dm_device.host_event, 5*HZ); | 923 | t = wait_for_completion_timeout(&dm_device.host_event, 5*HZ); |
920 | if (t == 0) { | 924 | if (t == 0) { |
921 | ret = -ETIMEDOUT; | 925 | ret = -ETIMEDOUT; |
922 | goto probe_error1; | 926 | goto probe_error2; |
923 | } | 927 | } |
924 | 928 | ||
925 | /* | 929 | /* |
@@ -928,7 +932,7 @@ static int balloon_probe(struct hv_device *dev, | |||
928 | */ | 932 | */ |
929 | if (dm_device.state == DM_INIT_ERROR) { | 933 | if (dm_device.state == DM_INIT_ERROR) { |
930 | ret = -ETIMEDOUT; | 934 | ret = -ETIMEDOUT; |
931 | goto probe_error1; | 935 | goto probe_error2; |
932 | } | 936 | } |
933 | /* | 937 | /* |
934 | * Now submit our capabilities to the host. | 938 | * Now submit our capabilities to the host. |
@@ -961,12 +965,12 @@ static int balloon_probe(struct hv_device *dev, | |||
961 | VM_PKT_DATA_INBAND, | 965 | VM_PKT_DATA_INBAND, |
962 | VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); | 966 | VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); |
963 | if (ret) | 967 | if (ret) |
964 | goto probe_error1; | 968 | goto probe_error2; |
965 | 969 | ||
966 | t = wait_for_completion_timeout(&dm_device.host_event, 5*HZ); | 970 | t = wait_for_completion_timeout(&dm_device.host_event, 5*HZ); |
967 | if (t == 0) { | 971 | if (t == 0) { |
968 | ret = -ETIMEDOUT; | 972 | ret = -ETIMEDOUT; |
969 | goto probe_error1; | 973 | goto probe_error2; |
970 | } | 974 | } |
971 | 975 | ||
972 | /* | 976 | /* |
@@ -975,18 +979,20 @@ static int balloon_probe(struct hv_device *dev, | |||
975 | */ | 979 | */ |
976 | if (dm_device.state == DM_INIT_ERROR) { | 980 | if (dm_device.state == DM_INIT_ERROR) { |
977 | ret = -ETIMEDOUT; | 981 | ret = -ETIMEDOUT; |
978 | goto probe_error1; | 982 | goto probe_error2; |
979 | } | 983 | } |
980 | 984 | ||
981 | dm_device.state = DM_INITIALIZED; | 985 | dm_device.state = DM_INITIALIZED; |
982 | 986 | ||
983 | return 0; | 987 | return 0; |
984 | 988 | ||
985 | probe_error1: | 989 | probe_error2: |
986 | kthread_stop(dm_device.thread); | 990 | kthread_stop(dm_device.thread); |
987 | 991 | ||
988 | probe_error0: | 992 | probe_error1: |
989 | vmbus_close(dev->channel); | 993 | vmbus_close(dev->channel); |
994 | probe_error0: | ||
995 | kfree(send_buffer); | ||
990 | return ret; | 996 | return ret; |
991 | } | 997 | } |
992 | 998 | ||
@@ -999,6 +1005,7 @@ static int balloon_remove(struct hv_device *dev) | |||
999 | 1005 | ||
1000 | vmbus_close(dev->channel); | 1006 | vmbus_close(dev->channel); |
1001 | kthread_stop(dm->thread); | 1007 | kthread_stop(dm->thread); |
1008 | kfree(send_buffer); | ||
1002 | 1009 | ||
1003 | return 0; | 1010 | return 0; |
1004 | } | 1011 | } |
diff --git a/drivers/hwmon/vexpress.c b/drivers/hwmon/vexpress.c index 86d7f6d858b1..d867e6bb2be1 100644 --- a/drivers/hwmon/vexpress.c +++ b/drivers/hwmon/vexpress.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/hwmon.h> | 19 | #include <linux/hwmon.h> |
20 | #include <linux/hwmon-sysfs.h> | 20 | #include <linux/hwmon-sysfs.h> |
21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
22 | #include <linux/of.h> | ||
22 | #include <linux/of_device.h> | 23 | #include <linux/of_device.h> |
23 | #include <linux/platform_device.h> | 24 | #include <linux/platform_device.h> |
24 | #include <linux/vexpress.h> | 25 | #include <linux/vexpress.h> |
diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c index cbba7db9ad59..f5258c205de5 100644 --- a/drivers/i2c/busses/i2c-designware-core.c +++ b/drivers/i2c/busses/i2c-designware-core.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/io.h> | 34 | #include <linux/io.h> |
35 | #include <linux/pm_runtime.h> | 35 | #include <linux/pm_runtime.h> |
36 | #include <linux/delay.h> | 36 | #include <linux/delay.h> |
37 | #include <linux/module.h> | ||
37 | #include "i2c-designware-core.h" | 38 | #include "i2c-designware-core.h" |
38 | 39 | ||
39 | /* | 40 | /* |
@@ -725,3 +726,6 @@ u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev) | |||
725 | return dw_readl(dev, DW_IC_COMP_PARAM_1); | 726 | return dw_readl(dev, DW_IC_COMP_PARAM_1); |
726 | } | 727 | } |
727 | EXPORT_SYMBOL_GPL(i2c_dw_read_comp_param); | 728 | EXPORT_SYMBOL_GPL(i2c_dw_read_comp_param); |
729 | |||
730 | MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter core"); | ||
731 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 1b1a936eccc9..d6abaf2cf2e3 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c | |||
@@ -127,7 +127,7 @@ struct mxs_i2c_dev { | |||
127 | struct device *dev; | 127 | struct device *dev; |
128 | void __iomem *regs; | 128 | void __iomem *regs; |
129 | struct completion cmd_complete; | 129 | struct completion cmd_complete; |
130 | u32 cmd_err; | 130 | int cmd_err; |
131 | struct i2c_adapter adapter; | 131 | struct i2c_adapter adapter; |
132 | const struct mxs_i2c_speed_config *speed; | 132 | const struct mxs_i2c_speed_config *speed; |
133 | 133 | ||
@@ -316,7 +316,7 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, | |||
316 | if (msg->len == 0) | 316 | if (msg->len == 0) |
317 | return -EINVAL; | 317 | return -EINVAL; |
318 | 318 | ||
319 | init_completion(&i2c->cmd_complete); | 319 | INIT_COMPLETION(i2c->cmd_complete); |
320 | i2c->cmd_err = 0; | 320 | i2c->cmd_err = 0; |
321 | 321 | ||
322 | ret = mxs_i2c_dma_setup_xfer(adap, msg, flags); | 322 | ret = mxs_i2c_dma_setup_xfer(adap, msg, flags); |
@@ -473,6 +473,8 @@ static int mxs_i2c_probe(struct platform_device *pdev) | |||
473 | i2c->dev = dev; | 473 | i2c->dev = dev; |
474 | i2c->speed = &mxs_i2c_95kHz_config; | 474 | i2c->speed = &mxs_i2c_95kHz_config; |
475 | 475 | ||
476 | init_completion(&i2c->cmd_complete); | ||
477 | |||
476 | if (dev->of_node) { | 478 | if (dev->of_node) { |
477 | err = mxs_i2c_get_ofdata(i2c); | 479 | err = mxs_i2c_get_ofdata(i2c); |
478 | if (err) | 480 | if (err) |
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 20d41bfa7c19..4cc2f0528c88 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c | |||
@@ -803,7 +803,7 @@ static int errata_omap3_i462(struct omap_i2c_dev *dev) | |||
803 | if (stat & OMAP_I2C_STAT_AL) { | 803 | if (stat & OMAP_I2C_STAT_AL) { |
804 | dev_err(dev->dev, "Arbitration lost\n"); | 804 | dev_err(dev->dev, "Arbitration lost\n"); |
805 | dev->cmd_err |= OMAP_I2C_STAT_AL; | 805 | dev->cmd_err |= OMAP_I2C_STAT_AL; |
806 | omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK); | 806 | omap_i2c_ack_stat(dev, OMAP_I2C_STAT_AL); |
807 | } | 807 | } |
808 | 808 | ||
809 | return -EIO; | 809 | return -EIO; |
@@ -963,7 +963,7 @@ omap_i2c_isr_thread(int this_irq, void *dev_id) | |||
963 | i2c_omap_errata_i207(dev, stat); | 963 | i2c_omap_errata_i207(dev, stat); |
964 | 964 | ||
965 | omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RDR); | 965 | omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RDR); |
966 | break; | 966 | continue; |
967 | } | 967 | } |
968 | 968 | ||
969 | if (stat & OMAP_I2C_STAT_RRDY) { | 969 | if (stat & OMAP_I2C_STAT_RRDY) { |
@@ -989,7 +989,7 @@ omap_i2c_isr_thread(int this_irq, void *dev_id) | |||
989 | break; | 989 | break; |
990 | 990 | ||
991 | omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XDR); | 991 | omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XDR); |
992 | break; | 992 | continue; |
993 | } | 993 | } |
994 | 994 | ||
995 | if (stat & OMAP_I2C_STAT_XRDY) { | 995 | if (stat & OMAP_I2C_STAT_XRDY) { |
diff --git a/drivers/i2c/busses/i2c-sirf.c b/drivers/i2c/busses/i2c-sirf.c index 3f1818b87974..e03381aee34f 100644 --- a/drivers/i2c/busses/i2c-sirf.c +++ b/drivers/i2c/busses/i2c-sirf.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/slab.h> | 12 | #include <linux/slab.h> |
13 | #include <linux/platform_device.h> | 13 | #include <linux/platform_device.h> |
14 | #include <linux/i2c.h> | 14 | #include <linux/i2c.h> |
15 | #include <linux/of_i2c.h> | ||
15 | #include <linux/clk.h> | 16 | #include <linux/clk.h> |
16 | #include <linux/err.h> | 17 | #include <linux/err.h> |
17 | #include <linux/io.h> | 18 | #include <linux/io.h> |
@@ -328,6 +329,7 @@ static int i2c_sirfsoc_probe(struct platform_device *pdev) | |||
328 | adap->algo = &i2c_sirfsoc_algo; | 329 | adap->algo = &i2c_sirfsoc_algo; |
329 | adap->algo_data = siic; | 330 | adap->algo_data = siic; |
330 | 331 | ||
332 | adap->dev.of_node = pdev->dev.of_node; | ||
331 | adap->dev.parent = &pdev->dev; | 333 | adap->dev.parent = &pdev->dev; |
332 | adap->nr = pdev->id; | 334 | adap->nr = pdev->id; |
333 | 335 | ||
@@ -371,6 +373,8 @@ static int i2c_sirfsoc_probe(struct platform_device *pdev) | |||
371 | 373 | ||
372 | clk_disable(clk); | 374 | clk_disable(clk); |
373 | 375 | ||
376 | of_i2c_register_devices(adap); | ||
377 | |||
374 | dev_info(&pdev->dev, " I2C adapter ready to operate\n"); | 378 | dev_info(&pdev->dev, " I2C adapter ready to operate\n"); |
375 | 379 | ||
376 | return 0; | 380 | return 0; |
diff --git a/drivers/i2c/muxes/i2c-mux-pinctrl.c b/drivers/i2c/muxes/i2c-mux-pinctrl.c index 1e44d04d1b22..a43c0ce5e3d8 100644 --- a/drivers/i2c/muxes/i2c-mux-pinctrl.c +++ b/drivers/i2c/muxes/i2c-mux-pinctrl.c | |||
@@ -167,7 +167,7 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev) | |||
167 | } | 167 | } |
168 | 168 | ||
169 | mux->busses = devm_kzalloc(&pdev->dev, | 169 | mux->busses = devm_kzalloc(&pdev->dev, |
170 | sizeof(mux->busses) * mux->pdata->bus_count, | 170 | sizeof(*mux->busses) * mux->pdata->bus_count, |
171 | GFP_KERNEL); | 171 | GFP_KERNEL); |
172 | if (!mux->busses) { | 172 | if (!mux->busses) { |
173 | dev_err(&pdev->dev, "Cannot allocate busses\n"); | 173 | dev_err(&pdev->dev, "Cannot allocate busses\n"); |
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 4ba384f1ab54..2df9414a72f7 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c | |||
@@ -448,8 +448,6 @@ static int intel_idle_probe(void) | |||
448 | else | 448 | else |
449 | on_each_cpu(__setup_broadcast_timer, (void *)true, 1); | 449 | on_each_cpu(__setup_broadcast_timer, (void *)true, 1); |
450 | 450 | ||
451 | register_cpu_notifier(&cpu_hotplug_notifier); | ||
452 | |||
453 | pr_debug(PREFIX "v" INTEL_IDLE_VERSION | 451 | pr_debug(PREFIX "v" INTEL_IDLE_VERSION |
454 | " model 0x%X\n", boot_cpu_data.x86_model); | 452 | " model 0x%X\n", boot_cpu_data.x86_model); |
455 | 453 | ||
@@ -612,6 +610,7 @@ static int __init intel_idle_init(void) | |||
612 | return retval; | 610 | return retval; |
613 | } | 611 | } |
614 | } | 612 | } |
613 | register_cpu_notifier(&cpu_hotplug_notifier); | ||
615 | 614 | ||
616 | return 0; | 615 | return 0; |
617 | } | 616 | } |
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index fe4bcd7c5b12..05e996fafc9d 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig | |||
@@ -8,6 +8,7 @@ config HID_SENSOR_ACCEL_3D | |||
8 | select IIO_BUFFER | 8 | select IIO_BUFFER |
9 | select IIO_TRIGGERED_BUFFER | 9 | select IIO_TRIGGERED_BUFFER |
10 | select HID_SENSOR_IIO_COMMON | 10 | select HID_SENSOR_IIO_COMMON |
11 | select HID_SENSOR_IIO_TRIGGER | ||
11 | tristate "HID Accelerometers 3D" | 12 | tristate "HID Accelerometers 3D" |
12 | help | 13 | help |
13 | Say yes here to build support for the HID SENSOR | 14 | Say yes here to build support for the HID SENSOR |
diff --git a/drivers/iio/adc/ad7266.c b/drivers/iio/adc/ad7266.c index 4a5f639bc684..bbad9b94cd75 100644 --- a/drivers/iio/adc/ad7266.c +++ b/drivers/iio/adc/ad7266.c | |||
@@ -411,7 +411,11 @@ static int ad7266_probe(struct spi_device *spi) | |||
411 | if (ret) | 411 | if (ret) |
412 | goto error_put_reg; | 412 | goto error_put_reg; |
413 | 413 | ||
414 | st->vref_uv = regulator_get_voltage(st->reg); | 414 | ret = regulator_get_voltage(st->reg); |
415 | if (ret < 0) | ||
416 | goto error_disable_reg; | ||
417 | |||
418 | st->vref_uv = ret; | ||
415 | } else { | 419 | } else { |
416 | /* Use internal reference */ | 420 | /* Use internal reference */ |
417 | st->vref_uv = 2500000; | 421 | st->vref_uv = 2500000; |
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index 04b013561f0f..a526c0e3aaa8 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c | |||
@@ -80,7 +80,7 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p) | |||
80 | *timestamp = pf->timestamp; | 80 | *timestamp = pf->timestamp; |
81 | } | 81 | } |
82 | 82 | ||
83 | iio_push_to_buffers(indio_dev, (u8 *)st->buffer); | 83 | iio_push_to_buffers(idev, (u8 *)st->buffer); |
84 | 84 | ||
85 | iio_trigger_notify_done(idev->trig); | 85 | iio_trigger_notify_done(idev->trig); |
86 | 86 | ||
diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c index b5669be6f396..03b25b3dc71e 100644 --- a/drivers/iio/adc/max1363.c +++ b/drivers/iio/adc/max1363.c | |||
@@ -1605,19 +1605,20 @@ static int max1363_probe(struct i2c_client *client, | |||
1605 | 1605 | ||
1606 | return 0; | 1606 | return 0; |
1607 | error_free_irq: | 1607 | error_free_irq: |
1608 | free_irq(st->client->irq, indio_dev); | 1608 | if (client->irq) |
1609 | free_irq(st->client->irq, indio_dev); | ||
1609 | error_uninit_buffer: | 1610 | error_uninit_buffer: |
1610 | iio_buffer_unregister(indio_dev); | 1611 | iio_buffer_unregister(indio_dev); |
1611 | error_cleanup_buffer: | 1612 | error_cleanup_buffer: |
1612 | max1363_buffer_cleanup(indio_dev); | 1613 | max1363_buffer_cleanup(indio_dev); |
1613 | error_free_available_scan_masks: | 1614 | error_free_available_scan_masks: |
1614 | kfree(indio_dev->available_scan_masks); | 1615 | kfree(indio_dev->available_scan_masks); |
1615 | error_unregister_map: | ||
1616 | iio_map_array_unregister(indio_dev, client->dev.platform_data); | ||
1617 | error_disable_reg: | 1616 | error_disable_reg: |
1618 | regulator_disable(st->reg); | 1617 | regulator_disable(st->reg); |
1619 | error_put_reg: | 1618 | error_put_reg: |
1620 | regulator_put(st->reg); | 1619 | regulator_put(st->reg); |
1620 | error_unregister_map: | ||
1621 | iio_map_array_unregister(indio_dev, client->dev.platform_data); | ||
1621 | error_free_device: | 1622 | error_free_device: |
1622 | iio_device_free(indio_dev); | 1623 | iio_device_free(indio_dev); |
1623 | error_out: | 1624 | error_out: |
@@ -1635,10 +1636,8 @@ static int max1363_remove(struct i2c_client *client) | |||
1635 | iio_buffer_unregister(indio_dev); | 1636 | iio_buffer_unregister(indio_dev); |
1636 | max1363_buffer_cleanup(indio_dev); | 1637 | max1363_buffer_cleanup(indio_dev); |
1637 | kfree(indio_dev->available_scan_masks); | 1638 | kfree(indio_dev->available_scan_masks); |
1638 | if (!IS_ERR(st->reg)) { | 1639 | regulator_disable(st->reg); |
1639 | regulator_disable(st->reg); | 1640 | regulator_put(st->reg); |
1640 | regulator_put(st->reg); | ||
1641 | } | ||
1642 | iio_map_array_unregister(indio_dev, client->dev.platform_data); | 1641 | iio_map_array_unregister(indio_dev, client->dev.platform_data); |
1643 | iio_device_free(indio_dev); | 1642 | iio_device_free(indio_dev); |
1644 | 1643 | ||
diff --git a/drivers/iio/common/hid-sensors/Kconfig b/drivers/iio/common/hid-sensors/Kconfig index ae10778da7aa..1178121b55b0 100644 --- a/drivers/iio/common/hid-sensors/Kconfig +++ b/drivers/iio/common/hid-sensors/Kconfig | |||
@@ -6,7 +6,7 @@ menu "Hid Sensor IIO Common" | |||
6 | config HID_SENSOR_IIO_COMMON | 6 | config HID_SENSOR_IIO_COMMON |
7 | tristate "Common modules for all HID Sensor IIO drivers" | 7 | tristate "Common modules for all HID Sensor IIO drivers" |
8 | depends on HID_SENSOR_HUB | 8 | depends on HID_SENSOR_HUB |
9 | select IIO_TRIGGER if IIO_BUFFER | 9 | select HID_SENSOR_IIO_TRIGGER if IIO_BUFFER |
10 | help | 10 | help |
11 | Say yes here to build support for HID sensor to use | 11 | Say yes here to build support for HID sensor to use |
12 | HID sensor common processing for attributes and IIO triggers. | 12 | HID sensor common processing for attributes and IIO triggers. |
@@ -14,6 +14,17 @@ config HID_SENSOR_IIO_COMMON | |||
14 | HID sensor drivers, this module contains processing for those | 14 | HID sensor drivers, this module contains processing for those |
15 | attributes. | 15 | attributes. |
16 | 16 | ||
17 | config HID_SENSOR_IIO_TRIGGER | ||
18 | tristate "Common module (trigger) for all HID Sensor IIO drivers" | ||
19 | depends on HID_SENSOR_HUB && HID_SENSOR_IIO_COMMON | ||
20 | select IIO_TRIGGER | ||
21 | help | ||
22 | Say yes here to build trigger support for HID sensors. | ||
23 | Triggers will be send if all requested attributes were read. | ||
24 | |||
25 | If this driver is compiled as a module, it will be named | ||
26 | hid-sensor-trigger. | ||
27 | |||
17 | config HID_SENSOR_ENUM_BASE_QUIRKS | 28 | config HID_SENSOR_ENUM_BASE_QUIRKS |
18 | bool "ENUM base quirks for HID Sensor IIO drivers" | 29 | bool "ENUM base quirks for HID Sensor IIO drivers" |
19 | depends on HID_SENSOR_IIO_COMMON | 30 | depends on HID_SENSOR_IIO_COMMON |
diff --git a/drivers/iio/common/hid-sensors/Makefile b/drivers/iio/common/hid-sensors/Makefile index 1f463e00c242..22e7c5a82325 100644 --- a/drivers/iio/common/hid-sensors/Makefile +++ b/drivers/iio/common/hid-sensors/Makefile | |||
@@ -3,4 +3,5 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | obj-$(CONFIG_HID_SENSOR_IIO_COMMON) += hid-sensor-iio-common.o | 5 | obj-$(CONFIG_HID_SENSOR_IIO_COMMON) += hid-sensor-iio-common.o |
6 | hid-sensor-iio-common-y := hid-sensor-attributes.o hid-sensor-trigger.o | 6 | obj-$(CONFIG_HID_SENSOR_IIO_TRIGGER) += hid-sensor-trigger.o |
7 | hid-sensor-iio-common-y := hid-sensor-attributes.o | ||
diff --git a/drivers/iio/dac/ad5380.c b/drivers/iio/dac/ad5380.c index 6c7898c765d9..483fc379a2da 100644 --- a/drivers/iio/dac/ad5380.c +++ b/drivers/iio/dac/ad5380.c | |||
@@ -406,7 +406,11 @@ static int ad5380_probe(struct device *dev, struct regmap *regmap, | |||
406 | goto error_free_reg; | 406 | goto error_free_reg; |
407 | } | 407 | } |
408 | 408 | ||
409 | st->vref = regulator_get_voltage(st->vref_reg); | 409 | ret = regulator_get_voltage(st->vref_reg); |
410 | if (ret < 0) | ||
411 | goto error_disable_reg; | ||
412 | |||
413 | st->vref = ret; | ||
410 | } else { | 414 | } else { |
411 | st->vref = st->chip_info->int_vref; | 415 | st->vref = st->chip_info->int_vref; |
412 | ctrl |= AD5380_CTRL_INT_VREF_EN; | 416 | ctrl |= AD5380_CTRL_INT_VREF_EN; |
diff --git a/drivers/iio/dac/ad5446.c b/drivers/iio/dac/ad5446.c index 29f653dab2f7..f5583aedfb59 100644 --- a/drivers/iio/dac/ad5446.c +++ b/drivers/iio/dac/ad5446.c | |||
@@ -226,7 +226,11 @@ static int ad5446_probe(struct device *dev, const char *name, | |||
226 | if (ret) | 226 | if (ret) |
227 | goto error_put_reg; | 227 | goto error_put_reg; |
228 | 228 | ||
229 | voltage_uv = regulator_get_voltage(reg); | 229 | ret = regulator_get_voltage(reg); |
230 | if (ret < 0) | ||
231 | goto error_disable_reg; | ||
232 | |||
233 | voltage_uv = ret; | ||
230 | } | 234 | } |
231 | 235 | ||
232 | indio_dev = iio_device_alloc(sizeof(*st)); | 236 | indio_dev = iio_device_alloc(sizeof(*st)); |
diff --git a/drivers/iio/dac/ad5504.c b/drivers/iio/dac/ad5504.c index b2a31a0468ed..0661829f2773 100644 --- a/drivers/iio/dac/ad5504.c +++ b/drivers/iio/dac/ad5504.c | |||
@@ -296,7 +296,11 @@ static int ad5504_probe(struct spi_device *spi) | |||
296 | if (ret) | 296 | if (ret) |
297 | goto error_put_reg; | 297 | goto error_put_reg; |
298 | 298 | ||
299 | voltage_uv = regulator_get_voltage(reg); | 299 | ret = regulator_get_voltage(reg); |
300 | if (ret < 0) | ||
301 | goto error_disable_reg; | ||
302 | |||
303 | voltage_uv = ret; | ||
300 | } | 304 | } |
301 | 305 | ||
302 | spi_set_drvdata(spi, indio_dev); | 306 | spi_set_drvdata(spi, indio_dev); |
diff --git a/drivers/iio/dac/ad5624r_spi.c b/drivers/iio/dac/ad5624r_spi.c index e9947969f9fe..f6e116627b71 100644 --- a/drivers/iio/dac/ad5624r_spi.c +++ b/drivers/iio/dac/ad5624r_spi.c | |||
@@ -238,7 +238,11 @@ static int ad5624r_probe(struct spi_device *spi) | |||
238 | if (ret) | 238 | if (ret) |
239 | goto error_put_reg; | 239 | goto error_put_reg; |
240 | 240 | ||
241 | voltage_uv = regulator_get_voltage(st->reg); | 241 | ret = regulator_get_voltage(st->reg); |
242 | if (ret < 0) | ||
243 | goto error_disable_reg; | ||
244 | |||
245 | voltage_uv = ret; | ||
242 | } | 246 | } |
243 | 247 | ||
244 | spi_set_drvdata(spi, indio_dev); | 248 | spi_set_drvdata(spi, indio_dev); |
diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c index 36e51382ae52..ca9609d7a15c 100644 --- a/drivers/iio/dac/ad5686.c +++ b/drivers/iio/dac/ad5686.c | |||
@@ -332,7 +332,11 @@ static int ad5686_probe(struct spi_device *spi) | |||
332 | if (ret) | 332 | if (ret) |
333 | goto error_put_reg; | 333 | goto error_put_reg; |
334 | 334 | ||
335 | voltage_uv = regulator_get_voltage(st->reg); | 335 | ret = regulator_get_voltage(st->reg); |
336 | if (ret < 0) | ||
337 | goto error_disable_reg; | ||
338 | |||
339 | voltage_uv = ret; | ||
336 | } | 340 | } |
337 | 341 | ||
338 | st->chip_info = | 342 | st->chip_info = |
diff --git a/drivers/iio/dac/ad5791.c b/drivers/iio/dac/ad5791.c index c84180f23139..6407b5407ddd 100644 --- a/drivers/iio/dac/ad5791.c +++ b/drivers/iio/dac/ad5791.c | |||
@@ -365,7 +365,11 @@ static int ad5791_probe(struct spi_device *spi) | |||
365 | if (ret) | 365 | if (ret) |
366 | goto error_put_reg_pos; | 366 | goto error_put_reg_pos; |
367 | 367 | ||
368 | pos_voltage_uv = regulator_get_voltage(st->reg_vdd); | 368 | ret = regulator_get_voltage(st->reg_vdd); |
369 | if (ret < 0) | ||
370 | goto error_disable_reg_pos; | ||
371 | |||
372 | pos_voltage_uv = ret; | ||
369 | } | 373 | } |
370 | 374 | ||
371 | st->reg_vss = regulator_get(&spi->dev, "vss"); | 375 | st->reg_vss = regulator_get(&spi->dev, "vss"); |
@@ -374,7 +378,11 @@ static int ad5791_probe(struct spi_device *spi) | |||
374 | if (ret) | 378 | if (ret) |
375 | goto error_put_reg_neg; | 379 | goto error_put_reg_neg; |
376 | 380 | ||
377 | neg_voltage_uv = regulator_get_voltage(st->reg_vss); | 381 | ret = regulator_get_voltage(st->reg_vss); |
382 | if (ret < 0) | ||
383 | goto error_disable_reg_neg; | ||
384 | |||
385 | neg_voltage_uv = ret; | ||
378 | } | 386 | } |
379 | 387 | ||
380 | st->pwr_down = true; | 388 | st->pwr_down = true; |
@@ -428,6 +436,7 @@ error_put_reg_neg: | |||
428 | if (!IS_ERR(st->reg_vss)) | 436 | if (!IS_ERR(st->reg_vss)) |
429 | regulator_put(st->reg_vss); | 437 | regulator_put(st->reg_vss); |
430 | 438 | ||
439 | error_disable_reg_pos: | ||
431 | if (!IS_ERR(st->reg_vdd)) | 440 | if (!IS_ERR(st->reg_vdd)) |
432 | regulator_disable(st->reg_vdd); | 441 | regulator_disable(st->reg_vdd); |
433 | error_put_reg_pos: | 442 | error_put_reg_pos: |
diff --git a/drivers/iio/frequency/adf4350.c b/drivers/iio/frequency/adf4350.c index e5033b4cfba0..a884252ac66b 100644 --- a/drivers/iio/frequency/adf4350.c +++ b/drivers/iio/frequency/adf4350.c | |||
@@ -173,7 +173,7 @@ static int adf4350_set_freq(struct adf4350_state *st, unsigned long long freq) | |||
173 | } while ((st->r1_mod > ADF4350_MAX_MODULUS) && r_cnt); | 173 | } while ((st->r1_mod > ADF4350_MAX_MODULUS) && r_cnt); |
174 | } while (r_cnt == 0); | 174 | } while (r_cnt == 0); |
175 | 175 | ||
176 | tmp = freq * (u64)st->r1_mod + (st->fpfd > 1); | 176 | tmp = freq * (u64)st->r1_mod + (st->fpfd >> 1); |
177 | do_div(tmp, st->fpfd); /* Div round closest (n + d/2)/d */ | 177 | do_div(tmp, st->fpfd); /* Div round closest (n + d/2)/d */ |
178 | st->r0_fract = do_div(tmp, st->r1_mod); | 178 | st->r0_fract = do_div(tmp, st->r1_mod); |
179 | st->r0_int = tmp; | 179 | st->r0_int = tmp; |
diff --git a/drivers/iio/gyro/Kconfig b/drivers/iio/gyro/Kconfig index 48ed1483ff27..96b68f63a902 100644 --- a/drivers/iio/gyro/Kconfig +++ b/drivers/iio/gyro/Kconfig | |||
@@ -17,6 +17,7 @@ config HID_SENSOR_GYRO_3D | |||
17 | select IIO_BUFFER | 17 | select IIO_BUFFER |
18 | select IIO_TRIGGERED_BUFFER | 18 | select IIO_TRIGGERED_BUFFER |
19 | select HID_SENSOR_IIO_COMMON | 19 | select HID_SENSOR_IIO_COMMON |
20 | select HID_SENSOR_IIO_TRIGGER | ||
20 | tristate "HID Gyroscope 3D" | 21 | tristate "HID Gyroscope 3D" |
21 | help | 22 | help |
22 | Say yes here to build support for the HID SENSOR | 23 | Say yes here to build support for the HID SENSOR |
diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index 1763c9bcb98a..dbf80abc834f 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig | |||
@@ -47,6 +47,7 @@ config HID_SENSOR_ALS | |||
47 | select IIO_BUFFER | 47 | select IIO_BUFFER |
48 | select IIO_TRIGGERED_BUFFER | 48 | select IIO_TRIGGERED_BUFFER |
49 | select HID_SENSOR_IIO_COMMON | 49 | select HID_SENSOR_IIO_COMMON |
50 | select HID_SENSOR_IIO_TRIGGER | ||
50 | tristate "HID ALS" | 51 | tristate "HID ALS" |
51 | help | 52 | help |
52 | Say yes here to build support for the HID SENSOR | 53 | Say yes here to build support for the HID SENSOR |
diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig index c1f0cdd57037..ff11d68225cf 100644 --- a/drivers/iio/magnetometer/Kconfig +++ b/drivers/iio/magnetometer/Kconfig | |||
@@ -8,6 +8,7 @@ config HID_SENSOR_MAGNETOMETER_3D | |||
8 | select IIO_BUFFER | 8 | select IIO_BUFFER |
9 | select IIO_TRIGGERED_BUFFER | 9 | select IIO_TRIGGERED_BUFFER |
10 | select HID_SENSOR_IIO_COMMON | 10 | select HID_SENSOR_IIO_COMMON |
11 | select HID_SENSOR_IIO_TRIGGER | ||
11 | tristate "HID Magenetometer 3D" | 12 | tristate "HID Magenetometer 3D" |
12 | help | 13 | help |
13 | Say yes here to build support for the HID SENSOR | 14 | Say yes here to build support for the HID SENSOR |
diff --git a/drivers/media/i2c/m5mols/m5mols_core.c b/drivers/media/i2c/m5mols/m5mols_core.c index 8a8d42fe2633..d4e7567b367c 100644 --- a/drivers/media/i2c/m5mols/m5mols_core.c +++ b/drivers/media/i2c/m5mols/m5mols_core.c | |||
@@ -556,7 +556,7 @@ static int m5mols_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | |||
556 | mutex_lock(&info->lock); | 556 | mutex_lock(&info->lock); |
557 | 557 | ||
558 | format = __find_format(info, fh, fmt->which, info->res_type); | 558 | format = __find_format(info, fh, fmt->which, info->res_type); |
559 | if (!format) | 559 | if (format) |
560 | fmt->format = *format; | 560 | fmt->format = *format; |
561 | else | 561 | else |
562 | ret = -EINVAL; | 562 | ret = -EINVAL; |
diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c index 1cf8293c0fb0..4a980e029ca7 100644 --- a/drivers/media/platform/coda.c +++ b/drivers/media/platform/coda.c | |||
@@ -23,8 +23,8 @@ | |||
23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
24 | #include <linux/videodev2.h> | 24 | #include <linux/videodev2.h> |
25 | #include <linux/of.h> | 25 | #include <linux/of.h> |
26 | #include <linux/platform_data/imx-iram.h> | ||
26 | 27 | ||
27 | #include <mach/iram.h> | ||
28 | #include <media/v4l2-ctrls.h> | 28 | #include <media/v4l2-ctrls.h> |
29 | #include <media/v4l2-device.h> | 29 | #include <media/v4l2-device.h> |
30 | #include <media/v4l2-ioctl.h> | 30 | #include <media/v4l2-ioctl.h> |
diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c index e0d73a642186..8dac17511e61 100644 --- a/drivers/media/platform/omap3isp/ispvideo.c +++ b/drivers/media/platform/omap3isp/ispvideo.c | |||
@@ -35,9 +35,6 @@ | |||
35 | #include <linux/vmalloc.h> | 35 | #include <linux/vmalloc.h> |
36 | #include <media/v4l2-dev.h> | 36 | #include <media/v4l2-dev.h> |
37 | #include <media/v4l2-ioctl.h> | 37 | #include <media/v4l2-ioctl.h> |
38 | #include <plat/iommu.h> | ||
39 | #include <plat/iovmm.h> | ||
40 | #include <plat/omap-pm.h> | ||
41 | 38 | ||
42 | #include "ispvideo.h" | 39 | #include "ispvideo.h" |
43 | #include "isp.h" | 40 | #include "isp.h" |
diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.c b/drivers/media/platform/s5p-fimc/fimc-mdevice.c index 4ab99f3a7b09..b4a68ecf0ca7 100644 --- a/drivers/media/platform/s5p-fimc/fimc-mdevice.c +++ b/drivers/media/platform/s5p-fimc/fimc-mdevice.c | |||
@@ -593,7 +593,7 @@ static int __fimc_md_create_flite_source_links(struct fimc_md *fmd) | |||
593 | { | 593 | { |
594 | struct media_entity *source, *sink; | 594 | struct media_entity *source, *sink; |
595 | unsigned int flags = MEDIA_LNK_FL_ENABLED; | 595 | unsigned int flags = MEDIA_LNK_FL_ENABLED; |
596 | int i, ret; | 596 | int i, ret = 0; |
597 | 597 | ||
598 | for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) { | 598 | for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) { |
599 | struct fimc_lite *fimc = fmd->fimc_lite[i]; | 599 | struct fimc_lite *fimc = fmd->fimc_lite[i]; |
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 379f57433711..681bc6ba149d 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c | |||
@@ -412,62 +412,48 @@ leave_handle_frame: | |||
412 | } | 412 | } |
413 | 413 | ||
414 | /* Error handling for interrupt */ | 414 | /* Error handling for interrupt */ |
415 | static void s5p_mfc_handle_error(struct s5p_mfc_ctx *ctx, | 415 | static void s5p_mfc_handle_error(struct s5p_mfc_dev *dev, |
416 | unsigned int reason, unsigned int err) | 416 | struct s5p_mfc_ctx *ctx, unsigned int reason, unsigned int err) |
417 | { | 417 | { |
418 | struct s5p_mfc_dev *dev; | ||
419 | unsigned long flags; | 418 | unsigned long flags; |
420 | 419 | ||
421 | /* If no context is available then all necessary | ||
422 | * processing has been done. */ | ||
423 | if (ctx == NULL) | ||
424 | return; | ||
425 | |||
426 | dev = ctx->dev; | ||
427 | mfc_err("Interrupt Error: %08x\n", err); | 420 | mfc_err("Interrupt Error: %08x\n", err); |
428 | s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); | ||
429 | wake_up_dev(dev, reason, err); | ||
430 | 421 | ||
431 | /* Error recovery is dependent on the state of context */ | 422 | if (ctx != NULL) { |
432 | switch (ctx->state) { | 423 | /* Error recovery is dependent on the state of context */ |
433 | case MFCINST_INIT: | 424 | switch (ctx->state) { |
434 | /* This error had to happen while acquireing instance */ | 425 | case MFCINST_RES_CHANGE_INIT: |
435 | case MFCINST_GOT_INST: | 426 | case MFCINST_RES_CHANGE_FLUSH: |
436 | /* This error had to happen while parsing the header */ | 427 | case MFCINST_RES_CHANGE_END: |
437 | case MFCINST_HEAD_PARSED: | 428 | case MFCINST_FINISHING: |
438 | /* This error had to happen while setting dst buffers */ | 429 | case MFCINST_FINISHED: |
439 | case MFCINST_RETURN_INST: | 430 | case MFCINST_RUNNING: |
440 | /* This error had to happen while releasing instance */ | 431 | /* It is higly probable that an error occured |
441 | clear_work_bit(ctx); | 432 | * while decoding a frame */ |
442 | wake_up_ctx(ctx, reason, err); | 433 | clear_work_bit(ctx); |
443 | if (test_and_clear_bit(0, &dev->hw_lock) == 0) | 434 | ctx->state = MFCINST_ERROR; |
444 | BUG(); | 435 | /* Mark all dst buffers as having an error */ |
445 | s5p_mfc_clock_off(); | 436 | spin_lock_irqsave(&dev->irqlock, flags); |
446 | ctx->state = MFCINST_ERROR; | 437 | s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, |
447 | break; | 438 | &ctx->dst_queue, &ctx->vq_dst); |
448 | case MFCINST_FINISHING: | 439 | /* Mark all src buffers as having an error */ |
449 | case MFCINST_FINISHED: | 440 | s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, |
450 | case MFCINST_RUNNING: | 441 | &ctx->src_queue, &ctx->vq_src); |
451 | /* It is higly probable that an error occured | 442 | spin_unlock_irqrestore(&dev->irqlock, flags); |
452 | * while decoding a frame */ | 443 | wake_up_ctx(ctx, reason, err); |
453 | clear_work_bit(ctx); | 444 | break; |
454 | ctx->state = MFCINST_ERROR; | 445 | default: |
455 | /* Mark all dst buffers as having an error */ | 446 | clear_work_bit(ctx); |
456 | spin_lock_irqsave(&dev->irqlock, flags); | 447 | ctx->state = MFCINST_ERROR; |
457 | s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->dst_queue, | 448 | wake_up_ctx(ctx, reason, err); |
458 | &ctx->vq_dst); | 449 | break; |
459 | /* Mark all src buffers as having an error */ | 450 | } |
460 | s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->src_queue, | ||
461 | &ctx->vq_src); | ||
462 | spin_unlock_irqrestore(&dev->irqlock, flags); | ||
463 | if (test_and_clear_bit(0, &dev->hw_lock) == 0) | ||
464 | BUG(); | ||
465 | s5p_mfc_clock_off(); | ||
466 | break; | ||
467 | default: | ||
468 | mfc_err("Encountered an error interrupt which had not been handled\n"); | ||
469 | break; | ||
470 | } | 451 | } |
452 | if (test_and_clear_bit(0, &dev->hw_lock) == 0) | ||
453 | BUG(); | ||
454 | s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); | ||
455 | s5p_mfc_clock_off(); | ||
456 | wake_up_dev(dev, reason, err); | ||
471 | return; | 457 | return; |
472 | } | 458 | } |
473 | 459 | ||
@@ -632,7 +618,7 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv) | |||
632 | dev->warn_start) | 618 | dev->warn_start) |
633 | s5p_mfc_handle_frame(ctx, reason, err); | 619 | s5p_mfc_handle_frame(ctx, reason, err); |
634 | else | 620 | else |
635 | s5p_mfc_handle_error(ctx, reason, err); | 621 | s5p_mfc_handle_error(dev, ctx, reason, err); |
636 | clear_bit(0, &dev->enter_suspend); | 622 | clear_bit(0, &dev->enter_suspend); |
637 | break; | 623 | break; |
638 | 624 | ||
diff --git a/drivers/media/usb/gspca/kinect.c b/drivers/media/usb/gspca/kinect.c index 40ad6687ee5d..3773a8a745df 100644 --- a/drivers/media/usb/gspca/kinect.c +++ b/drivers/media/usb/gspca/kinect.c | |||
@@ -381,6 +381,7 @@ static const struct sd_desc sd_desc = { | |||
381 | /* -- module initialisation -- */ | 381 | /* -- module initialisation -- */ |
382 | static const struct usb_device_id device_table[] = { | 382 | static const struct usb_device_id device_table[] = { |
383 | {USB_DEVICE(0x045e, 0x02ae)}, | 383 | {USB_DEVICE(0x045e, 0x02ae)}, |
384 | {USB_DEVICE(0x045e, 0x02bf)}, | ||
384 | {} | 385 | {} |
385 | }; | 386 | }; |
386 | 387 | ||
diff --git a/drivers/media/usb/gspca/sonixb.c b/drivers/media/usb/gspca/sonixb.c index 70511d5f9538..1220340e7602 100644 --- a/drivers/media/usb/gspca/sonixb.c +++ b/drivers/media/usb/gspca/sonixb.c | |||
@@ -496,7 +496,7 @@ static void reg_w(struct gspca_dev *gspca_dev, | |||
496 | } | 496 | } |
497 | } | 497 | } |
498 | 498 | ||
499 | static void i2c_w(struct gspca_dev *gspca_dev, const __u8 *buffer) | 499 | static void i2c_w(struct gspca_dev *gspca_dev, const u8 *buf) |
500 | { | 500 | { |
501 | int retry = 60; | 501 | int retry = 60; |
502 | 502 | ||
@@ -504,16 +504,19 @@ static void i2c_w(struct gspca_dev *gspca_dev, const __u8 *buffer) | |||
504 | return; | 504 | return; |
505 | 505 | ||
506 | /* is i2c ready */ | 506 | /* is i2c ready */ |
507 | reg_w(gspca_dev, 0x08, buffer, 8); | 507 | reg_w(gspca_dev, 0x08, buf, 8); |
508 | while (retry--) { | 508 | while (retry--) { |
509 | if (gspca_dev->usb_err < 0) | 509 | if (gspca_dev->usb_err < 0) |
510 | return; | 510 | return; |
511 | msleep(10); | 511 | msleep(1); |
512 | reg_r(gspca_dev, 0x08); | 512 | reg_r(gspca_dev, 0x08); |
513 | if (gspca_dev->usb_buf[0] & 0x04) { | 513 | if (gspca_dev->usb_buf[0] & 0x04) { |
514 | if (gspca_dev->usb_buf[0] & 0x08) { | 514 | if (gspca_dev->usb_buf[0] & 0x08) { |
515 | dev_err(gspca_dev->v4l2_dev.dev, | 515 | dev_err(gspca_dev->v4l2_dev.dev, |
516 | "i2c write error\n"); | 516 | "i2c error writing %02x %02x %02x %02x" |
517 | " %02x %02x %02x %02x\n", | ||
518 | buf[0], buf[1], buf[2], buf[3], | ||
519 | buf[4], buf[5], buf[6], buf[7]); | ||
517 | gspca_dev->usb_err = -EIO; | 520 | gspca_dev->usb_err = -EIO; |
518 | } | 521 | } |
519 | return; | 522 | return; |
@@ -530,7 +533,7 @@ static void i2c_w_vector(struct gspca_dev *gspca_dev, | |||
530 | for (;;) { | 533 | for (;;) { |
531 | if (gspca_dev->usb_err < 0) | 534 | if (gspca_dev->usb_err < 0) |
532 | return; | 535 | return; |
533 | reg_w(gspca_dev, 0x08, *buffer, 8); | 536 | i2c_w(gspca_dev, *buffer); |
534 | len -= 8; | 537 | len -= 8; |
535 | if (len <= 0) | 538 | if (len <= 0) |
536 | break; | 539 | break; |
diff --git a/drivers/media/usb/gspca/sonixj.c b/drivers/media/usb/gspca/sonixj.c index 5a86047b846f..36307a9028a9 100644 --- a/drivers/media/usb/gspca/sonixj.c +++ b/drivers/media/usb/gspca/sonixj.c | |||
@@ -1550,6 +1550,7 @@ static void i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val) | |||
1550 | 0, | 1550 | 0, |
1551 | gspca_dev->usb_buf, 8, | 1551 | gspca_dev->usb_buf, 8, |
1552 | 500); | 1552 | 500); |
1553 | msleep(2); | ||
1553 | if (ret < 0) { | 1554 | if (ret < 0) { |
1554 | pr_err("i2c_w1 err %d\n", ret); | 1555 | pr_err("i2c_w1 err %d\n", ret); |
1555 | gspca_dev->usb_err = ret; | 1556 | gspca_dev->usb_err = ret; |
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index 2bb7613ddebb..d5baab17a5ef 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c | |||
@@ -1431,8 +1431,10 @@ int uvc_ctrl_set(struct uvc_video_chain *chain, | |||
1431 | int ret; | 1431 | int ret; |
1432 | 1432 | ||
1433 | ctrl = uvc_find_control(chain, xctrl->id, &mapping); | 1433 | ctrl = uvc_find_control(chain, xctrl->id, &mapping); |
1434 | if (ctrl == NULL || (ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR) == 0) | 1434 | if (ctrl == NULL) |
1435 | return -EINVAL; | 1435 | return -EINVAL; |
1436 | if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR)) | ||
1437 | return -EACCES; | ||
1436 | 1438 | ||
1437 | /* Clamp out of range values. */ | 1439 | /* Clamp out of range values. */ |
1438 | switch (mapping->v4l2_type) { | 1440 | switch (mapping->v4l2_type) { |
diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index f2ee8c6b0d8d..68d59b527492 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c | |||
@@ -657,8 +657,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
657 | ret = uvc_ctrl_get(chain, ctrl); | 657 | ret = uvc_ctrl_get(chain, ctrl); |
658 | if (ret < 0) { | 658 | if (ret < 0) { |
659 | uvc_ctrl_rollback(handle); | 659 | uvc_ctrl_rollback(handle); |
660 | ctrls->error_idx = ret == -ENOENT | 660 | ctrls->error_idx = i; |
661 | ? ctrls->count : i; | ||
662 | return ret; | 661 | return ret; |
663 | } | 662 | } |
664 | } | 663 | } |
@@ -686,8 +685,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
686 | ret = uvc_ctrl_set(chain, ctrl); | 685 | ret = uvc_ctrl_set(chain, ctrl); |
687 | if (ret < 0) { | 686 | if (ret < 0) { |
688 | uvc_ctrl_rollback(handle); | 687 | uvc_ctrl_rollback(handle); |
689 | ctrls->error_idx = (ret == -ENOENT && | 688 | ctrls->error_idx = cmd == VIDIOC_S_EXT_CTRLS |
690 | cmd == VIDIOC_S_EXT_CTRLS) | ||
691 | ? ctrls->count : i; | 689 | ? ctrls->count : i; |
692 | return ret; | 690 | return ret; |
693 | } | 691 | } |
diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 9f81be23a81f..e02c4797b1c6 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c | |||
@@ -921,8 +921,10 @@ static void __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b | |||
921 | * In videobuf we use our internal V4l2_planes struct for | 921 | * In videobuf we use our internal V4l2_planes struct for |
922 | * single-planar buffers as well, for simplicity. | 922 | * single-planar buffers as well, for simplicity. |
923 | */ | 923 | */ |
924 | if (V4L2_TYPE_IS_OUTPUT(b->type)) | 924 | if (V4L2_TYPE_IS_OUTPUT(b->type)) { |
925 | v4l2_planes[0].bytesused = b->bytesused; | 925 | v4l2_planes[0].bytesused = b->bytesused; |
926 | v4l2_planes[0].data_offset = 0; | ||
927 | } | ||
926 | 928 | ||
927 | if (b->memory == V4L2_MEMORY_USERPTR) { | 929 | if (b->memory == V4L2_MEMORY_USERPTR) { |
928 | v4l2_planes[0].m.userptr = b->m.userptr; | 930 | v4l2_planes[0].m.userptr = b->m.userptr; |
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 1c0abd4dfc43..47ad4e270877 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig | |||
@@ -292,6 +292,7 @@ config TWL4030_CORE | |||
292 | bool "Texas Instruments TWL4030/TWL5030/TWL6030/TPS659x0 Support" | 292 | bool "Texas Instruments TWL4030/TWL5030/TWL6030/TPS659x0 Support" |
293 | depends on I2C=y && GENERIC_HARDIRQS | 293 | depends on I2C=y && GENERIC_HARDIRQS |
294 | select IRQ_DOMAIN | 294 | select IRQ_DOMAIN |
295 | select REGMAP_I2C | ||
295 | help | 296 | help |
296 | Say yes here if you have TWL4030 / TWL6030 family chip on your board. | 297 | Say yes here if you have TWL4030 / TWL6030 family chip on your board. |
297 | This core driver provides register access and IRQ handling | 298 | This core driver provides register access and IRQ handling |
diff --git a/drivers/mfd/vexpress-sysreg.c b/drivers/mfd/vexpress-sysreg.c index e5d8f63b252a..77048b18439e 100644 --- a/drivers/mfd/vexpress-sysreg.c +++ b/drivers/mfd/vexpress-sysreg.c | |||
@@ -313,19 +313,11 @@ static void vexpress_sysreg_config_complete(unsigned long data) | |||
313 | } | 313 | } |
314 | 314 | ||
315 | 315 | ||
316 | void __init vexpress_sysreg_early_init(void __iomem *base) | 316 | void __init vexpress_sysreg_setup(struct device_node *node) |
317 | { | 317 | { |
318 | struct device_node *node = of_find_compatible_node(NULL, NULL, | 318 | if (WARN_ON(!vexpress_sysreg_base)) |
319 | "arm,vexpress-sysreg"); | ||
320 | |||
321 | if (node) | ||
322 | base = of_iomap(node, 0); | ||
323 | |||
324 | if (WARN_ON(!base)) | ||
325 | return; | 319 | return; |
326 | 320 | ||
327 | vexpress_sysreg_base = base; | ||
328 | |||
329 | if (readl(vexpress_sysreg_base + SYS_MISC) & SYS_MISC_MASTERSITE) | 321 | if (readl(vexpress_sysreg_base + SYS_MISC) & SYS_MISC_MASTERSITE) |
330 | vexpress_master_site = VEXPRESS_SITE_DB2; | 322 | vexpress_master_site = VEXPRESS_SITE_DB2; |
331 | else | 323 | else |
@@ -336,9 +328,23 @@ void __init vexpress_sysreg_early_init(void __iomem *base) | |||
336 | WARN_ON(!vexpress_sysreg_config_bridge); | 328 | WARN_ON(!vexpress_sysreg_config_bridge); |
337 | } | 329 | } |
338 | 330 | ||
331 | void __init vexpress_sysreg_early_init(void __iomem *base) | ||
332 | { | ||
333 | vexpress_sysreg_base = base; | ||
334 | vexpress_sysreg_setup(NULL); | ||
335 | } | ||
336 | |||
339 | void __init vexpress_sysreg_of_early_init(void) | 337 | void __init vexpress_sysreg_of_early_init(void) |
340 | { | 338 | { |
341 | vexpress_sysreg_early_init(NULL); | 339 | struct device_node *node = of_find_compatible_node(NULL, NULL, |
340 | "arm,vexpress-sysreg"); | ||
341 | |||
342 | if (node) { | ||
343 | vexpress_sysreg_base = of_iomap(node, 0); | ||
344 | vexpress_sysreg_setup(node); | ||
345 | } else { | ||
346 | pr_info("vexpress-sysreg: No Device Tree node found."); | ||
347 | } | ||
342 | } | 348 | } |
343 | 349 | ||
344 | 350 | ||
@@ -426,9 +432,11 @@ static int vexpress_sysreg_probe(struct platform_device *pdev) | |||
426 | return -EBUSY; | 432 | return -EBUSY; |
427 | } | 433 | } |
428 | 434 | ||
429 | if (!vexpress_sysreg_base) | 435 | if (!vexpress_sysreg_base) { |
430 | vexpress_sysreg_base = devm_ioremap(&pdev->dev, res->start, | 436 | vexpress_sysreg_base = devm_ioremap(&pdev->dev, res->start, |
431 | resource_size(res)); | 437 | resource_size(res)); |
438 | vexpress_sysreg_setup(pdev->dev.of_node); | ||
439 | } | ||
432 | 440 | ||
433 | if (!vexpress_sysreg_base) { | 441 | if (!vexpress_sysreg_base) { |
434 | dev_err(&pdev->dev, "Failed to obtain base address!\n"); | 442 | dev_err(&pdev->dev, "Failed to obtain base address!\n"); |
diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c index 18794aea6062..e40ffd9502d1 100644 --- a/drivers/misc/mei/amthif.c +++ b/drivers/misc/mei/amthif.c | |||
@@ -187,13 +187,13 @@ int mei_amthif_read(struct mei_device *dev, struct file *file, | |||
187 | wait_ret = wait_event_interruptible(dev->iamthif_cl.wait, | 187 | wait_ret = wait_event_interruptible(dev->iamthif_cl.wait, |
188 | (cb = mei_amthif_find_read_list_entry(dev, file))); | 188 | (cb = mei_amthif_find_read_list_entry(dev, file))); |
189 | 189 | ||
190 | /* Locking again the Mutex */ | ||
191 | mutex_lock(&dev->device_lock); | ||
192 | |||
190 | if (wait_ret) | 193 | if (wait_ret) |
191 | return -ERESTARTSYS; | 194 | return -ERESTARTSYS; |
192 | 195 | ||
193 | dev_dbg(&dev->pdev->dev, "woke up from sleep\n"); | 196 | dev_dbg(&dev->pdev->dev, "woke up from sleep\n"); |
194 | |||
195 | /* Locking again the Mutex */ | ||
196 | mutex_lock(&dev->device_lock); | ||
197 | } | 197 | } |
198 | 198 | ||
199 | 199 | ||
diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c index 9ff942a346ed..83269f1d16e3 100644 --- a/drivers/misc/ti-st/st_kim.c +++ b/drivers/misc/ti-st/st_kim.c | |||
@@ -468,6 +468,11 @@ long st_kim_start(void *kim_data) | |||
468 | if (pdata->chip_enable) | 468 | if (pdata->chip_enable) |
469 | pdata->chip_enable(kim_gdata); | 469 | pdata->chip_enable(kim_gdata); |
470 | 470 | ||
471 | /* Configure BT nShutdown to HIGH state */ | ||
472 | gpio_set_value(kim_gdata->nshutdown, GPIO_LOW); | ||
473 | mdelay(5); /* FIXME: a proper toggle */ | ||
474 | gpio_set_value(kim_gdata->nshutdown, GPIO_HIGH); | ||
475 | mdelay(100); | ||
471 | /* re-initialize the completion */ | 476 | /* re-initialize the completion */ |
472 | INIT_COMPLETION(kim_gdata->ldisc_installed); | 477 | INIT_COMPLETION(kim_gdata->ldisc_installed); |
473 | /* send notification to UIM */ | 478 | /* send notification to UIM */ |
@@ -509,7 +514,8 @@ long st_kim_start(void *kim_data) | |||
509 | * (b) upon failure to either install ldisc or download firmware. | 514 | * (b) upon failure to either install ldisc or download firmware. |
510 | * The function is responsible to (a) notify UIM about un-installation, | 515 | * The function is responsible to (a) notify UIM about un-installation, |
511 | * (b) flush UART if the ldisc was installed. | 516 | * (b) flush UART if the ldisc was installed. |
512 | * (c) invoke platform's chip disabling routine. | 517 | * (c) reset BT_EN - pull down nshutdown at the end. |
518 | * (d) invoke platform's chip disabling routine. | ||
513 | */ | 519 | */ |
514 | long st_kim_stop(void *kim_data) | 520 | long st_kim_stop(void *kim_data) |
515 | { | 521 | { |
@@ -541,6 +547,13 @@ long st_kim_stop(void *kim_data) | |||
541 | err = -ETIMEDOUT; | 547 | err = -ETIMEDOUT; |
542 | } | 548 | } |
543 | 549 | ||
550 | /* By default configure BT nShutdown to LOW state */ | ||
551 | gpio_set_value(kim_gdata->nshutdown, GPIO_LOW); | ||
552 | mdelay(1); | ||
553 | gpio_set_value(kim_gdata->nshutdown, GPIO_HIGH); | ||
554 | mdelay(1); | ||
555 | gpio_set_value(kim_gdata->nshutdown, GPIO_LOW); | ||
556 | |||
544 | /* platform specific disable */ | 557 | /* platform specific disable */ |
545 | if (pdata->chip_disable) | 558 | if (pdata->chip_disable) |
546 | pdata->chip_disable(kim_gdata); | 559 | pdata->chip_disable(kim_gdata); |
@@ -733,6 +746,20 @@ static int kim_probe(struct platform_device *pdev) | |||
733 | /* refer to itself */ | 746 | /* refer to itself */ |
734 | kim_gdata->core_data->kim_data = kim_gdata; | 747 | kim_gdata->core_data->kim_data = kim_gdata; |
735 | 748 | ||
749 | /* Claim the chip enable nShutdown gpio from the system */ | ||
750 | kim_gdata->nshutdown = pdata->nshutdown_gpio; | ||
751 | err = gpio_request(kim_gdata->nshutdown, "kim"); | ||
752 | if (unlikely(err)) { | ||
753 | pr_err(" gpio %ld request failed ", kim_gdata->nshutdown); | ||
754 | return err; | ||
755 | } | ||
756 | |||
757 | /* Configure nShutdown GPIO as output=0 */ | ||
758 | err = gpio_direction_output(kim_gdata->nshutdown, 0); | ||
759 | if (unlikely(err)) { | ||
760 | pr_err(" unable to configure gpio %ld", kim_gdata->nshutdown); | ||
761 | return err; | ||
762 | } | ||
736 | /* get reference of pdev for request_firmware | 763 | /* get reference of pdev for request_firmware |
737 | */ | 764 | */ |
738 | kim_gdata->kim_pdev = pdev; | 765 | kim_gdata->kim_pdev = pdev; |
@@ -779,10 +806,18 @@ err_core_init: | |||
779 | 806 | ||
780 | static int kim_remove(struct platform_device *pdev) | 807 | static int kim_remove(struct platform_device *pdev) |
781 | { | 808 | { |
809 | /* free the GPIOs requested */ | ||
810 | struct ti_st_plat_data *pdata = pdev->dev.platform_data; | ||
782 | struct kim_data_s *kim_gdata; | 811 | struct kim_data_s *kim_gdata; |
783 | 812 | ||
784 | kim_gdata = dev_get_drvdata(&pdev->dev); | 813 | kim_gdata = dev_get_drvdata(&pdev->dev); |
785 | 814 | ||
815 | /* Free the Bluetooth/FM/GPIO | ||
816 | * nShutdown gpio from the system | ||
817 | */ | ||
818 | gpio_free(pdata->nshutdown_gpio); | ||
819 | pr_info("nshutdown GPIO Freed"); | ||
820 | |||
786 | debugfs_remove_recursive(kim_debugfs_dir); | 821 | debugfs_remove_recursive(kim_debugfs_dir); |
787 | sysfs_remove_group(&pdev->dev.kobj, &uim_attr_grp); | 822 | sysfs_remove_group(&pdev->dev.kobj, &uim_attr_grp); |
788 | pr_info("sysfs entries removed"); | 823 | pr_info("sysfs entries removed"); |
diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c index de4c20b3936c..f8dd36102949 100644 --- a/drivers/mmc/host/mvsdio.c +++ b/drivers/mmc/host/mvsdio.c | |||
@@ -50,8 +50,6 @@ struct mvsd_host { | |||
50 | struct timer_list timer; | 50 | struct timer_list timer; |
51 | struct mmc_host *mmc; | 51 | struct mmc_host *mmc; |
52 | struct device *dev; | 52 | struct device *dev; |
53 | struct resource *res; | ||
54 | int irq; | ||
55 | struct clk *clk; | 53 | struct clk *clk; |
56 | int gpio_card_detect; | 54 | int gpio_card_detect; |
57 | int gpio_write_protect; | 55 | int gpio_write_protect; |
@@ -718,10 +716,6 @@ static int __init mvsd_probe(struct platform_device *pdev) | |||
718 | if (!r || irq < 0 || !mvsd_data) | 716 | if (!r || irq < 0 || !mvsd_data) |
719 | return -ENXIO; | 717 | return -ENXIO; |
720 | 718 | ||
721 | r = request_mem_region(r->start, SZ_1K, DRIVER_NAME); | ||
722 | if (!r) | ||
723 | return -EBUSY; | ||
724 | |||
725 | mmc = mmc_alloc_host(sizeof(struct mvsd_host), &pdev->dev); | 719 | mmc = mmc_alloc_host(sizeof(struct mvsd_host), &pdev->dev); |
726 | if (!mmc) { | 720 | if (!mmc) { |
727 | ret = -ENOMEM; | 721 | ret = -ENOMEM; |
@@ -731,8 +725,8 @@ static int __init mvsd_probe(struct platform_device *pdev) | |||
731 | host = mmc_priv(mmc); | 725 | host = mmc_priv(mmc); |
732 | host->mmc = mmc; | 726 | host->mmc = mmc; |
733 | host->dev = &pdev->dev; | 727 | host->dev = &pdev->dev; |
734 | host->res = r; | ||
735 | host->base_clock = mvsd_data->clock / 2; | 728 | host->base_clock = mvsd_data->clock / 2; |
729 | host->clk = ERR_PTR(-EINVAL); | ||
736 | 730 | ||
737 | mmc->ops = &mvsd_ops; | 731 | mmc->ops = &mvsd_ops; |
738 | 732 | ||
@@ -752,7 +746,7 @@ static int __init mvsd_probe(struct platform_device *pdev) | |||
752 | 746 | ||
753 | spin_lock_init(&host->lock); | 747 | spin_lock_init(&host->lock); |
754 | 748 | ||
755 | host->base = ioremap(r->start, SZ_4K); | 749 | host->base = devm_request_and_ioremap(&pdev->dev, r); |
756 | if (!host->base) { | 750 | if (!host->base) { |
757 | ret = -ENOMEM; | 751 | ret = -ENOMEM; |
758 | goto out; | 752 | goto out; |
@@ -765,44 +759,45 @@ static int __init mvsd_probe(struct platform_device *pdev) | |||
765 | 759 | ||
766 | mvsd_power_down(host); | 760 | mvsd_power_down(host); |
767 | 761 | ||
768 | ret = request_irq(irq, mvsd_irq, 0, DRIVER_NAME, host); | 762 | ret = devm_request_irq(&pdev->dev, irq, mvsd_irq, 0, DRIVER_NAME, host); |
769 | if (ret) { | 763 | if (ret) { |
770 | pr_err("%s: cannot assign irq %d\n", DRIVER_NAME, irq); | 764 | pr_err("%s: cannot assign irq %d\n", DRIVER_NAME, irq); |
771 | goto out; | 765 | goto out; |
772 | } else | 766 | } |
773 | host->irq = irq; | ||
774 | 767 | ||
775 | /* Not all platforms can gate the clock, so it is not | 768 | /* Not all platforms can gate the clock, so it is not |
776 | an error if the clock does not exists. */ | 769 | an error if the clock does not exists. */ |
777 | host->clk = clk_get(&pdev->dev, NULL); | 770 | host->clk = devm_clk_get(&pdev->dev, NULL); |
778 | if (!IS_ERR(host->clk)) { | 771 | if (!IS_ERR(host->clk)) |
779 | clk_prepare_enable(host->clk); | 772 | clk_prepare_enable(host->clk); |
780 | } | ||
781 | 773 | ||
782 | if (mvsd_data->gpio_card_detect) { | 774 | if (mvsd_data->gpio_card_detect) { |
783 | ret = gpio_request(mvsd_data->gpio_card_detect, | 775 | ret = devm_gpio_request_one(&pdev->dev, |
784 | DRIVER_NAME " cd"); | 776 | mvsd_data->gpio_card_detect, |
777 | GPIOF_IN, DRIVER_NAME " cd"); | ||
785 | if (ret == 0) { | 778 | if (ret == 0) { |
786 | gpio_direction_input(mvsd_data->gpio_card_detect); | ||
787 | irq = gpio_to_irq(mvsd_data->gpio_card_detect); | 779 | irq = gpio_to_irq(mvsd_data->gpio_card_detect); |
788 | ret = request_irq(irq, mvsd_card_detect_irq, | 780 | ret = devm_request_irq(&pdev->dev, irq, |
789 | IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING, | 781 | mvsd_card_detect_irq, |
790 | DRIVER_NAME " cd", host); | 782 | IRQ_TYPE_EDGE_RISING | |
783 | IRQ_TYPE_EDGE_FALLING, | ||
784 | DRIVER_NAME " cd", host); | ||
791 | if (ret == 0) | 785 | if (ret == 0) |
792 | host->gpio_card_detect = | 786 | host->gpio_card_detect = |
793 | mvsd_data->gpio_card_detect; | 787 | mvsd_data->gpio_card_detect; |
794 | else | 788 | else |
795 | gpio_free(mvsd_data->gpio_card_detect); | 789 | devm_gpio_free(&pdev->dev, |
790 | mvsd_data->gpio_card_detect); | ||
796 | } | 791 | } |
797 | } | 792 | } |
798 | if (!host->gpio_card_detect) | 793 | if (!host->gpio_card_detect) |
799 | mmc->caps |= MMC_CAP_NEEDS_POLL; | 794 | mmc->caps |= MMC_CAP_NEEDS_POLL; |
800 | 795 | ||
801 | if (mvsd_data->gpio_write_protect) { | 796 | if (mvsd_data->gpio_write_protect) { |
802 | ret = gpio_request(mvsd_data->gpio_write_protect, | 797 | ret = devm_gpio_request_one(&pdev->dev, |
803 | DRIVER_NAME " wp"); | 798 | mvsd_data->gpio_write_protect, |
799 | GPIOF_IN, DRIVER_NAME " wp"); | ||
804 | if (ret == 0) { | 800 | if (ret == 0) { |
805 | gpio_direction_input(mvsd_data->gpio_write_protect); | ||
806 | host->gpio_write_protect = | 801 | host->gpio_write_protect = |
807 | mvsd_data->gpio_write_protect; | 802 | mvsd_data->gpio_write_protect; |
808 | } | 803 | } |
@@ -824,26 +819,11 @@ static int __init mvsd_probe(struct platform_device *pdev) | |||
824 | return 0; | 819 | return 0; |
825 | 820 | ||
826 | out: | 821 | out: |
827 | if (host) { | 822 | if (mmc) { |
828 | if (host->irq) | 823 | if (!IS_ERR(host->clk)) |
829 | free_irq(host->irq, host); | ||
830 | if (host->gpio_card_detect) { | ||
831 | free_irq(gpio_to_irq(host->gpio_card_detect), host); | ||
832 | gpio_free(host->gpio_card_detect); | ||
833 | } | ||
834 | if (host->gpio_write_protect) | ||
835 | gpio_free(host->gpio_write_protect); | ||
836 | if (host->base) | ||
837 | iounmap(host->base); | ||
838 | } | ||
839 | if (r) | ||
840 | release_resource(r); | ||
841 | if (mmc) | ||
842 | if (!IS_ERR_OR_NULL(host->clk)) { | ||
843 | clk_disable_unprepare(host->clk); | 824 | clk_disable_unprepare(host->clk); |
844 | clk_put(host->clk); | ||
845 | } | ||
846 | mmc_free_host(mmc); | 825 | mmc_free_host(mmc); |
826 | } | ||
847 | 827 | ||
848 | return ret; | 828 | return ret; |
849 | } | 829 | } |
@@ -852,28 +832,16 @@ static int __exit mvsd_remove(struct platform_device *pdev) | |||
852 | { | 832 | { |
853 | struct mmc_host *mmc = platform_get_drvdata(pdev); | 833 | struct mmc_host *mmc = platform_get_drvdata(pdev); |
854 | 834 | ||
855 | if (mmc) { | 835 | struct mvsd_host *host = mmc_priv(mmc); |
856 | struct mvsd_host *host = mmc_priv(mmc); | ||
857 | 836 | ||
858 | if (host->gpio_card_detect) { | 837 | mmc_remove_host(mmc); |
859 | free_irq(gpio_to_irq(host->gpio_card_detect), host); | 838 | del_timer_sync(&host->timer); |
860 | gpio_free(host->gpio_card_detect); | 839 | mvsd_power_down(host); |
861 | } | 840 | |
862 | mmc_remove_host(mmc); | 841 | if (!IS_ERR(host->clk)) |
863 | free_irq(host->irq, host); | 842 | clk_disable_unprepare(host->clk); |
864 | if (host->gpio_write_protect) | 843 | mmc_free_host(mmc); |
865 | gpio_free(host->gpio_write_protect); | ||
866 | del_timer_sync(&host->timer); | ||
867 | mvsd_power_down(host); | ||
868 | iounmap(host->base); | ||
869 | release_resource(host->res); | ||
870 | 844 | ||
871 | if (!IS_ERR(host->clk)) { | ||
872 | clk_disable_unprepare(host->clk); | ||
873 | clk_put(host->clk); | ||
874 | } | ||
875 | mmc_free_host(mmc); | ||
876 | } | ||
877 | platform_set_drvdata(pdev, NULL); | 845 | platform_set_drvdata(pdev, NULL); |
878 | return 0; | 846 | return 0; |
879 | } | 847 | } |
diff --git a/drivers/net/ethernet/adi/Kconfig b/drivers/net/ethernet/adi/Kconfig index e49c0eff040b..a9481606bbcd 100644 --- a/drivers/net/ethernet/adi/Kconfig +++ b/drivers/net/ethernet/adi/Kconfig | |||
@@ -61,6 +61,7 @@ config BFIN_RX_DESC_NUM | |||
61 | 61 | ||
62 | config BFIN_MAC_USE_HWSTAMP | 62 | config BFIN_MAC_USE_HWSTAMP |
63 | bool "Use IEEE 1588 hwstamp" | 63 | bool "Use IEEE 1588 hwstamp" |
64 | depends on BFIN_MAC && BF518 | ||
64 | select PTP_1588_CLOCK | 65 | select PTP_1588_CLOCK |
65 | default y | 66 | default y |
66 | ---help--- | 67 | ---help--- |
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index 01588b66a38c..f771ddfba646 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | |||
@@ -80,12 +80,37 @@ static inline void bnx2x_move_fp(struct bnx2x *bp, int from, int to) | |||
80 | new_txdata_index = new_max_eth_txqs + FCOE_TXQ_IDX_OFFSET; | 80 | new_txdata_index = new_max_eth_txqs + FCOE_TXQ_IDX_OFFSET; |
81 | } | 81 | } |
82 | 82 | ||
83 | memcpy(&bp->bnx2x_txq[old_txdata_index], | 83 | memcpy(&bp->bnx2x_txq[new_txdata_index], |
84 | &bp->bnx2x_txq[new_txdata_index], | 84 | &bp->bnx2x_txq[old_txdata_index], |
85 | sizeof(struct bnx2x_fp_txdata)); | 85 | sizeof(struct bnx2x_fp_txdata)); |
86 | to_fp->txdata_ptr[0] = &bp->bnx2x_txq[new_txdata_index]; | 86 | to_fp->txdata_ptr[0] = &bp->bnx2x_txq[new_txdata_index]; |
87 | } | 87 | } |
88 | 88 | ||
89 | /** | ||
90 | * bnx2x_shrink_eth_fp - guarantees fastpath structures stay intact | ||
91 | * | ||
92 | * @bp: driver handle | ||
93 | * @delta: number of eth queues which were not allocated | ||
94 | */ | ||
95 | static void bnx2x_shrink_eth_fp(struct bnx2x *bp, int delta) | ||
96 | { | ||
97 | int i, cos, old_eth_num = BNX2X_NUM_ETH_QUEUES(bp); | ||
98 | |||
99 | /* Queue pointer cannot be re-set on an fp-basis, as moving pointer | ||
100 | * backward along the array could cause memory to be overriden | ||
101 | */ | ||
102 | for (cos = 1; cos < bp->max_cos; cos++) { | ||
103 | for (i = 0; i < old_eth_num - delta; i++) { | ||
104 | struct bnx2x_fastpath *fp = &bp->fp[i]; | ||
105 | int new_idx = cos * (old_eth_num - delta) + i; | ||
106 | |||
107 | memcpy(&bp->bnx2x_txq[new_idx], fp->txdata_ptr[cos], | ||
108 | sizeof(struct bnx2x_fp_txdata)); | ||
109 | fp->txdata_ptr[cos] = &bp->bnx2x_txq[new_idx]; | ||
110 | } | ||
111 | } | ||
112 | } | ||
113 | |||
89 | int load_count[2][3] = { {0} }; /* per-path: 0-common, 1-port0, 2-port1 */ | 114 | int load_count[2][3] = { {0} }; /* per-path: 0-common, 1-port0, 2-port1 */ |
90 | 115 | ||
91 | /* free skb in the packet ring at pos idx | 116 | /* free skb in the packet ring at pos idx |
@@ -3863,6 +3888,7 @@ int bnx2x_alloc_fp_mem(struct bnx2x *bp) | |||
3863 | int delta = BNX2X_NUM_ETH_QUEUES(bp) - i; | 3888 | int delta = BNX2X_NUM_ETH_QUEUES(bp) - i; |
3864 | 3889 | ||
3865 | WARN_ON(delta < 0); | 3890 | WARN_ON(delta < 0); |
3891 | bnx2x_shrink_eth_fp(bp, delta); | ||
3866 | if (CNIC_SUPPORT(bp)) | 3892 | if (CNIC_SUPPORT(bp)) |
3867 | /* move non eth FPs next to last eth FP | 3893 | /* move non eth FPs next to last eth FP |
3868 | * must be done in that order | 3894 | * must be done in that order |
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c index 277f17e3c8f8..a427b49a886c 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c | |||
@@ -2777,10 +2777,10 @@ static int bnx2x_set_rss_flags(struct bnx2x *bp, struct ethtool_rxnfc *info) | |||
2777 | } else if ((info->flow_type == UDP_V6_FLOW) && | 2777 | } else if ((info->flow_type == UDP_V6_FLOW) && |
2778 | (bp->rss_conf_obj.udp_rss_v6 != udp_rss_requested)) { | 2778 | (bp->rss_conf_obj.udp_rss_v6 != udp_rss_requested)) { |
2779 | bp->rss_conf_obj.udp_rss_v6 = udp_rss_requested; | 2779 | bp->rss_conf_obj.udp_rss_v6 = udp_rss_requested; |
2780 | return bnx2x_config_rss_pf(bp, &bp->rss_conf_obj, 0); | ||
2781 | DP(BNX2X_MSG_ETHTOOL, | 2780 | DP(BNX2X_MSG_ETHTOOL, |
2782 | "rss re-configured, UDP 4-tupple %s\n", | 2781 | "rss re-configured, UDP 4-tupple %s\n", |
2783 | udp_rss_requested ? "enabled" : "disabled"); | 2782 | udp_rss_requested ? "enabled" : "disabled"); |
2783 | return bnx2x_config_rss_pf(bp, &bp->rss_conf_obj, 0); | ||
2784 | } else { | 2784 | } else { |
2785 | return 0; | 2785 | return 0; |
2786 | } | 2786 | } |
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 940ef859dc60..5523da3afcdc 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | |||
@@ -127,6 +127,17 @@ MODULE_PARM_DESC(debug, " Default debug msglevel"); | |||
127 | 127 | ||
128 | struct workqueue_struct *bnx2x_wq; | 128 | struct workqueue_struct *bnx2x_wq; |
129 | 129 | ||
130 | struct bnx2x_mac_vals { | ||
131 | u32 xmac_addr; | ||
132 | u32 xmac_val; | ||
133 | u32 emac_addr; | ||
134 | u32 emac_val; | ||
135 | u32 umac_addr; | ||
136 | u32 umac_val; | ||
137 | u32 bmac_addr; | ||
138 | u32 bmac_val[2]; | ||
139 | }; | ||
140 | |||
130 | enum bnx2x_board_type { | 141 | enum bnx2x_board_type { |
131 | BCM57710 = 0, | 142 | BCM57710 = 0, |
132 | BCM57711, | 143 | BCM57711, |
@@ -9420,12 +9431,19 @@ static inline void bnx2x_undi_int_disable(struct bnx2x *bp) | |||
9420 | bnx2x_undi_int_disable_e1h(bp); | 9431 | bnx2x_undi_int_disable_e1h(bp); |
9421 | } | 9432 | } |
9422 | 9433 | ||
9423 | static void bnx2x_prev_unload_close_mac(struct bnx2x *bp) | 9434 | static void bnx2x_prev_unload_close_mac(struct bnx2x *bp, |
9435 | struct bnx2x_mac_vals *vals) | ||
9424 | { | 9436 | { |
9425 | u32 val, base_addr, offset, mask, reset_reg; | 9437 | u32 val, base_addr, offset, mask, reset_reg; |
9426 | bool mac_stopped = false; | 9438 | bool mac_stopped = false; |
9427 | u8 port = BP_PORT(bp); | 9439 | u8 port = BP_PORT(bp); |
9428 | 9440 | ||
9441 | /* reset addresses as they also mark which values were changed */ | ||
9442 | vals->bmac_addr = 0; | ||
9443 | vals->umac_addr = 0; | ||
9444 | vals->xmac_addr = 0; | ||
9445 | vals->emac_addr = 0; | ||
9446 | |||
9429 | reset_reg = REG_RD(bp, MISC_REG_RESET_REG_2); | 9447 | reset_reg = REG_RD(bp, MISC_REG_RESET_REG_2); |
9430 | 9448 | ||
9431 | if (!CHIP_IS_E3(bp)) { | 9449 | if (!CHIP_IS_E3(bp)) { |
@@ -9447,14 +9465,18 @@ static void bnx2x_prev_unload_close_mac(struct bnx2x *bp) | |||
9447 | */ | 9465 | */ |
9448 | wb_data[0] = REG_RD(bp, base_addr + offset); | 9466 | wb_data[0] = REG_RD(bp, base_addr + offset); |
9449 | wb_data[1] = REG_RD(bp, base_addr + offset + 0x4); | 9467 | wb_data[1] = REG_RD(bp, base_addr + offset + 0x4); |
9468 | vals->bmac_addr = base_addr + offset; | ||
9469 | vals->bmac_val[0] = wb_data[0]; | ||
9470 | vals->bmac_val[1] = wb_data[1]; | ||
9450 | wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE; | 9471 | wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE; |
9451 | REG_WR(bp, base_addr + offset, wb_data[0]); | 9472 | REG_WR(bp, vals->bmac_addr, wb_data[0]); |
9452 | REG_WR(bp, base_addr + offset + 0x4, wb_data[1]); | 9473 | REG_WR(bp, vals->bmac_addr + 0x4, wb_data[1]); |
9453 | 9474 | ||
9454 | } | 9475 | } |
9455 | BNX2X_DEV_INFO("Disable emac Rx\n"); | 9476 | BNX2X_DEV_INFO("Disable emac Rx\n"); |
9456 | REG_WR(bp, NIG_REG_NIG_EMAC0_EN + BP_PORT(bp)*4, 0); | 9477 | vals->emac_addr = NIG_REG_NIG_EMAC0_EN + BP_PORT(bp)*4; |
9457 | 9478 | vals->emac_val = REG_RD(bp, vals->emac_addr); | |
9479 | REG_WR(bp, vals->emac_addr, 0); | ||
9458 | mac_stopped = true; | 9480 | mac_stopped = true; |
9459 | } else { | 9481 | } else { |
9460 | if (reset_reg & MISC_REGISTERS_RESET_REG_2_XMAC) { | 9482 | if (reset_reg & MISC_REGISTERS_RESET_REG_2_XMAC) { |
@@ -9465,14 +9487,18 @@ static void bnx2x_prev_unload_close_mac(struct bnx2x *bp) | |||
9465 | val & ~(1 << 1)); | 9487 | val & ~(1 << 1)); |
9466 | REG_WR(bp, base_addr + XMAC_REG_PFC_CTRL_HI, | 9488 | REG_WR(bp, base_addr + XMAC_REG_PFC_CTRL_HI, |
9467 | val | (1 << 1)); | 9489 | val | (1 << 1)); |
9468 | REG_WR(bp, base_addr + XMAC_REG_CTRL, 0); | 9490 | vals->xmac_addr = base_addr + XMAC_REG_CTRL; |
9491 | vals->xmac_val = REG_RD(bp, vals->xmac_addr); | ||
9492 | REG_WR(bp, vals->xmac_addr, 0); | ||
9469 | mac_stopped = true; | 9493 | mac_stopped = true; |
9470 | } | 9494 | } |
9471 | mask = MISC_REGISTERS_RESET_REG_2_UMAC0 << port; | 9495 | mask = MISC_REGISTERS_RESET_REG_2_UMAC0 << port; |
9472 | if (mask & reset_reg) { | 9496 | if (mask & reset_reg) { |
9473 | BNX2X_DEV_INFO("Disable umac Rx\n"); | 9497 | BNX2X_DEV_INFO("Disable umac Rx\n"); |
9474 | base_addr = BP_PORT(bp) ? GRCBASE_UMAC1 : GRCBASE_UMAC0; | 9498 | base_addr = BP_PORT(bp) ? GRCBASE_UMAC1 : GRCBASE_UMAC0; |
9475 | REG_WR(bp, base_addr + UMAC_REG_COMMAND_CONFIG, 0); | 9499 | vals->umac_addr = base_addr + UMAC_REG_COMMAND_CONFIG; |
9500 | vals->umac_val = REG_RD(bp, vals->umac_addr); | ||
9501 | REG_WR(bp, vals->umac_addr, 0); | ||
9476 | mac_stopped = true; | 9502 | mac_stopped = true; |
9477 | } | 9503 | } |
9478 | } | 9504 | } |
@@ -9664,12 +9690,16 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp) | |||
9664 | { | 9690 | { |
9665 | u32 reset_reg, tmp_reg = 0, rc; | 9691 | u32 reset_reg, tmp_reg = 0, rc; |
9666 | bool prev_undi = false; | 9692 | bool prev_undi = false; |
9693 | struct bnx2x_mac_vals mac_vals; | ||
9694 | |||
9667 | /* It is possible a previous function received 'common' answer, | 9695 | /* It is possible a previous function received 'common' answer, |
9668 | * but hasn't loaded yet, therefore creating a scenario of | 9696 | * but hasn't loaded yet, therefore creating a scenario of |
9669 | * multiple functions receiving 'common' on the same path. | 9697 | * multiple functions receiving 'common' on the same path. |
9670 | */ | 9698 | */ |
9671 | BNX2X_DEV_INFO("Common unload Flow\n"); | 9699 | BNX2X_DEV_INFO("Common unload Flow\n"); |
9672 | 9700 | ||
9701 | memset(&mac_vals, 0, sizeof(mac_vals)); | ||
9702 | |||
9673 | if (bnx2x_prev_is_path_marked(bp)) | 9703 | if (bnx2x_prev_is_path_marked(bp)) |
9674 | return bnx2x_prev_mcp_done(bp); | 9704 | return bnx2x_prev_mcp_done(bp); |
9675 | 9705 | ||
@@ -9680,7 +9710,10 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp) | |||
9680 | u32 timer_count = 1000; | 9710 | u32 timer_count = 1000; |
9681 | 9711 | ||
9682 | /* Close the MAC Rx to prevent BRB from filling up */ | 9712 | /* Close the MAC Rx to prevent BRB from filling up */ |
9683 | bnx2x_prev_unload_close_mac(bp); | 9713 | bnx2x_prev_unload_close_mac(bp, &mac_vals); |
9714 | |||
9715 | /* close LLH filters towards the BRB */ | ||
9716 | bnx2x_set_rx_filter(&bp->link_params, 0); | ||
9684 | 9717 | ||
9685 | /* Check if the UNDI driver was previously loaded | 9718 | /* Check if the UNDI driver was previously loaded |
9686 | * UNDI driver initializes CID offset for normal bell to 0x7 | 9719 | * UNDI driver initializes CID offset for normal bell to 0x7 |
@@ -9727,6 +9760,17 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp) | |||
9727 | /* No packets are in the pipeline, path is ready for reset */ | 9760 | /* No packets are in the pipeline, path is ready for reset */ |
9728 | bnx2x_reset_common(bp); | 9761 | bnx2x_reset_common(bp); |
9729 | 9762 | ||
9763 | if (mac_vals.xmac_addr) | ||
9764 | REG_WR(bp, mac_vals.xmac_addr, mac_vals.xmac_val); | ||
9765 | if (mac_vals.umac_addr) | ||
9766 | REG_WR(bp, mac_vals.umac_addr, mac_vals.umac_val); | ||
9767 | if (mac_vals.emac_addr) | ||
9768 | REG_WR(bp, mac_vals.emac_addr, mac_vals.emac_val); | ||
9769 | if (mac_vals.bmac_addr) { | ||
9770 | REG_WR(bp, mac_vals.bmac_addr, mac_vals.bmac_val[0]); | ||
9771 | REG_WR(bp, mac_vals.bmac_addr + 4, mac_vals.bmac_val[1]); | ||
9772 | } | ||
9773 | |||
9730 | rc = bnx2x_prev_mark_path(bp, prev_undi); | 9774 | rc = bnx2x_prev_mark_path(bp, prev_undi); |
9731 | if (rc) { | 9775 | if (rc) { |
9732 | bnx2x_prev_mcp_done(bp); | 9776 | bnx2x_prev_mcp_done(bp); |
diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index 3bc1912afba9..4eba17b83ba8 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h | |||
@@ -190,6 +190,7 @@ struct be_eq_obj { | |||
190 | 190 | ||
191 | u8 idx; /* array index */ | 191 | u8 idx; /* array index */ |
192 | u16 tx_budget; | 192 | u16 tx_budget; |
193 | u16 spurious_intr; | ||
193 | struct napi_struct napi; | 194 | struct napi_struct napi; |
194 | struct be_adapter *adapter; | 195 | struct be_adapter *adapter; |
195 | } ____cacheline_aligned_in_smp; | 196 | } ____cacheline_aligned_in_smp; |
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 9dca22be8125..5c995700e534 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c | |||
@@ -2026,19 +2026,30 @@ static irqreturn_t be_intx(int irq, void *dev) | |||
2026 | struct be_adapter *adapter = eqo->adapter; | 2026 | struct be_adapter *adapter = eqo->adapter; |
2027 | int num_evts = 0; | 2027 | int num_evts = 0; |
2028 | 2028 | ||
2029 | /* On Lancer, clear-intr bit of the EQ DB does not work. | 2029 | /* IRQ is not expected when NAPI is scheduled as the EQ |
2030 | * INTx is de-asserted only on notifying num evts. | 2030 | * will not be armed. |
2031 | * But, this can happen on Lancer INTx where it takes | ||
2032 | * a while to de-assert INTx or in BE2 where occasionaly | ||
2033 | * an interrupt may be raised even when EQ is unarmed. | ||
2034 | * If NAPI is already scheduled, then counting & notifying | ||
2035 | * events will orphan them. | ||
2031 | */ | 2036 | */ |
2032 | if (lancer_chip(adapter)) | 2037 | if (napi_schedule_prep(&eqo->napi)) { |
2033 | num_evts = events_get(eqo); | 2038 | num_evts = events_get(eqo); |
2039 | __napi_schedule(&eqo->napi); | ||
2040 | if (num_evts) | ||
2041 | eqo->spurious_intr = 0; | ||
2042 | } | ||
2043 | be_eq_notify(adapter, eqo->q.id, false, true, num_evts); | ||
2034 | 2044 | ||
2035 | /* The EQ-notify may not de-assert INTx rightaway, causing | 2045 | /* Return IRQ_HANDLED only for the the first spurious intr |
2036 | * the ISR to be invoked again. So, return HANDLED even when | 2046 | * after a valid intr to stop the kernel from branding |
2037 | * num_evts is zero. | 2047 | * this irq as a bad one! |
2038 | */ | 2048 | */ |
2039 | be_eq_notify(adapter, eqo->q.id, false, true, num_evts); | 2049 | if (num_evts || eqo->spurious_intr++ == 0) |
2040 | napi_schedule(&eqo->napi); | 2050 | return IRQ_HANDLED; |
2041 | return IRQ_HANDLED; | 2051 | else |
2052 | return IRQ_NONE; | ||
2042 | } | 2053 | } |
2043 | 2054 | ||
2044 | static irqreturn_t be_msix(int irq, void *dev) | 2055 | static irqreturn_t be_msix(int irq, void *dev) |
diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_main.c b/drivers/net/ethernet/qlogic/qlge/qlge_main.c index f80cd975daed..3e73742024b0 100644 --- a/drivers/net/ethernet/qlogic/qlge/qlge_main.c +++ b/drivers/net/ethernet/qlogic/qlge/qlge_main.c | |||
@@ -4678,7 +4678,7 @@ static int qlge_probe(struct pci_dev *pdev, | |||
4678 | qdev = netdev_priv(ndev); | 4678 | qdev = netdev_priv(ndev); |
4679 | SET_NETDEV_DEV(ndev, &pdev->dev); | 4679 | SET_NETDEV_DEV(ndev, &pdev->dev); |
4680 | ndev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | | 4680 | ndev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | |
4681 | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN | | 4681 | NETIF_F_TSO | NETIF_F_TSO_ECN | |
4682 | NETIF_F_HW_VLAN_TX | NETIF_F_RXCSUM; | 4682 | NETIF_F_HW_VLAN_TX | NETIF_F_RXCSUM; |
4683 | ndev->features = ndev->hw_features | | 4683 | ndev->features = ndev->hw_features | |
4684 | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; | 4684 | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; |
diff --git a/drivers/net/ethernet/xilinx/Kconfig b/drivers/net/ethernet/xilinx/Kconfig index 5778a4ae1164..122d60c0481b 100644 --- a/drivers/net/ethernet/xilinx/Kconfig +++ b/drivers/net/ethernet/xilinx/Kconfig | |||
@@ -27,7 +27,7 @@ config XILINX_EMACLITE | |||
27 | 27 | ||
28 | config XILINX_AXI_EMAC | 28 | config XILINX_AXI_EMAC |
29 | tristate "Xilinx 10/100/1000 AXI Ethernet support" | 29 | tristate "Xilinx 10/100/1000 AXI Ethernet support" |
30 | depends on (PPC32 || MICROBLAZE) | 30 | depends on MICROBLAZE |
31 | select PHYLIB | 31 | select PHYLIB |
32 | ---help--- | 32 | ---help--- |
33 | This driver supports the 10/100/1000 Ethernet from Xilinx for the | 33 | This driver supports the 10/100/1000 Ethernet from Xilinx for the |
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index d9f69b82cc4f..6f47100e58d7 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c | |||
@@ -1590,7 +1590,7 @@ static int axienet_of_probe(struct platform_device *op) | |||
1590 | lp->rx_irq = irq_of_parse_and_map(np, 1); | 1590 | lp->rx_irq = irq_of_parse_and_map(np, 1); |
1591 | lp->tx_irq = irq_of_parse_and_map(np, 0); | 1591 | lp->tx_irq = irq_of_parse_and_map(np, 0); |
1592 | of_node_put(np); | 1592 | of_node_put(np); |
1593 | if ((lp->rx_irq == NO_IRQ) || (lp->tx_irq == NO_IRQ)) { | 1593 | if ((lp->rx_irq <= 0) || (lp->tx_irq <= 0)) { |
1594 | dev_err(&op->dev, "could not determine irqs\n"); | 1594 | dev_err(&op->dev, "could not determine irqs\n"); |
1595 | ret = -ENOMEM; | 1595 | ret = -ENOMEM; |
1596 | goto err_iounmap_2; | 1596 | goto err_iounmap_2; |
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index fbd106edbe59..af372d0957fe 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c | |||
@@ -404,8 +404,8 @@ static void __tun_detach(struct tun_file *tfile, bool clean) | |||
404 | struct tun_struct *tun; | 404 | struct tun_struct *tun; |
405 | struct net_device *dev; | 405 | struct net_device *dev; |
406 | 406 | ||
407 | tun = rcu_dereference_protected(tfile->tun, | 407 | tun = rtnl_dereference(tfile->tun); |
408 | lockdep_rtnl_is_held()); | 408 | |
409 | if (tun) { | 409 | if (tun) { |
410 | u16 index = tfile->queue_index; | 410 | u16 index = tfile->queue_index; |
411 | BUG_ON(index >= tun->numqueues); | 411 | BUG_ON(index >= tun->numqueues); |
@@ -414,8 +414,7 @@ static void __tun_detach(struct tun_file *tfile, bool clean) | |||
414 | rcu_assign_pointer(tun->tfiles[index], | 414 | rcu_assign_pointer(tun->tfiles[index], |
415 | tun->tfiles[tun->numqueues - 1]); | 415 | tun->tfiles[tun->numqueues - 1]); |
416 | rcu_assign_pointer(tfile->tun, NULL); | 416 | rcu_assign_pointer(tfile->tun, NULL); |
417 | ntfile = rcu_dereference_protected(tun->tfiles[index], | 417 | ntfile = rtnl_dereference(tun->tfiles[index]); |
418 | lockdep_rtnl_is_held()); | ||
419 | ntfile->queue_index = index; | 418 | ntfile->queue_index = index; |
420 | 419 | ||
421 | --tun->numqueues; | 420 | --tun->numqueues; |
@@ -429,8 +428,10 @@ static void __tun_detach(struct tun_file *tfile, bool clean) | |||
429 | /* Drop read queue */ | 428 | /* Drop read queue */ |
430 | skb_queue_purge(&tfile->sk.sk_receive_queue); | 429 | skb_queue_purge(&tfile->sk.sk_receive_queue); |
431 | tun_set_real_num_queues(tun); | 430 | tun_set_real_num_queues(tun); |
432 | } else if (tfile->detached && clean) | 431 | } else if (tfile->detached && clean) { |
433 | tun = tun_enable_queue(tfile); | 432 | tun = tun_enable_queue(tfile); |
433 | sock_put(&tfile->sk); | ||
434 | } | ||
434 | 435 | ||
435 | if (clean) { | 436 | if (clean) { |
436 | if (tun && tun->numqueues == 0 && tun->numdisabled == 0 && | 437 | if (tun && tun->numqueues == 0 && tun->numdisabled == 0 && |
@@ -458,8 +459,7 @@ static void tun_detach_all(struct net_device *dev) | |||
458 | int i, n = tun->numqueues; | 459 | int i, n = tun->numqueues; |
459 | 460 | ||
460 | for (i = 0; i < n; i++) { | 461 | for (i = 0; i < n; i++) { |
461 | tfile = rcu_dereference_protected(tun->tfiles[i], | 462 | tfile = rtnl_dereference(tun->tfiles[i]); |
462 | lockdep_rtnl_is_held()); | ||
463 | BUG_ON(!tfile); | 463 | BUG_ON(!tfile); |
464 | wake_up_all(&tfile->wq.wait); | 464 | wake_up_all(&tfile->wq.wait); |
465 | rcu_assign_pointer(tfile->tun, NULL); | 465 | rcu_assign_pointer(tfile->tun, NULL); |
@@ -469,8 +469,7 @@ static void tun_detach_all(struct net_device *dev) | |||
469 | 469 | ||
470 | synchronize_net(); | 470 | synchronize_net(); |
471 | for (i = 0; i < n; i++) { | 471 | for (i = 0; i < n; i++) { |
472 | tfile = rcu_dereference_protected(tun->tfiles[i], | 472 | tfile = rtnl_dereference(tun->tfiles[i]); |
473 | lockdep_rtnl_is_held()); | ||
474 | /* Drop read queue */ | 473 | /* Drop read queue */ |
475 | skb_queue_purge(&tfile->sk.sk_receive_queue); | 474 | skb_queue_purge(&tfile->sk.sk_receive_queue); |
476 | sock_put(&tfile->sk); | 475 | sock_put(&tfile->sk); |
@@ -481,6 +480,9 @@ static void tun_detach_all(struct net_device *dev) | |||
481 | sock_put(&tfile->sk); | 480 | sock_put(&tfile->sk); |
482 | } | 481 | } |
483 | BUG_ON(tun->numdisabled != 0); | 482 | BUG_ON(tun->numdisabled != 0); |
483 | |||
484 | if (tun->flags & TUN_PERSIST) | ||
485 | module_put(THIS_MODULE); | ||
484 | } | 486 | } |
485 | 487 | ||
486 | static int tun_attach(struct tun_struct *tun, struct file *file) | 488 | static int tun_attach(struct tun_struct *tun, struct file *file) |
@@ -489,7 +491,7 @@ static int tun_attach(struct tun_struct *tun, struct file *file) | |||
489 | int err; | 491 | int err; |
490 | 492 | ||
491 | err = -EINVAL; | 493 | err = -EINVAL; |
492 | if (rcu_dereference_protected(tfile->tun, lockdep_rtnl_is_held())) | 494 | if (rtnl_dereference(tfile->tun)) |
493 | goto out; | 495 | goto out; |
494 | 496 | ||
495 | err = -EBUSY; | 497 | err = -EBUSY; |
@@ -1544,6 +1546,9 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) | |||
1544 | struct net_device *dev; | 1546 | struct net_device *dev; |
1545 | int err; | 1547 | int err; |
1546 | 1548 | ||
1549 | if (tfile->detached) | ||
1550 | return -EINVAL; | ||
1551 | |||
1547 | dev = __dev_get_by_name(net, ifr->ifr_name); | 1552 | dev = __dev_get_by_name(net, ifr->ifr_name); |
1548 | if (dev) { | 1553 | if (dev) { |
1549 | if (ifr->ifr_flags & IFF_TUN_EXCL) | 1554 | if (ifr->ifr_flags & IFF_TUN_EXCL) |
@@ -1738,8 +1743,7 @@ static void tun_detach_filter(struct tun_struct *tun, int n) | |||
1738 | struct tun_file *tfile; | 1743 | struct tun_file *tfile; |
1739 | 1744 | ||
1740 | for (i = 0; i < n; i++) { | 1745 | for (i = 0; i < n; i++) { |
1741 | tfile = rcu_dereference_protected(tun->tfiles[i], | 1746 | tfile = rtnl_dereference(tun->tfiles[i]); |
1742 | lockdep_rtnl_is_held()); | ||
1743 | sk_detach_filter(tfile->socket.sk); | 1747 | sk_detach_filter(tfile->socket.sk); |
1744 | } | 1748 | } |
1745 | 1749 | ||
@@ -1752,8 +1756,7 @@ static int tun_attach_filter(struct tun_struct *tun) | |||
1752 | struct tun_file *tfile; | 1756 | struct tun_file *tfile; |
1753 | 1757 | ||
1754 | for (i = 0; i < tun->numqueues; i++) { | 1758 | for (i = 0; i < tun->numqueues; i++) { |
1755 | tfile = rcu_dereference_protected(tun->tfiles[i], | 1759 | tfile = rtnl_dereference(tun->tfiles[i]); |
1756 | lockdep_rtnl_is_held()); | ||
1757 | ret = sk_attach_filter(&tun->fprog, tfile->socket.sk); | 1760 | ret = sk_attach_filter(&tun->fprog, tfile->socket.sk); |
1758 | if (ret) { | 1761 | if (ret) { |
1759 | tun_detach_filter(tun, i); | 1762 | tun_detach_filter(tun, i); |
@@ -1771,8 +1774,7 @@ static void tun_set_sndbuf(struct tun_struct *tun) | |||
1771 | int i; | 1774 | int i; |
1772 | 1775 | ||
1773 | for (i = 0; i < tun->numqueues; i++) { | 1776 | for (i = 0; i < tun->numqueues; i++) { |
1774 | tfile = rcu_dereference_protected(tun->tfiles[i], | 1777 | tfile = rtnl_dereference(tun->tfiles[i]); |
1775 | lockdep_rtnl_is_held()); | ||
1776 | tfile->socket.sk->sk_sndbuf = tun->sndbuf; | 1778 | tfile->socket.sk->sk_sndbuf = tun->sndbuf; |
1777 | } | 1779 | } |
1778 | } | 1780 | } |
@@ -1789,13 +1791,10 @@ static int tun_set_queue(struct file *file, struct ifreq *ifr) | |||
1789 | tun = tfile->detached; | 1791 | tun = tfile->detached; |
1790 | if (!tun) | 1792 | if (!tun) |
1791 | ret = -EINVAL; | 1793 | ret = -EINVAL; |
1792 | else if (tun_not_capable(tun)) | ||
1793 | ret = -EPERM; | ||
1794 | else | 1794 | else |
1795 | ret = tun_attach(tun, file); | 1795 | ret = tun_attach(tun, file); |
1796 | } else if (ifr->ifr_flags & IFF_DETACH_QUEUE) { | 1796 | } else if (ifr->ifr_flags & IFF_DETACH_QUEUE) { |
1797 | tun = rcu_dereference_protected(tfile->tun, | 1797 | tun = rtnl_dereference(tfile->tun); |
1798 | lockdep_rtnl_is_held()); | ||
1799 | if (!tun || !(tun->flags & TUN_TAP_MQ)) | 1798 | if (!tun || !(tun->flags & TUN_TAP_MQ)) |
1800 | ret = -EINVAL; | 1799 | ret = -EINVAL; |
1801 | else | 1800 | else |
@@ -1880,10 +1879,11 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, | |||
1880 | /* Disable/Enable persist mode. Keep an extra reference to the | 1879 | /* Disable/Enable persist mode. Keep an extra reference to the |
1881 | * module to prevent the module being unprobed. | 1880 | * module to prevent the module being unprobed. |
1882 | */ | 1881 | */ |
1883 | if (arg) { | 1882 | if (arg && !(tun->flags & TUN_PERSIST)) { |
1884 | tun->flags |= TUN_PERSIST; | 1883 | tun->flags |= TUN_PERSIST; |
1885 | __module_get(THIS_MODULE); | 1884 | __module_get(THIS_MODULE); |
1886 | } else { | 1885 | } |
1886 | if (!arg && (tun->flags & TUN_PERSIST)) { | ||
1887 | tun->flags &= ~TUN_PERSIST; | 1887 | tun->flags &= ~TUN_PERSIST; |
1888 | module_put(THIS_MODULE); | 1888 | module_put(THIS_MODULE); |
1889 | } | 1889 | } |
diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig index 1a67a4f829fe..2c02b4e84094 100644 --- a/drivers/net/wireless/ath/Kconfig +++ b/drivers/net/wireless/ath/Kconfig | |||
@@ -30,5 +30,6 @@ source "drivers/net/wireless/ath/ath9k/Kconfig" | |||
30 | source "drivers/net/wireless/ath/carl9170/Kconfig" | 30 | source "drivers/net/wireless/ath/carl9170/Kconfig" |
31 | source "drivers/net/wireless/ath/ath6kl/Kconfig" | 31 | source "drivers/net/wireless/ath/ath6kl/Kconfig" |
32 | source "drivers/net/wireless/ath/ar5523/Kconfig" | 32 | source "drivers/net/wireless/ath/ar5523/Kconfig" |
33 | source "drivers/net/wireless/ath/wil6210/Kconfig" | ||
33 | 34 | ||
34 | endif | 35 | endif |
diff --git a/drivers/net/wireless/ath/Makefile b/drivers/net/wireless/ath/Makefile index 1e18621326dc..97b964ded2be 100644 --- a/drivers/net/wireless/ath/Makefile +++ b/drivers/net/wireless/ath/Makefile | |||
@@ -3,6 +3,7 @@ obj-$(CONFIG_ATH9K_HW) += ath9k/ | |||
3 | obj-$(CONFIG_CARL9170) += carl9170/ | 3 | obj-$(CONFIG_CARL9170) += carl9170/ |
4 | obj-$(CONFIG_ATH6KL) += ath6kl/ | 4 | obj-$(CONFIG_ATH6KL) += ath6kl/ |
5 | obj-$(CONFIG_AR5523) += ar5523/ | 5 | obj-$(CONFIG_AR5523) += ar5523/ |
6 | obj-$(CONFIG_WIL6210) += wil6210/ | ||
6 | 7 | ||
7 | obj-$(CONFIG_ATH_COMMON) += ath.o | 8 | obj-$(CONFIG_ATH_COMMON) += ath.o |
8 | 9 | ||
diff --git a/drivers/net/wireless/ath/wil6210/Kconfig b/drivers/net/wireless/ath/wil6210/Kconfig new file mode 100644 index 000000000000..bac3d98a0cfb --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/Kconfig | |||
@@ -0,0 +1,29 @@ | |||
1 | config WIL6210 | ||
2 | tristate "Wilocity 60g WiFi card wil6210 support" | ||
3 | depends on CFG80211 | ||
4 | depends on PCI | ||
5 | default n | ||
6 | ---help--- | ||
7 | This module adds support for wireless adapter based on | ||
8 | wil6210 chip by Wilocity. It supports operation on the | ||
9 | 60 GHz band, covered by the IEEE802.11ad standard. | ||
10 | |||
11 | http://wireless.kernel.org/en/users/Drivers/wil6210 | ||
12 | |||
13 | If you choose to build it as a module, it will be called | ||
14 | wil6210 | ||
15 | |||
16 | config WIL6210_ISR_COR | ||
17 | bool "Use Clear-On-Read mode for ISR registers for wil6210" | ||
18 | depends on WIL6210 | ||
19 | default y | ||
20 | ---help--- | ||
21 | ISR registers on wil6210 chip may operate in either | ||
22 | COR (Clear-On-Read) or W1C (Write-1-to-Clear) mode. | ||
23 | For production code, use COR (say y); is default since | ||
24 | it saves extra target transaction; | ||
25 | For ISR debug, use W1C (say n); is allows to monitor ISR | ||
26 | registers with debugfs. If COR were used, ISR would | ||
27 | self-clear when accessed for debug purposes, it makes | ||
28 | such monitoring impossible. | ||
29 | Say y unless you debug interrupts | ||
diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile new file mode 100644 index 000000000000..9396dc9fe3c5 --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/Makefile | |||
@@ -0,0 +1,13 @@ | |||
1 | obj-$(CONFIG_WIL6210) += wil6210.o | ||
2 | |||
3 | wil6210-objs := main.o | ||
4 | wil6210-objs += netdev.o | ||
5 | wil6210-objs += cfg80211.o | ||
6 | wil6210-objs += pcie_bus.o | ||
7 | wil6210-objs += debugfs.o | ||
8 | wil6210-objs += wmi.o | ||
9 | wil6210-objs += interrupt.o | ||
10 | wil6210-objs += txrx.o | ||
11 | |||
12 | subdir-ccflags-y += -Werror | ||
13 | subdir-ccflags-y += -D__CHECK_ENDIAN__ | ||
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c new file mode 100644 index 000000000000..116f4e807ae1 --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c | |||
@@ -0,0 +1,573 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012 Qualcomm Atheros, Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/netdevice.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/etherdevice.h> | ||
21 | #include <linux/wireless.h> | ||
22 | #include <linux/ieee80211.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/version.h> | ||
25 | #include <net/cfg80211.h> | ||
26 | |||
27 | #include "wil6210.h" | ||
28 | #include "wmi.h" | ||
29 | |||
30 | #define CHAN60G(_channel, _flags) { \ | ||
31 | .band = IEEE80211_BAND_60GHZ, \ | ||
32 | .center_freq = 56160 + (2160 * (_channel)), \ | ||
33 | .hw_value = (_channel), \ | ||
34 | .flags = (_flags), \ | ||
35 | .max_antenna_gain = 0, \ | ||
36 | .max_power = 40, \ | ||
37 | } | ||
38 | |||
39 | static struct ieee80211_channel wil_60ghz_channels[] = { | ||
40 | CHAN60G(1, 0), | ||
41 | CHAN60G(2, 0), | ||
42 | CHAN60G(3, 0), | ||
43 | /* channel 4 not supported yet */ | ||
44 | }; | ||
45 | |||
46 | static struct ieee80211_supported_band wil_band_60ghz = { | ||
47 | .channels = wil_60ghz_channels, | ||
48 | .n_channels = ARRAY_SIZE(wil_60ghz_channels), | ||
49 | .ht_cap = { | ||
50 | .ht_supported = true, | ||
51 | .cap = 0, /* TODO */ | ||
52 | .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, /* TODO */ | ||
53 | .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, /* TODO */ | ||
54 | .mcs = { | ||
55 | /* MCS 1..12 - SC PHY */ | ||
56 | .rx_mask = {0xfe, 0x1f}, /* 1..12 */ | ||
57 | .tx_params = IEEE80211_HT_MCS_TX_DEFINED, /* TODO */ | ||
58 | }, | ||
59 | }, | ||
60 | }; | ||
61 | |||
62 | static const struct ieee80211_txrx_stypes | ||
63 | wil_mgmt_stypes[NUM_NL80211_IFTYPES] = { | ||
64 | [NL80211_IFTYPE_STATION] = { | ||
65 | .tx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
66 | BIT(IEEE80211_STYPE_PROBE_RESP >> 4), | ||
67 | .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
68 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ||
69 | }, | ||
70 | [NL80211_IFTYPE_AP] = { | ||
71 | .tx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
72 | BIT(IEEE80211_STYPE_PROBE_RESP >> 4), | ||
73 | .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
74 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ||
75 | }, | ||
76 | [NL80211_IFTYPE_P2P_CLIENT] = { | ||
77 | .tx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
78 | BIT(IEEE80211_STYPE_PROBE_RESP >> 4), | ||
79 | .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
80 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ||
81 | }, | ||
82 | [NL80211_IFTYPE_P2P_GO] = { | ||
83 | .tx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
84 | BIT(IEEE80211_STYPE_PROBE_RESP >> 4), | ||
85 | .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
86 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ||
87 | }, | ||
88 | }; | ||
89 | |||
90 | static const u32 wil_cipher_suites[] = { | ||
91 | WLAN_CIPHER_SUITE_GCMP, | ||
92 | }; | ||
93 | |||
94 | int wil_iftype_nl2wmi(enum nl80211_iftype type) | ||
95 | { | ||
96 | static const struct { | ||
97 | enum nl80211_iftype nl; | ||
98 | enum wmi_network_type wmi; | ||
99 | } __nl2wmi[] = { | ||
100 | {NL80211_IFTYPE_ADHOC, WMI_NETTYPE_ADHOC}, | ||
101 | {NL80211_IFTYPE_STATION, WMI_NETTYPE_INFRA}, | ||
102 | {NL80211_IFTYPE_AP, WMI_NETTYPE_AP}, | ||
103 | {NL80211_IFTYPE_P2P_CLIENT, WMI_NETTYPE_P2P}, | ||
104 | {NL80211_IFTYPE_P2P_GO, WMI_NETTYPE_P2P}, | ||
105 | {NL80211_IFTYPE_MONITOR, WMI_NETTYPE_ADHOC}, /* FIXME */ | ||
106 | }; | ||
107 | uint i; | ||
108 | |||
109 | for (i = 0; i < ARRAY_SIZE(__nl2wmi); i++) { | ||
110 | if (__nl2wmi[i].nl == type) | ||
111 | return __nl2wmi[i].wmi; | ||
112 | } | ||
113 | |||
114 | return -EOPNOTSUPP; | ||
115 | } | ||
116 | |||
117 | static int wil_cfg80211_get_station(struct wiphy *wiphy, | ||
118 | struct net_device *ndev, | ||
119 | u8 *mac, struct station_info *sinfo) | ||
120 | { | ||
121 | struct wil6210_priv *wil = wiphy_to_wil(wiphy); | ||
122 | int rc; | ||
123 | struct wmi_notify_req_cmd cmd = { | ||
124 | .cid = 0, | ||
125 | .interval_usec = 0, | ||
126 | }; | ||
127 | |||
128 | if (memcmp(mac, wil->dst_addr[0], ETH_ALEN)) | ||
129 | return -ENOENT; | ||
130 | |||
131 | /* WMI_NOTIFY_REQ_DONE_EVENTID handler fills wil->stats.bf_mcs */ | ||
132 | rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd), | ||
133 | WMI_NOTIFY_REQ_DONE_EVENTID, NULL, 0, 20); | ||
134 | if (rc) | ||
135 | return rc; | ||
136 | |||
137 | sinfo->generation = wil->sinfo_gen; | ||
138 | |||
139 | sinfo->filled |= STATION_INFO_TX_BITRATE; | ||
140 | sinfo->txrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G; | ||
141 | sinfo->txrate.mcs = wil->stats.bf_mcs; | ||
142 | sinfo->filled |= STATION_INFO_RX_BITRATE; | ||
143 | sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G; | ||
144 | sinfo->rxrate.mcs = wil->stats.last_mcs_rx; | ||
145 | |||
146 | if (test_bit(wil_status_fwconnected, &wil->status)) { | ||
147 | sinfo->filled |= STATION_INFO_SIGNAL; | ||
148 | sinfo->signal = 12; /* TODO: provide real value */ | ||
149 | } | ||
150 | |||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static int wil_cfg80211_change_iface(struct wiphy *wiphy, | ||
155 | struct net_device *ndev, | ||
156 | enum nl80211_iftype type, u32 *flags, | ||
157 | struct vif_params *params) | ||
158 | { | ||
159 | struct wil6210_priv *wil = wiphy_to_wil(wiphy); | ||
160 | struct wireless_dev *wdev = wil->wdev; | ||
161 | |||
162 | switch (type) { | ||
163 | case NL80211_IFTYPE_STATION: | ||
164 | case NL80211_IFTYPE_AP: | ||
165 | case NL80211_IFTYPE_P2P_CLIENT: | ||
166 | case NL80211_IFTYPE_P2P_GO: | ||
167 | break; | ||
168 | case NL80211_IFTYPE_MONITOR: | ||
169 | if (flags) | ||
170 | wil->monitor_flags = *flags; | ||
171 | else | ||
172 | wil->monitor_flags = 0; | ||
173 | |||
174 | break; | ||
175 | default: | ||
176 | return -EOPNOTSUPP; | ||
177 | } | ||
178 | |||
179 | wdev->iftype = type; | ||
180 | |||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | static int wil_cfg80211_scan(struct wiphy *wiphy, | ||
185 | struct cfg80211_scan_request *request) | ||
186 | { | ||
187 | struct wil6210_priv *wil = wiphy_to_wil(wiphy); | ||
188 | struct wireless_dev *wdev = wil->wdev; | ||
189 | struct { | ||
190 | struct wmi_start_scan_cmd cmd; | ||
191 | u16 chnl[4]; | ||
192 | } __packed cmd; | ||
193 | uint i, n; | ||
194 | |||
195 | if (wil->scan_request) { | ||
196 | wil_err(wil, "Already scanning\n"); | ||
197 | return -EAGAIN; | ||
198 | } | ||
199 | |||
200 | /* check we are client side */ | ||
201 | switch (wdev->iftype) { | ||
202 | case NL80211_IFTYPE_STATION: | ||
203 | case NL80211_IFTYPE_P2P_CLIENT: | ||
204 | break; | ||
205 | default: | ||
206 | return -EOPNOTSUPP; | ||
207 | |||
208 | } | ||
209 | |||
210 | /* FW don't support scan after connection attempt */ | ||
211 | if (test_bit(wil_status_dontscan, &wil->status)) { | ||
212 | wil_err(wil, "Scan after connect attempt not supported\n"); | ||
213 | return -EBUSY; | ||
214 | } | ||
215 | |||
216 | wil->scan_request = request; | ||
217 | |||
218 | memset(&cmd, 0, sizeof(cmd)); | ||
219 | cmd.cmd.num_channels = 0; | ||
220 | n = min(request->n_channels, 4U); | ||
221 | for (i = 0; i < n; i++) { | ||
222 | int ch = request->channels[i]->hw_value; | ||
223 | if (ch == 0) { | ||
224 | wil_err(wil, | ||
225 | "Scan requested for unknown frequency %dMhz\n", | ||
226 | request->channels[i]->center_freq); | ||
227 | continue; | ||
228 | } | ||
229 | /* 0-based channel indexes */ | ||
230 | cmd.cmd.channel_list[cmd.cmd.num_channels++].channel = ch - 1; | ||
231 | wil_dbg(wil, "Scan for ch %d : %d MHz\n", ch, | ||
232 | request->channels[i]->center_freq); | ||
233 | } | ||
234 | |||
235 | return wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) + | ||
236 | cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0])); | ||
237 | } | ||
238 | |||
239 | static int wil_cfg80211_connect(struct wiphy *wiphy, | ||
240 | struct net_device *ndev, | ||
241 | struct cfg80211_connect_params *sme) | ||
242 | { | ||
243 | struct wil6210_priv *wil = wiphy_to_wil(wiphy); | ||
244 | struct cfg80211_bss *bss; | ||
245 | struct wmi_connect_cmd conn; | ||
246 | const u8 *ssid_eid; | ||
247 | const u8 *rsn_eid; | ||
248 | int ch; | ||
249 | int rc = 0; | ||
250 | |||
251 | bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid, | ||
252 | sme->ssid, sme->ssid_len, | ||
253 | WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); | ||
254 | if (!bss) { | ||
255 | wil_err(wil, "Unable to find BSS\n"); | ||
256 | return -ENOENT; | ||
257 | } | ||
258 | |||
259 | ssid_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SSID); | ||
260 | if (!ssid_eid) { | ||
261 | wil_err(wil, "No SSID\n"); | ||
262 | rc = -ENOENT; | ||
263 | goto out; | ||
264 | } | ||
265 | |||
266 | rsn_eid = sme->ie ? | ||
267 | cfg80211_find_ie(WLAN_EID_RSN, sme->ie, sme->ie_len) : | ||
268 | NULL; | ||
269 | if (rsn_eid) { | ||
270 | if (sme->ie_len > WMI_MAX_IE_LEN) { | ||
271 | rc = -ERANGE; | ||
272 | wil_err(wil, "IE too large (%td bytes)\n", | ||
273 | sme->ie_len); | ||
274 | goto out; | ||
275 | } | ||
276 | /* | ||
277 | * For secure assoc, send: | ||
278 | * (1) WMI_DELETE_CIPHER_KEY_CMD | ||
279 | * (2) WMI_SET_APPIE_CMD | ||
280 | */ | ||
281 | rc = wmi_del_cipher_key(wil, 0, bss->bssid); | ||
282 | if (rc) { | ||
283 | wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD failed\n"); | ||
284 | goto out; | ||
285 | } | ||
286 | /* WMI_SET_APPIE_CMD */ | ||
287 | rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie); | ||
288 | if (rc) { | ||
289 | wil_err(wil, "WMI_SET_APPIE_CMD failed\n"); | ||
290 | goto out; | ||
291 | } | ||
292 | } | ||
293 | |||
294 | /* WMI_CONNECT_CMD */ | ||
295 | memset(&conn, 0, sizeof(conn)); | ||
296 | switch (bss->capability & 0x03) { | ||
297 | case WLAN_CAPABILITY_DMG_TYPE_AP: | ||
298 | conn.network_type = WMI_NETTYPE_INFRA; | ||
299 | break; | ||
300 | case WLAN_CAPABILITY_DMG_TYPE_PBSS: | ||
301 | conn.network_type = WMI_NETTYPE_P2P; | ||
302 | break; | ||
303 | default: | ||
304 | wil_err(wil, "Unsupported BSS type, capability= 0x%04x\n", | ||
305 | bss->capability); | ||
306 | goto out; | ||
307 | } | ||
308 | if (rsn_eid) { | ||
309 | conn.dot11_auth_mode = WMI_AUTH11_SHARED; | ||
310 | conn.auth_mode = WMI_AUTH_WPA2_PSK; | ||
311 | conn.pairwise_crypto_type = WMI_CRYPT_AES_GCMP; | ||
312 | conn.pairwise_crypto_len = 16; | ||
313 | } else { | ||
314 | conn.dot11_auth_mode = WMI_AUTH11_OPEN; | ||
315 | conn.auth_mode = WMI_AUTH_NONE; | ||
316 | } | ||
317 | |||
318 | conn.ssid_len = min_t(u8, ssid_eid[1], 32); | ||
319 | memcpy(conn.ssid, ssid_eid+2, conn.ssid_len); | ||
320 | |||
321 | ch = bss->channel->hw_value; | ||
322 | if (ch == 0) { | ||
323 | wil_err(wil, "BSS at unknown frequency %dMhz\n", | ||
324 | bss->channel->center_freq); | ||
325 | rc = -EOPNOTSUPP; | ||
326 | goto out; | ||
327 | } | ||
328 | conn.channel = ch - 1; | ||
329 | |||
330 | memcpy(conn.bssid, bss->bssid, 6); | ||
331 | memcpy(conn.dst_mac, bss->bssid, 6); | ||
332 | /* | ||
333 | * FW don't support scan after connection attempt | ||
334 | */ | ||
335 | set_bit(wil_status_dontscan, &wil->status); | ||
336 | |||
337 | rc = wmi_send(wil, WMI_CONNECT_CMDID, &conn, sizeof(conn)); | ||
338 | if (rc == 0) { | ||
339 | /* Connect can take lots of time */ | ||
340 | mod_timer(&wil->connect_timer, | ||
341 | jiffies + msecs_to_jiffies(2000)); | ||
342 | } | ||
343 | |||
344 | out: | ||
345 | cfg80211_put_bss(bss); | ||
346 | |||
347 | return rc; | ||
348 | } | ||
349 | |||
350 | static int wil_cfg80211_disconnect(struct wiphy *wiphy, | ||
351 | struct net_device *ndev, | ||
352 | u16 reason_code) | ||
353 | { | ||
354 | int rc; | ||
355 | struct wil6210_priv *wil = wiphy_to_wil(wiphy); | ||
356 | |||
357 | rc = wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0); | ||
358 | |||
359 | return rc; | ||
360 | } | ||
361 | |||
362 | static int wil_cfg80211_set_channel(struct wiphy *wiphy, | ||
363 | struct cfg80211_chan_def *chandef) | ||
364 | { | ||
365 | struct wil6210_priv *wil = wiphy_to_wil(wiphy); | ||
366 | struct wireless_dev *wdev = wil->wdev; | ||
367 | |||
368 | wdev->preset_chandef = *chandef; | ||
369 | |||
370 | return 0; | ||
371 | } | ||
372 | |||
373 | static int wil_cfg80211_add_key(struct wiphy *wiphy, | ||
374 | struct net_device *ndev, | ||
375 | u8 key_index, bool pairwise, | ||
376 | const u8 *mac_addr, | ||
377 | struct key_params *params) | ||
378 | { | ||
379 | struct wil6210_priv *wil = wiphy_to_wil(wiphy); | ||
380 | |||
381 | /* group key is not used */ | ||
382 | if (!pairwise) | ||
383 | return 0; | ||
384 | |||
385 | return wmi_add_cipher_key(wil, key_index, mac_addr, | ||
386 | params->key_len, params->key); | ||
387 | } | ||
388 | |||
389 | static int wil_cfg80211_del_key(struct wiphy *wiphy, | ||
390 | struct net_device *ndev, | ||
391 | u8 key_index, bool pairwise, | ||
392 | const u8 *mac_addr) | ||
393 | { | ||
394 | struct wil6210_priv *wil = wiphy_to_wil(wiphy); | ||
395 | |||
396 | /* group key is not used */ | ||
397 | if (!pairwise) | ||
398 | return 0; | ||
399 | |||
400 | return wmi_del_cipher_key(wil, key_index, mac_addr); | ||
401 | } | ||
402 | |||
403 | /* Need to be present or wiphy_new() will WARN */ | ||
404 | static int wil_cfg80211_set_default_key(struct wiphy *wiphy, | ||
405 | struct net_device *ndev, | ||
406 | u8 key_index, bool unicast, | ||
407 | bool multicast) | ||
408 | { | ||
409 | return 0; | ||
410 | } | ||
411 | |||
412 | static int wil_cfg80211_start_ap(struct wiphy *wiphy, | ||
413 | struct net_device *ndev, | ||
414 | struct cfg80211_ap_settings *info) | ||
415 | { | ||
416 | int rc = 0; | ||
417 | struct wil6210_priv *wil = wiphy_to_wil(wiphy); | ||
418 | struct wireless_dev *wdev = ndev->ieee80211_ptr; | ||
419 | struct ieee80211_channel *channel = info->chandef.chan; | ||
420 | struct cfg80211_beacon_data *bcon = &info->beacon; | ||
421 | u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype); | ||
422 | |||
423 | if (!channel) { | ||
424 | wil_err(wil, "AP: No channel???\n"); | ||
425 | return -EINVAL; | ||
426 | } | ||
427 | |||
428 | wil_dbg(wil, "AP on Channel %d %d MHz, %s\n", channel->hw_value, | ||
429 | channel->center_freq, info->privacy ? "secure" : "open"); | ||
430 | print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET, | ||
431 | info->ssid, info->ssid_len); | ||
432 | |||
433 | rc = wil_reset(wil); | ||
434 | if (rc) | ||
435 | return rc; | ||
436 | |||
437 | rc = wmi_set_ssid(wil, info->ssid_len, info->ssid); | ||
438 | if (rc) | ||
439 | return rc; | ||
440 | |||
441 | rc = wmi_set_channel(wil, channel->hw_value); | ||
442 | if (rc) | ||
443 | return rc; | ||
444 | |||
445 | /* MAC address - pre-requisite for other commands */ | ||
446 | wmi_set_mac_address(wil, ndev->dev_addr); | ||
447 | |||
448 | /* IE's */ | ||
449 | /* bcon 'head IE's are not relevant for 60g band */ | ||
450 | wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len, | ||
451 | bcon->beacon_ies); | ||
452 | wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, bcon->proberesp_ies_len, | ||
453 | bcon->proberesp_ies); | ||
454 | wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, bcon->assocresp_ies_len, | ||
455 | bcon->assocresp_ies); | ||
456 | |||
457 | wil->secure_pcp = info->privacy; | ||
458 | |||
459 | rc = wmi_set_bcon(wil, info->beacon_interval, wmi_nettype); | ||
460 | if (rc) | ||
461 | return rc; | ||
462 | |||
463 | /* Rx VRING. After MAC and beacon */ | ||
464 | rc = wil_rx_init(wil); | ||
465 | |||
466 | netif_carrier_on(ndev); | ||
467 | |||
468 | return rc; | ||
469 | } | ||
470 | |||
471 | static int wil_cfg80211_stop_ap(struct wiphy *wiphy, | ||
472 | struct net_device *ndev) | ||
473 | { | ||
474 | int rc = 0; | ||
475 | struct wil6210_priv *wil = wiphy_to_wil(wiphy); | ||
476 | struct wireless_dev *wdev = ndev->ieee80211_ptr; | ||
477 | u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype); | ||
478 | |||
479 | /* To stop beaconing, set BI to 0 */ | ||
480 | rc = wmi_set_bcon(wil, 0, wmi_nettype); | ||
481 | |||
482 | return rc; | ||
483 | } | ||
484 | |||
485 | static struct cfg80211_ops wil_cfg80211_ops = { | ||
486 | .scan = wil_cfg80211_scan, | ||
487 | .connect = wil_cfg80211_connect, | ||
488 | .disconnect = wil_cfg80211_disconnect, | ||
489 | .change_virtual_intf = wil_cfg80211_change_iface, | ||
490 | .get_station = wil_cfg80211_get_station, | ||
491 | .set_monitor_channel = wil_cfg80211_set_channel, | ||
492 | .add_key = wil_cfg80211_add_key, | ||
493 | .del_key = wil_cfg80211_del_key, | ||
494 | .set_default_key = wil_cfg80211_set_default_key, | ||
495 | /* AP mode */ | ||
496 | .start_ap = wil_cfg80211_start_ap, | ||
497 | .stop_ap = wil_cfg80211_stop_ap, | ||
498 | }; | ||
499 | |||
500 | static void wil_wiphy_init(struct wiphy *wiphy) | ||
501 | { | ||
502 | /* TODO: set real value */ | ||
503 | wiphy->max_scan_ssids = 10; | ||
504 | wiphy->max_num_pmkids = 0 /* TODO: */; | ||
505 | wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | | ||
506 | BIT(NL80211_IFTYPE_AP) | | ||
507 | BIT(NL80211_IFTYPE_MONITOR); | ||
508 | /* TODO: enable P2P when integrated with supplicant: | ||
509 | * BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO) | ||
510 | */ | ||
511 | wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME | | ||
512 | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; | ||
513 | dev_warn(wiphy_dev(wiphy), "%s : flags = 0x%08x\n", | ||
514 | __func__, wiphy->flags); | ||
515 | wiphy->probe_resp_offload = | ||
516 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | | ||
517 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | | ||
518 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P; | ||
519 | |||
520 | wiphy->bands[IEEE80211_BAND_60GHZ] = &wil_band_60ghz; | ||
521 | |||
522 | /* TODO: figure this out */ | ||
523 | wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; | ||
524 | |||
525 | wiphy->cipher_suites = wil_cipher_suites; | ||
526 | wiphy->n_cipher_suites = ARRAY_SIZE(wil_cipher_suites); | ||
527 | wiphy->mgmt_stypes = wil_mgmt_stypes; | ||
528 | } | ||
529 | |||
530 | struct wireless_dev *wil_cfg80211_init(struct device *dev) | ||
531 | { | ||
532 | int rc = 0; | ||
533 | struct wireless_dev *wdev; | ||
534 | |||
535 | wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); | ||
536 | if (!wdev) | ||
537 | return ERR_PTR(-ENOMEM); | ||
538 | |||
539 | wdev->wiphy = wiphy_new(&wil_cfg80211_ops, | ||
540 | sizeof(struct wil6210_priv)); | ||
541 | if (!wdev->wiphy) { | ||
542 | rc = -ENOMEM; | ||
543 | goto out; | ||
544 | } | ||
545 | |||
546 | set_wiphy_dev(wdev->wiphy, dev); | ||
547 | wil_wiphy_init(wdev->wiphy); | ||
548 | |||
549 | rc = wiphy_register(wdev->wiphy); | ||
550 | if (rc < 0) | ||
551 | goto out_failed_reg; | ||
552 | |||
553 | return wdev; | ||
554 | |||
555 | out_failed_reg: | ||
556 | wiphy_free(wdev->wiphy); | ||
557 | out: | ||
558 | kfree(wdev); | ||
559 | |||
560 | return ERR_PTR(rc); | ||
561 | } | ||
562 | |||
563 | void wil_wdev_free(struct wil6210_priv *wil) | ||
564 | { | ||
565 | struct wireless_dev *wdev = wil_to_wdev(wil); | ||
566 | |||
567 | if (!wdev) | ||
568 | return; | ||
569 | |||
570 | wiphy_unregister(wdev->wiphy); | ||
571 | wiphy_free(wdev->wiphy); | ||
572 | kfree(wdev); | ||
573 | } | ||
diff --git a/drivers/net/wireless/ath/wil6210/dbg_hexdump.h b/drivers/net/wireless/ath/wil6210/dbg_hexdump.h new file mode 100644 index 000000000000..6a315ba5aa7d --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/dbg_hexdump.h | |||
@@ -0,0 +1,30 @@ | |||
1 | #ifndef WIL_DBG_HEXDUMP_H_ | ||
2 | #define WIL_DBG_HEXDUMP_H_ | ||
3 | |||
4 | #if defined(CONFIG_DYNAMIC_DEBUG) | ||
5 | #define wil_dynamic_hex_dump(prefix_str, prefix_type, rowsize, \ | ||
6 | groupsize, buf, len, ascii) \ | ||
7 | do { \ | ||
8 | DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, \ | ||
9 | __builtin_constant_p(prefix_str) ? prefix_str : "hexdump");\ | ||
10 | if (unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT)) \ | ||
11 | print_hex_dump(KERN_DEBUG, prefix_str, \ | ||
12 | prefix_type, rowsize, groupsize, \ | ||
13 | buf, len, ascii); \ | ||
14 | } while (0) | ||
15 | |||
16 | #define wil_print_hex_dump_debug(prefix_str, prefix_type, rowsize, \ | ||
17 | groupsize, buf, len, ascii) \ | ||
18 | wil_dynamic_hex_dump(prefix_str, prefix_type, rowsize, \ | ||
19 | groupsize, buf, len, ascii) | ||
20 | |||
21 | #define print_hex_dump_bytes(prefix_str, prefix_type, buf, len) \ | ||
22 | wil_dynamic_hex_dump(prefix_str, prefix_type, 16, 1, buf, len, true) | ||
23 | #else /* defined(CONFIG_DYNAMIC_DEBUG) */ | ||
24 | #define wil_print_hex_dump_debug(prefix_str, prefix_type, rowsize, \ | ||
25 | groupsize, buf, len, ascii) \ | ||
26 | print_hex_dump(KERN_DEBUG, prefix_str, prefix_type, rowsize, \ | ||
27 | groupsize, buf, len, ascii) | ||
28 | #endif /* defined(CONFIG_DYNAMIC_DEBUG) */ | ||
29 | |||
30 | #endif /* WIL_DBG_HEXDUMP_H_ */ | ||
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c new file mode 100644 index 000000000000..65fc9683bfd8 --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/debugfs.c | |||
@@ -0,0 +1,603 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012 Qualcomm Atheros, Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <linux/debugfs.h> | ||
19 | #include <linux/seq_file.h> | ||
20 | #include <linux/pci.h> | ||
21 | #include <linux/rtnetlink.h> | ||
22 | |||
23 | #include "wil6210.h" | ||
24 | #include "txrx.h" | ||
25 | |||
26 | /* Nasty hack. Better have per device instances */ | ||
27 | static u32 mem_addr; | ||
28 | static u32 dbg_txdesc_index; | ||
29 | |||
30 | static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil, | ||
31 | const char *name, struct vring *vring) | ||
32 | { | ||
33 | void __iomem *x = wmi_addr(wil, vring->hwtail); | ||
34 | |||
35 | seq_printf(s, "VRING %s = {\n", name); | ||
36 | seq_printf(s, " pa = 0x%016llx\n", (unsigned long long)vring->pa); | ||
37 | seq_printf(s, " va = 0x%p\n", vring->va); | ||
38 | seq_printf(s, " size = %d\n", vring->size); | ||
39 | seq_printf(s, " swtail = %d\n", vring->swtail); | ||
40 | seq_printf(s, " swhead = %d\n", vring->swhead); | ||
41 | seq_printf(s, " hwtail = [0x%08x] -> ", vring->hwtail); | ||
42 | if (x) | ||
43 | seq_printf(s, "0x%08x\n", ioread32(x)); | ||
44 | else | ||
45 | seq_printf(s, "???\n"); | ||
46 | |||
47 | if (vring->va && (vring->size < 1025)) { | ||
48 | uint i; | ||
49 | for (i = 0; i < vring->size; i++) { | ||
50 | volatile struct vring_tx_desc *d = &vring->va[i].tx; | ||
51 | if ((i % 64) == 0 && (i != 0)) | ||
52 | seq_printf(s, "\n"); | ||
53 | seq_printf(s, "%s", (d->dma.status & BIT(0)) ? | ||
54 | "S" : (vring->ctx[i] ? "H" : "h")); | ||
55 | } | ||
56 | seq_printf(s, "\n"); | ||
57 | } | ||
58 | seq_printf(s, "}\n"); | ||
59 | } | ||
60 | |||
61 | static int wil_vring_debugfs_show(struct seq_file *s, void *data) | ||
62 | { | ||
63 | uint i; | ||
64 | struct wil6210_priv *wil = s->private; | ||
65 | |||
66 | wil_print_vring(s, wil, "rx", &wil->vring_rx); | ||
67 | |||
68 | for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) { | ||
69 | struct vring *vring = &(wil->vring_tx[i]); | ||
70 | if (vring->va) { | ||
71 | char name[10]; | ||
72 | snprintf(name, sizeof(name), "tx_%2d", i); | ||
73 | wil_print_vring(s, wil, name, vring); | ||
74 | } | ||
75 | } | ||
76 | |||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | static int wil_vring_seq_open(struct inode *inode, struct file *file) | ||
81 | { | ||
82 | return single_open(file, wil_vring_debugfs_show, inode->i_private); | ||
83 | } | ||
84 | |||
85 | static const struct file_operations fops_vring = { | ||
86 | .open = wil_vring_seq_open, | ||
87 | .release = single_release, | ||
88 | .read = seq_read, | ||
89 | .llseek = seq_lseek, | ||
90 | }; | ||
91 | |||
92 | static void wil_print_ring(struct seq_file *s, const char *prefix, | ||
93 | void __iomem *off) | ||
94 | { | ||
95 | struct wil6210_priv *wil = s->private; | ||
96 | struct wil6210_mbox_ring r; | ||
97 | int rsize; | ||
98 | uint i; | ||
99 | |||
100 | wil_memcpy_fromio_32(&r, off, sizeof(r)); | ||
101 | wil_mbox_ring_le2cpus(&r); | ||
102 | /* | ||
103 | * we just read memory block from NIC. This memory may be | ||
104 | * garbage. Check validity before using it. | ||
105 | */ | ||
106 | rsize = r.size / sizeof(struct wil6210_mbox_ring_desc); | ||
107 | |||
108 | seq_printf(s, "ring %s = {\n", prefix); | ||
109 | seq_printf(s, " base = 0x%08x\n", r.base); | ||
110 | seq_printf(s, " size = 0x%04x bytes -> %d entries\n", r.size, rsize); | ||
111 | seq_printf(s, " tail = 0x%08x\n", r.tail); | ||
112 | seq_printf(s, " head = 0x%08x\n", r.head); | ||
113 | seq_printf(s, " entry size = %d\n", r.entry_size); | ||
114 | |||
115 | if (r.size % sizeof(struct wil6210_mbox_ring_desc)) { | ||
116 | seq_printf(s, " ??? size is not multiple of %zd, garbage?\n", | ||
117 | sizeof(struct wil6210_mbox_ring_desc)); | ||
118 | goto out; | ||
119 | } | ||
120 | |||
121 | if (!wmi_addr(wil, r.base) || | ||
122 | !wmi_addr(wil, r.tail) || | ||
123 | !wmi_addr(wil, r.head)) { | ||
124 | seq_printf(s, " ??? pointers are garbage?\n"); | ||
125 | goto out; | ||
126 | } | ||
127 | |||
128 | for (i = 0; i < rsize; i++) { | ||
129 | struct wil6210_mbox_ring_desc d; | ||
130 | struct wil6210_mbox_hdr hdr; | ||
131 | size_t delta = i * sizeof(d); | ||
132 | void __iomem *x = wil->csr + HOSTADDR(r.base) + delta; | ||
133 | |||
134 | wil_memcpy_fromio_32(&d, x, sizeof(d)); | ||
135 | |||
136 | seq_printf(s, " [%2x] %s %s%s 0x%08x", i, | ||
137 | d.sync ? "F" : "E", | ||
138 | (r.tail - r.base == delta) ? "t" : " ", | ||
139 | (r.head - r.base == delta) ? "h" : " ", | ||
140 | le32_to_cpu(d.addr)); | ||
141 | if (0 == wmi_read_hdr(wil, d.addr, &hdr)) { | ||
142 | u16 len = le16_to_cpu(hdr.len); | ||
143 | seq_printf(s, " -> %04x %04x %04x %02x\n", | ||
144 | le16_to_cpu(hdr.seq), len, | ||
145 | le16_to_cpu(hdr.type), hdr.flags); | ||
146 | if (len <= MAX_MBOXITEM_SIZE) { | ||
147 | int n = 0; | ||
148 | unsigned char printbuf[16 * 3 + 2]; | ||
149 | unsigned char databuf[MAX_MBOXITEM_SIZE]; | ||
150 | void __iomem *src = wmi_buffer(wil, d.addr) + | ||
151 | sizeof(struct wil6210_mbox_hdr); | ||
152 | /* | ||
153 | * No need to check @src for validity - | ||
154 | * we already validated @d.addr while | ||
155 | * reading header | ||
156 | */ | ||
157 | wil_memcpy_fromio_32(databuf, src, len); | ||
158 | while (n < len) { | ||
159 | int l = min(len - n, 16); | ||
160 | hex_dump_to_buffer(databuf + n, l, | ||
161 | 16, 1, printbuf, | ||
162 | sizeof(printbuf), | ||
163 | false); | ||
164 | seq_printf(s, " : %s\n", printbuf); | ||
165 | n += l; | ||
166 | } | ||
167 | } | ||
168 | } else { | ||
169 | seq_printf(s, "\n"); | ||
170 | } | ||
171 | } | ||
172 | out: | ||
173 | seq_printf(s, "}\n"); | ||
174 | } | ||
175 | |||
176 | static int wil_mbox_debugfs_show(struct seq_file *s, void *data) | ||
177 | { | ||
178 | struct wil6210_priv *wil = s->private; | ||
179 | |||
180 | wil_print_ring(s, "tx", wil->csr + HOST_MBOX + | ||
181 | offsetof(struct wil6210_mbox_ctl, tx)); | ||
182 | wil_print_ring(s, "rx", wil->csr + HOST_MBOX + | ||
183 | offsetof(struct wil6210_mbox_ctl, rx)); | ||
184 | |||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | static int wil_mbox_seq_open(struct inode *inode, struct file *file) | ||
189 | { | ||
190 | return single_open(file, wil_mbox_debugfs_show, inode->i_private); | ||
191 | } | ||
192 | |||
193 | static const struct file_operations fops_mbox = { | ||
194 | .open = wil_mbox_seq_open, | ||
195 | .release = single_release, | ||
196 | .read = seq_read, | ||
197 | .llseek = seq_lseek, | ||
198 | }; | ||
199 | |||
200 | static int wil_debugfs_iomem_x32_set(void *data, u64 val) | ||
201 | { | ||
202 | iowrite32(val, (void __iomem *)data); | ||
203 | wmb(); /* make sure write propagated to HW */ | ||
204 | |||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | static int wil_debugfs_iomem_x32_get(void *data, u64 *val) | ||
209 | { | ||
210 | *val = ioread32((void __iomem *)data); | ||
211 | |||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, wil_debugfs_iomem_x32_get, | ||
216 | wil_debugfs_iomem_x32_set, "0x%08llx\n"); | ||
217 | |||
218 | static struct dentry *wil_debugfs_create_iomem_x32(const char *name, | ||
219 | mode_t mode, | ||
220 | struct dentry *parent, | ||
221 | void __iomem *value) | ||
222 | { | ||
223 | return debugfs_create_file(name, mode, parent, (void * __force)value, | ||
224 | &fops_iomem_x32); | ||
225 | } | ||
226 | |||
227 | static int wil6210_debugfs_create_ISR(struct wil6210_priv *wil, | ||
228 | const char *name, | ||
229 | struct dentry *parent, u32 off) | ||
230 | { | ||
231 | struct dentry *d = debugfs_create_dir(name, parent); | ||
232 | |||
233 | if (IS_ERR_OR_NULL(d)) | ||
234 | return -ENODEV; | ||
235 | |||
236 | wil_debugfs_create_iomem_x32("ICC", S_IRUGO | S_IWUSR, d, | ||
237 | wil->csr + off); | ||
238 | wil_debugfs_create_iomem_x32("ICR", S_IRUGO | S_IWUSR, d, | ||
239 | wil->csr + off + 4); | ||
240 | wil_debugfs_create_iomem_x32("ICM", S_IRUGO | S_IWUSR, d, | ||
241 | wil->csr + off + 8); | ||
242 | wil_debugfs_create_iomem_x32("ICS", S_IWUSR, d, | ||
243 | wil->csr + off + 12); | ||
244 | wil_debugfs_create_iomem_x32("IMV", S_IRUGO | S_IWUSR, d, | ||
245 | wil->csr + off + 16); | ||
246 | wil_debugfs_create_iomem_x32("IMS", S_IWUSR, d, | ||
247 | wil->csr + off + 20); | ||
248 | wil_debugfs_create_iomem_x32("IMC", S_IWUSR, d, | ||
249 | wil->csr + off + 24); | ||
250 | |||
251 | return 0; | ||
252 | } | ||
253 | |||
254 | static int wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv *wil, | ||
255 | struct dentry *parent) | ||
256 | { | ||
257 | struct dentry *d = debugfs_create_dir("PSEUDO_ISR", parent); | ||
258 | |||
259 | if (IS_ERR_OR_NULL(d)) | ||
260 | return -ENODEV; | ||
261 | |||
262 | wil_debugfs_create_iomem_x32("CAUSE", S_IRUGO, d, wil->csr + | ||
263 | HOSTADDR(RGF_DMA_PSEUDO_CAUSE)); | ||
264 | wil_debugfs_create_iomem_x32("MASK_SW", S_IRUGO, d, wil->csr + | ||
265 | HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW)); | ||
266 | wil_debugfs_create_iomem_x32("MASK_FW", S_IRUGO, d, wil->csr + | ||
267 | HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_FW)); | ||
268 | |||
269 | return 0; | ||
270 | } | ||
271 | |||
272 | static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil, | ||
273 | struct dentry *parent) | ||
274 | { | ||
275 | struct dentry *d = debugfs_create_dir("ITR_CNT", parent); | ||
276 | |||
277 | if (IS_ERR_OR_NULL(d)) | ||
278 | return -ENODEV; | ||
279 | |||
280 | wil_debugfs_create_iomem_x32("TRSH", S_IRUGO, d, wil->csr + | ||
281 | HOSTADDR(RGF_DMA_ITR_CNT_TRSH)); | ||
282 | wil_debugfs_create_iomem_x32("DATA", S_IRUGO, d, wil->csr + | ||
283 | HOSTADDR(RGF_DMA_ITR_CNT_DATA)); | ||
284 | wil_debugfs_create_iomem_x32("CTL", S_IRUGO, d, wil->csr + | ||
285 | HOSTADDR(RGF_DMA_ITR_CNT_CRL)); | ||
286 | |||
287 | return 0; | ||
288 | } | ||
289 | |||
290 | static int wil_memread_debugfs_show(struct seq_file *s, void *data) | ||
291 | { | ||
292 | struct wil6210_priv *wil = s->private; | ||
293 | void __iomem *a = wmi_buffer(wil, cpu_to_le32(mem_addr)); | ||
294 | |||
295 | if (a) | ||
296 | seq_printf(s, "[0x%08x] = 0x%08x\n", mem_addr, ioread32(a)); | ||
297 | else | ||
298 | seq_printf(s, "[0x%08x] = INVALID\n", mem_addr); | ||
299 | |||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | static int wil_memread_seq_open(struct inode *inode, struct file *file) | ||
304 | { | ||
305 | return single_open(file, wil_memread_debugfs_show, inode->i_private); | ||
306 | } | ||
307 | |||
308 | static const struct file_operations fops_memread = { | ||
309 | .open = wil_memread_seq_open, | ||
310 | .release = single_release, | ||
311 | .read = seq_read, | ||
312 | .llseek = seq_lseek, | ||
313 | }; | ||
314 | |||
315 | static int wil_default_open(struct inode *inode, struct file *file) | ||
316 | { | ||
317 | if (inode->i_private) | ||
318 | file->private_data = inode->i_private; | ||
319 | |||
320 | return 0; | ||
321 | } | ||
322 | |||
323 | static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf, | ||
324 | size_t count, loff_t *ppos) | ||
325 | { | ||
326 | enum { max_count = 4096 }; | ||
327 | struct debugfs_blob_wrapper *blob = file->private_data; | ||
328 | loff_t pos = *ppos; | ||
329 | size_t available = blob->size; | ||
330 | void *buf; | ||
331 | size_t ret; | ||
332 | |||
333 | if (pos < 0) | ||
334 | return -EINVAL; | ||
335 | |||
336 | if (pos >= available || !count) | ||
337 | return 0; | ||
338 | |||
339 | if (count > available - pos) | ||
340 | count = available - pos; | ||
341 | if (count > max_count) | ||
342 | count = max_count; | ||
343 | |||
344 | buf = kmalloc(count, GFP_KERNEL); | ||
345 | if (!buf) | ||
346 | return -ENOMEM; | ||
347 | |||
348 | wil_memcpy_fromio_32(buf, (const volatile void __iomem *)blob->data + | ||
349 | pos, count); | ||
350 | |||
351 | ret = copy_to_user(user_buf, buf, count); | ||
352 | kfree(buf); | ||
353 | if (ret == count) | ||
354 | return -EFAULT; | ||
355 | |||
356 | count -= ret; | ||
357 | *ppos = pos + count; | ||
358 | |||
359 | return count; | ||
360 | } | ||
361 | |||
362 | static const struct file_operations fops_ioblob = { | ||
363 | .read = wil_read_file_ioblob, | ||
364 | .open = wil_default_open, | ||
365 | .llseek = default_llseek, | ||
366 | }; | ||
367 | |||
368 | static | ||
369 | struct dentry *wil_debugfs_create_ioblob(const char *name, | ||
370 | mode_t mode, | ||
371 | struct dentry *parent, | ||
372 | struct debugfs_blob_wrapper *blob) | ||
373 | { | ||
374 | return debugfs_create_file(name, mode, parent, blob, &fops_ioblob); | ||
375 | } | ||
376 | /*---reset---*/ | ||
377 | static ssize_t wil_write_file_reset(struct file *file, const char __user *buf, | ||
378 | size_t len, loff_t *ppos) | ||
379 | { | ||
380 | struct wil6210_priv *wil = file->private_data; | ||
381 | struct net_device *ndev = wil_to_ndev(wil); | ||
382 | |||
383 | /** | ||
384 | * BUG: | ||
385 | * this code does NOT sync device state with the rest of system | ||
386 | * use with care, debug only!!! | ||
387 | */ | ||
388 | rtnl_lock(); | ||
389 | dev_close(ndev); | ||
390 | ndev->flags &= ~IFF_UP; | ||
391 | rtnl_unlock(); | ||
392 | wil_reset(wil); | ||
393 | |||
394 | return len; | ||
395 | } | ||
396 | |||
397 | static const struct file_operations fops_reset = { | ||
398 | .write = wil_write_file_reset, | ||
399 | .open = wil_default_open, | ||
400 | }; | ||
401 | /*---------Tx descriptor------------*/ | ||
402 | |||
403 | static int wil_txdesc_debugfs_show(struct seq_file *s, void *data) | ||
404 | { | ||
405 | struct wil6210_priv *wil = s->private; | ||
406 | struct vring *vring = &(wil->vring_tx[0]); | ||
407 | |||
408 | if (!vring->va) { | ||
409 | seq_printf(s, "No Tx VRING\n"); | ||
410 | return 0; | ||
411 | } | ||
412 | |||
413 | if (dbg_txdesc_index < vring->size) { | ||
414 | volatile struct vring_tx_desc *d = | ||
415 | &(vring->va[dbg_txdesc_index].tx); | ||
416 | volatile u32 *u = (volatile u32 *)d; | ||
417 | struct sk_buff *skb = vring->ctx[dbg_txdesc_index]; | ||
418 | |||
419 | seq_printf(s, "Tx[%3d] = {\n", dbg_txdesc_index); | ||
420 | seq_printf(s, " MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n", | ||
421 | u[0], u[1], u[2], u[3]); | ||
422 | seq_printf(s, " DMA = 0x%08x 0x%08x 0x%08x 0x%08x\n", | ||
423 | u[4], u[5], u[6], u[7]); | ||
424 | seq_printf(s, " SKB = %p\n", skb); | ||
425 | |||
426 | if (skb) { | ||
427 | unsigned char printbuf[16 * 3 + 2]; | ||
428 | int i = 0; | ||
429 | int len = skb_headlen(skb); | ||
430 | void *p = skb->data; | ||
431 | |||
432 | seq_printf(s, " len = %d\n", len); | ||
433 | |||
434 | while (i < len) { | ||
435 | int l = min(len - i, 16); | ||
436 | hex_dump_to_buffer(p + i, l, 16, 1, printbuf, | ||
437 | sizeof(printbuf), false); | ||
438 | seq_printf(s, " : %s\n", printbuf); | ||
439 | i += l; | ||
440 | } | ||
441 | } | ||
442 | seq_printf(s, "}\n"); | ||
443 | } else { | ||
444 | seq_printf(s, "TxDesc index (%d) >= size (%d)\n", | ||
445 | dbg_txdesc_index, vring->size); | ||
446 | } | ||
447 | |||
448 | return 0; | ||
449 | } | ||
450 | |||
451 | static int wil_txdesc_seq_open(struct inode *inode, struct file *file) | ||
452 | { | ||
453 | return single_open(file, wil_txdesc_debugfs_show, inode->i_private); | ||
454 | } | ||
455 | |||
456 | static const struct file_operations fops_txdesc = { | ||
457 | .open = wil_txdesc_seq_open, | ||
458 | .release = single_release, | ||
459 | .read = seq_read, | ||
460 | .llseek = seq_lseek, | ||
461 | }; | ||
462 | |||
463 | /*---------beamforming------------*/ | ||
464 | static int wil_bf_debugfs_show(struct seq_file *s, void *data) | ||
465 | { | ||
466 | struct wil6210_priv *wil = s->private; | ||
467 | seq_printf(s, | ||
468 | "TSF : 0x%016llx\n" | ||
469 | "TxMCS : %d\n" | ||
470 | "Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n", | ||
471 | wil->stats.tsf, wil->stats.bf_mcs, | ||
472 | wil->stats.my_rx_sector, wil->stats.my_tx_sector, | ||
473 | wil->stats.peer_rx_sector, wil->stats.peer_tx_sector); | ||
474 | return 0; | ||
475 | } | ||
476 | |||
477 | static int wil_bf_seq_open(struct inode *inode, struct file *file) | ||
478 | { | ||
479 | return single_open(file, wil_bf_debugfs_show, inode->i_private); | ||
480 | } | ||
481 | |||
482 | static const struct file_operations fops_bf = { | ||
483 | .open = wil_bf_seq_open, | ||
484 | .release = single_release, | ||
485 | .read = seq_read, | ||
486 | .llseek = seq_lseek, | ||
487 | }; | ||
488 | /*---------SSID------------*/ | ||
489 | static ssize_t wil_read_file_ssid(struct file *file, char __user *user_buf, | ||
490 | size_t count, loff_t *ppos) | ||
491 | { | ||
492 | struct wil6210_priv *wil = file->private_data; | ||
493 | struct wireless_dev *wdev = wil_to_wdev(wil); | ||
494 | |||
495 | return simple_read_from_buffer(user_buf, count, ppos, | ||
496 | wdev->ssid, wdev->ssid_len); | ||
497 | } | ||
498 | |||
499 | static ssize_t wil_write_file_ssid(struct file *file, const char __user *buf, | ||
500 | size_t count, loff_t *ppos) | ||
501 | { | ||
502 | struct wil6210_priv *wil = file->private_data; | ||
503 | struct wireless_dev *wdev = wil_to_wdev(wil); | ||
504 | struct net_device *ndev = wil_to_ndev(wil); | ||
505 | |||
506 | if (*ppos != 0) { | ||
507 | wil_err(wil, "Unable to set SSID substring from [%d]\n", | ||
508 | (int)*ppos); | ||
509 | return -EINVAL; | ||
510 | } | ||
511 | |||
512 | if (count > sizeof(wdev->ssid)) { | ||
513 | wil_err(wil, "SSID too long, len = %d\n", (int)count); | ||
514 | return -EINVAL; | ||
515 | } | ||
516 | if (netif_running(ndev)) { | ||
517 | wil_err(wil, "Unable to change SSID on running interface\n"); | ||
518 | return -EINVAL; | ||
519 | } | ||
520 | |||
521 | wdev->ssid_len = count; | ||
522 | return simple_write_to_buffer(wdev->ssid, wdev->ssid_len, ppos, | ||
523 | buf, count); | ||
524 | } | ||
525 | |||
526 | static const struct file_operations fops_ssid = { | ||
527 | .read = wil_read_file_ssid, | ||
528 | .write = wil_write_file_ssid, | ||
529 | .open = wil_default_open, | ||
530 | }; | ||
531 | |||
532 | /*----------------*/ | ||
533 | int wil6210_debugfs_init(struct wil6210_priv *wil) | ||
534 | { | ||
535 | struct dentry *dbg = wil->debug = debugfs_create_dir(WIL_NAME, | ||
536 | wil_to_wiphy(wil)->debugfsdir); | ||
537 | |||
538 | if (IS_ERR_OR_NULL(dbg)) | ||
539 | return -ENODEV; | ||
540 | |||
541 | debugfs_create_file("mbox", S_IRUGO, dbg, wil, &fops_mbox); | ||
542 | debugfs_create_file("vrings", S_IRUGO, dbg, wil, &fops_vring); | ||
543 | debugfs_create_file("txdesc", S_IRUGO, dbg, wil, &fops_txdesc); | ||
544 | debugfs_create_u32("txdesc_index", S_IRUGO | S_IWUSR, dbg, | ||
545 | &dbg_txdesc_index); | ||
546 | debugfs_create_file("bf", S_IRUGO, dbg, wil, &fops_bf); | ||
547 | debugfs_create_file("ssid", S_IRUGO | S_IWUSR, dbg, wil, &fops_ssid); | ||
548 | debugfs_create_u32("secure_pcp", S_IRUGO | S_IWUSR, dbg, | ||
549 | &wil->secure_pcp); | ||
550 | |||
551 | wil6210_debugfs_create_ISR(wil, "USER_ICR", dbg, | ||
552 | HOSTADDR(RGF_USER_USER_ICR)); | ||
553 | wil6210_debugfs_create_ISR(wil, "DMA_EP_TX_ICR", dbg, | ||
554 | HOSTADDR(RGF_DMA_EP_TX_ICR)); | ||
555 | wil6210_debugfs_create_ISR(wil, "DMA_EP_RX_ICR", dbg, | ||
556 | HOSTADDR(RGF_DMA_EP_RX_ICR)); | ||
557 | wil6210_debugfs_create_ISR(wil, "DMA_EP_MISC_ICR", dbg, | ||
558 | HOSTADDR(RGF_DMA_EP_MISC_ICR)); | ||
559 | wil6210_debugfs_create_pseudo_ISR(wil, dbg); | ||
560 | wil6210_debugfs_create_ITR_CNT(wil, dbg); | ||
561 | |||
562 | debugfs_create_u32("mem_addr", S_IRUGO | S_IWUSR, dbg, &mem_addr); | ||
563 | debugfs_create_file("mem_val", S_IRUGO, dbg, wil, &fops_memread); | ||
564 | |||
565 | debugfs_create_file("reset", S_IWUSR, dbg, wil, &fops_reset); | ||
566 | |||
567 | wil->rgf_blob.data = (void * __force)wil->csr + 0; | ||
568 | wil->rgf_blob.size = 0xa000; | ||
569 | wil_debugfs_create_ioblob("blob_rgf", S_IRUGO, dbg, &wil->rgf_blob); | ||
570 | |||
571 | wil->fw_code_blob.data = (void * __force)wil->csr + 0x40000; | ||
572 | wil->fw_code_blob.size = 0x40000; | ||
573 | wil_debugfs_create_ioblob("blob_fw_code", S_IRUGO, dbg, | ||
574 | &wil->fw_code_blob); | ||
575 | |||
576 | wil->fw_data_blob.data = (void * __force)wil->csr + 0x80000; | ||
577 | wil->fw_data_blob.size = 0x8000; | ||
578 | wil_debugfs_create_ioblob("blob_fw_data", S_IRUGO, dbg, | ||
579 | &wil->fw_data_blob); | ||
580 | |||
581 | wil->fw_peri_blob.data = (void * __force)wil->csr + 0x88000; | ||
582 | wil->fw_peri_blob.size = 0x18000; | ||
583 | wil_debugfs_create_ioblob("blob_fw_peri", S_IRUGO, dbg, | ||
584 | &wil->fw_peri_blob); | ||
585 | |||
586 | wil->uc_code_blob.data = (void * __force)wil->csr + 0xa0000; | ||
587 | wil->uc_code_blob.size = 0x10000; | ||
588 | wil_debugfs_create_ioblob("blob_uc_code", S_IRUGO, dbg, | ||
589 | &wil->uc_code_blob); | ||
590 | |||
591 | wil->uc_data_blob.data = (void * __force)wil->csr + 0xb0000; | ||
592 | wil->uc_data_blob.size = 0x4000; | ||
593 | wil_debugfs_create_ioblob("blob_uc_data", S_IRUGO, dbg, | ||
594 | &wil->uc_data_blob); | ||
595 | |||
596 | return 0; | ||
597 | } | ||
598 | |||
599 | void wil6210_debugfs_remove(struct wil6210_priv *wil) | ||
600 | { | ||
601 | debugfs_remove_recursive(wil->debug); | ||
602 | wil->debug = NULL; | ||
603 | } | ||
diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c new file mode 100644 index 000000000000..38049da71049 --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/interrupt.c | |||
@@ -0,0 +1,471 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012 Qualcomm Atheros, Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include <linux/interrupt.h> | ||
18 | |||
19 | #include "wil6210.h" | ||
20 | |||
21 | /** | ||
22 | * Theory of operation: | ||
23 | * | ||
24 | * There is ISR pseudo-cause register, | ||
25 | * dma_rgf->DMA_RGF.PSEUDO_CAUSE.PSEUDO_CAUSE | ||
26 | * Its bits represents OR'ed bits from 3 real ISR registers: | ||
27 | * TX, RX, and MISC. | ||
28 | * | ||
29 | * Registers may be configured to either "write 1 to clear" or | ||
30 | * "clear on read" mode | ||
31 | * | ||
32 | * When handling interrupt, one have to mask/unmask interrupts for the | ||
33 | * real ISR registers, or hardware may malfunction. | ||
34 | * | ||
35 | */ | ||
36 | |||
37 | #define WIL6210_IRQ_DISABLE (0xFFFFFFFFUL) | ||
38 | #define WIL6210_IMC_RX BIT_DMA_EP_RX_ICR_RX_DONE | ||
39 | #define WIL6210_IMC_TX (BIT_DMA_EP_TX_ICR_TX_DONE | \ | ||
40 | BIT_DMA_EP_TX_ICR_TX_DONE_N(0)) | ||
41 | #define WIL6210_IMC_MISC (ISR_MISC_FW_READY | ISR_MISC_MBOX_EVT) | ||
42 | |||
43 | #define WIL6210_IRQ_PSEUDO_MASK (u32)(~(BIT_DMA_PSEUDO_CAUSE_RX | \ | ||
44 | BIT_DMA_PSEUDO_CAUSE_TX | \ | ||
45 | BIT_DMA_PSEUDO_CAUSE_MISC)) | ||
46 | |||
47 | #if defined(CONFIG_WIL6210_ISR_COR) | ||
48 | /* configure to Clear-On-Read mode */ | ||
49 | #define WIL_ICR_ICC_VALUE (0xFFFFFFFFUL) | ||
50 | |||
51 | static inline void wil_icr_clear(u32 x, void __iomem *addr) | ||
52 | { | ||
53 | |||
54 | } | ||
55 | #else /* defined(CONFIG_WIL6210_ISR_COR) */ | ||
56 | /* configure to Write-1-to-Clear mode */ | ||
57 | #define WIL_ICR_ICC_VALUE (0UL) | ||
58 | |||
59 | static inline void wil_icr_clear(u32 x, void __iomem *addr) | ||
60 | { | ||
61 | iowrite32(x, addr); | ||
62 | } | ||
63 | #endif /* defined(CONFIG_WIL6210_ISR_COR) */ | ||
64 | |||
65 | static inline u32 wil_ioread32_and_clear(void __iomem *addr) | ||
66 | { | ||
67 | u32 x = ioread32(addr); | ||
68 | |||
69 | wil_icr_clear(x, addr); | ||
70 | |||
71 | return x; | ||
72 | } | ||
73 | |||
74 | static void wil6210_mask_irq_tx(struct wil6210_priv *wil) | ||
75 | { | ||
76 | iowrite32(WIL6210_IRQ_DISABLE, wil->csr + | ||
77 | HOSTADDR(RGF_DMA_EP_TX_ICR) + | ||
78 | offsetof(struct RGF_ICR, IMS)); | ||
79 | } | ||
80 | |||
81 | static void wil6210_mask_irq_rx(struct wil6210_priv *wil) | ||
82 | { | ||
83 | iowrite32(WIL6210_IRQ_DISABLE, wil->csr + | ||
84 | HOSTADDR(RGF_DMA_EP_RX_ICR) + | ||
85 | offsetof(struct RGF_ICR, IMS)); | ||
86 | } | ||
87 | |||
88 | static void wil6210_mask_irq_misc(struct wil6210_priv *wil) | ||
89 | { | ||
90 | iowrite32(WIL6210_IRQ_DISABLE, wil->csr + | ||
91 | HOSTADDR(RGF_DMA_EP_MISC_ICR) + | ||
92 | offsetof(struct RGF_ICR, IMS)); | ||
93 | } | ||
94 | |||
95 | static void wil6210_mask_irq_pseudo(struct wil6210_priv *wil) | ||
96 | { | ||
97 | wil_dbg_IRQ(wil, "%s()\n", __func__); | ||
98 | |||
99 | iowrite32(WIL6210_IRQ_DISABLE, wil->csr + | ||
100 | HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW)); | ||
101 | |||
102 | clear_bit(wil_status_irqen, &wil->status); | ||
103 | } | ||
104 | |||
105 | static void wil6210_unmask_irq_tx(struct wil6210_priv *wil) | ||
106 | { | ||
107 | iowrite32(WIL6210_IMC_TX, wil->csr + | ||
108 | HOSTADDR(RGF_DMA_EP_TX_ICR) + | ||
109 | offsetof(struct RGF_ICR, IMC)); | ||
110 | } | ||
111 | |||
112 | static void wil6210_unmask_irq_rx(struct wil6210_priv *wil) | ||
113 | { | ||
114 | iowrite32(WIL6210_IMC_RX, wil->csr + | ||
115 | HOSTADDR(RGF_DMA_EP_RX_ICR) + | ||
116 | offsetof(struct RGF_ICR, IMC)); | ||
117 | } | ||
118 | |||
119 | static void wil6210_unmask_irq_misc(struct wil6210_priv *wil) | ||
120 | { | ||
121 | iowrite32(WIL6210_IMC_MISC, wil->csr + | ||
122 | HOSTADDR(RGF_DMA_EP_MISC_ICR) + | ||
123 | offsetof(struct RGF_ICR, IMC)); | ||
124 | } | ||
125 | |||
126 | static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil) | ||
127 | { | ||
128 | wil_dbg_IRQ(wil, "%s()\n", __func__); | ||
129 | |||
130 | set_bit(wil_status_irqen, &wil->status); | ||
131 | |||
132 | iowrite32(WIL6210_IRQ_PSEUDO_MASK, wil->csr + | ||
133 | HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW)); | ||
134 | } | ||
135 | |||
136 | void wil6210_disable_irq(struct wil6210_priv *wil) | ||
137 | { | ||
138 | wil_dbg_IRQ(wil, "%s()\n", __func__); | ||
139 | |||
140 | wil6210_mask_irq_tx(wil); | ||
141 | wil6210_mask_irq_rx(wil); | ||
142 | wil6210_mask_irq_misc(wil); | ||
143 | wil6210_mask_irq_pseudo(wil); | ||
144 | } | ||
145 | |||
146 | void wil6210_enable_irq(struct wil6210_priv *wil) | ||
147 | { | ||
148 | wil_dbg_IRQ(wil, "%s()\n", __func__); | ||
149 | |||
150 | iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_RX_ICR) + | ||
151 | offsetof(struct RGF_ICR, ICC)); | ||
152 | iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_TX_ICR) + | ||
153 | offsetof(struct RGF_ICR, ICC)); | ||
154 | iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) + | ||
155 | offsetof(struct RGF_ICR, ICC)); | ||
156 | |||
157 | wil6210_unmask_irq_pseudo(wil); | ||
158 | wil6210_unmask_irq_tx(wil); | ||
159 | wil6210_unmask_irq_rx(wil); | ||
160 | wil6210_unmask_irq_misc(wil); | ||
161 | } | ||
162 | |||
163 | static irqreturn_t wil6210_irq_rx(int irq, void *cookie) | ||
164 | { | ||
165 | struct wil6210_priv *wil = cookie; | ||
166 | u32 isr = wil_ioread32_and_clear(wil->csr + | ||
167 | HOSTADDR(RGF_DMA_EP_RX_ICR) + | ||
168 | offsetof(struct RGF_ICR, ICR)); | ||
169 | |||
170 | wil_dbg_IRQ(wil, "ISR RX 0x%08x\n", isr); | ||
171 | |||
172 | if (!isr) { | ||
173 | wil_err(wil, "spurious IRQ: RX\n"); | ||
174 | return IRQ_NONE; | ||
175 | } | ||
176 | |||
177 | wil6210_mask_irq_rx(wil); | ||
178 | |||
179 | if (isr & BIT_DMA_EP_RX_ICR_RX_DONE) { | ||
180 | wil_dbg_IRQ(wil, "RX done\n"); | ||
181 | isr &= ~BIT_DMA_EP_RX_ICR_RX_DONE; | ||
182 | wil_rx_handle(wil); | ||
183 | } | ||
184 | |||
185 | if (isr) | ||
186 | wil_err(wil, "un-handled RX ISR bits 0x%08x\n", isr); | ||
187 | |||
188 | wil6210_unmask_irq_rx(wil); | ||
189 | |||
190 | return IRQ_HANDLED; | ||
191 | } | ||
192 | |||
193 | static irqreturn_t wil6210_irq_tx(int irq, void *cookie) | ||
194 | { | ||
195 | struct wil6210_priv *wil = cookie; | ||
196 | u32 isr = wil_ioread32_and_clear(wil->csr + | ||
197 | HOSTADDR(RGF_DMA_EP_TX_ICR) + | ||
198 | offsetof(struct RGF_ICR, ICR)); | ||
199 | |||
200 | wil_dbg_IRQ(wil, "ISR TX 0x%08x\n", isr); | ||
201 | |||
202 | if (!isr) { | ||
203 | wil_err(wil, "spurious IRQ: TX\n"); | ||
204 | return IRQ_NONE; | ||
205 | } | ||
206 | |||
207 | wil6210_mask_irq_tx(wil); | ||
208 | |||
209 | if (isr & BIT_DMA_EP_TX_ICR_TX_DONE) { | ||
210 | uint i; | ||
211 | wil_dbg_IRQ(wil, "TX done\n"); | ||
212 | isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE; | ||
213 | for (i = 0; i < 24; i++) { | ||
214 | u32 mask = BIT_DMA_EP_TX_ICR_TX_DONE_N(i); | ||
215 | if (isr & mask) { | ||
216 | isr &= ~mask; | ||
217 | wil_dbg_IRQ(wil, "TX done(%i)\n", i); | ||
218 | wil_tx_complete(wil, i); | ||
219 | } | ||
220 | } | ||
221 | } | ||
222 | |||
223 | if (isr) | ||
224 | wil_err(wil, "un-handled TX ISR bits 0x%08x\n", isr); | ||
225 | |||
226 | wil6210_unmask_irq_tx(wil); | ||
227 | |||
228 | return IRQ_HANDLED; | ||
229 | } | ||
230 | |||
231 | static irqreturn_t wil6210_irq_misc(int irq, void *cookie) | ||
232 | { | ||
233 | struct wil6210_priv *wil = cookie; | ||
234 | u32 isr = wil_ioread32_and_clear(wil->csr + | ||
235 | HOSTADDR(RGF_DMA_EP_MISC_ICR) + | ||
236 | offsetof(struct RGF_ICR, ICR)); | ||
237 | |||
238 | wil_dbg_IRQ(wil, "ISR MISC 0x%08x\n", isr); | ||
239 | |||
240 | if (!isr) { | ||
241 | wil_err(wil, "spurious IRQ: MISC\n"); | ||
242 | return IRQ_NONE; | ||
243 | } | ||
244 | |||
245 | wil6210_mask_irq_misc(wil); | ||
246 | |||
247 | if (isr & ISR_MISC_FW_READY) { | ||
248 | wil_dbg_IRQ(wil, "IRQ: FW ready\n"); | ||
249 | /** | ||
250 | * Actual FW ready indicated by the | ||
251 | * WMI_FW_READY_EVENTID | ||
252 | */ | ||
253 | isr &= ~ISR_MISC_FW_READY; | ||
254 | } | ||
255 | |||
256 | wil->isr_misc = isr; | ||
257 | |||
258 | if (isr) { | ||
259 | return IRQ_WAKE_THREAD; | ||
260 | } else { | ||
261 | wil6210_unmask_irq_misc(wil); | ||
262 | return IRQ_HANDLED; | ||
263 | } | ||
264 | } | ||
265 | |||
266 | static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie) | ||
267 | { | ||
268 | struct wil6210_priv *wil = cookie; | ||
269 | u32 isr = wil->isr_misc; | ||
270 | |||
271 | wil_dbg_IRQ(wil, "Thread ISR MISC 0x%08x\n", isr); | ||
272 | |||
273 | if (isr & ISR_MISC_MBOX_EVT) { | ||
274 | wil_dbg_IRQ(wil, "MBOX event\n"); | ||
275 | wmi_recv_cmd(wil); | ||
276 | isr &= ~ISR_MISC_MBOX_EVT; | ||
277 | } | ||
278 | |||
279 | if (isr) | ||
280 | wil_err(wil, "un-handled MISC ISR bits 0x%08x\n", isr); | ||
281 | |||
282 | wil->isr_misc = 0; | ||
283 | |||
284 | wil6210_unmask_irq_misc(wil); | ||
285 | |||
286 | return IRQ_HANDLED; | ||
287 | } | ||
288 | |||
289 | /** | ||
290 | * thread IRQ handler | ||
291 | */ | ||
292 | static irqreturn_t wil6210_thread_irq(int irq, void *cookie) | ||
293 | { | ||
294 | struct wil6210_priv *wil = cookie; | ||
295 | |||
296 | wil_dbg_IRQ(wil, "Thread IRQ\n"); | ||
297 | /* Discover real IRQ cause */ | ||
298 | if (wil->isr_misc) | ||
299 | wil6210_irq_misc_thread(irq, cookie); | ||
300 | |||
301 | wil6210_unmask_irq_pseudo(wil); | ||
302 | |||
303 | return IRQ_HANDLED; | ||
304 | } | ||
305 | |||
306 | /* DEBUG | ||
307 | * There is subtle bug in hardware that causes IRQ to raise when it should be | ||
308 | * masked. It is quite rare and hard to debug. | ||
309 | * | ||
310 | * Catch irq issue if it happens and print all I can. | ||
311 | */ | ||
312 | static int wil6210_debug_irq_mask(struct wil6210_priv *wil, u32 pseudo_cause) | ||
313 | { | ||
314 | if (!test_bit(wil_status_irqen, &wil->status)) { | ||
315 | u32 icm_rx = wil_ioread32_and_clear(wil->csr + | ||
316 | HOSTADDR(RGF_DMA_EP_RX_ICR) + | ||
317 | offsetof(struct RGF_ICR, ICM)); | ||
318 | u32 icr_rx = wil_ioread32_and_clear(wil->csr + | ||
319 | HOSTADDR(RGF_DMA_EP_RX_ICR) + | ||
320 | offsetof(struct RGF_ICR, ICR)); | ||
321 | u32 imv_rx = ioread32(wil->csr + | ||
322 | HOSTADDR(RGF_DMA_EP_RX_ICR) + | ||
323 | offsetof(struct RGF_ICR, IMV)); | ||
324 | u32 icm_tx = wil_ioread32_and_clear(wil->csr + | ||
325 | HOSTADDR(RGF_DMA_EP_TX_ICR) + | ||
326 | offsetof(struct RGF_ICR, ICM)); | ||
327 | u32 icr_tx = wil_ioread32_and_clear(wil->csr + | ||
328 | HOSTADDR(RGF_DMA_EP_TX_ICR) + | ||
329 | offsetof(struct RGF_ICR, ICR)); | ||
330 | u32 imv_tx = ioread32(wil->csr + | ||
331 | HOSTADDR(RGF_DMA_EP_TX_ICR) + | ||
332 | offsetof(struct RGF_ICR, IMV)); | ||
333 | u32 icm_misc = wil_ioread32_and_clear(wil->csr + | ||
334 | HOSTADDR(RGF_DMA_EP_MISC_ICR) + | ||
335 | offsetof(struct RGF_ICR, ICM)); | ||
336 | u32 icr_misc = wil_ioread32_and_clear(wil->csr + | ||
337 | HOSTADDR(RGF_DMA_EP_MISC_ICR) + | ||
338 | offsetof(struct RGF_ICR, ICR)); | ||
339 | u32 imv_misc = ioread32(wil->csr + | ||
340 | HOSTADDR(RGF_DMA_EP_MISC_ICR) + | ||
341 | offsetof(struct RGF_ICR, IMV)); | ||
342 | wil_err(wil, "IRQ when it should be masked: pseudo 0x%08x\n" | ||
343 | "Rx icm:icr:imv 0x%08x 0x%08x 0x%08x\n" | ||
344 | "Tx icm:icr:imv 0x%08x 0x%08x 0x%08x\n" | ||
345 | "Misc icm:icr:imv 0x%08x 0x%08x 0x%08x\n", | ||
346 | pseudo_cause, | ||
347 | icm_rx, icr_rx, imv_rx, | ||
348 | icm_tx, icr_tx, imv_tx, | ||
349 | icm_misc, icr_misc, imv_misc); | ||
350 | |||
351 | return -EINVAL; | ||
352 | } | ||
353 | |||
354 | return 0; | ||
355 | } | ||
356 | |||
357 | static irqreturn_t wil6210_hardirq(int irq, void *cookie) | ||
358 | { | ||
359 | irqreturn_t rc = IRQ_HANDLED; | ||
360 | struct wil6210_priv *wil = cookie; | ||
361 | u32 pseudo_cause = ioread32(wil->csr + HOSTADDR(RGF_DMA_PSEUDO_CAUSE)); | ||
362 | |||
363 | /** | ||
364 | * pseudo_cause is Clear-On-Read, no need to ACK | ||
365 | */ | ||
366 | if ((pseudo_cause == 0) || ((pseudo_cause & 0xff) == 0xff)) | ||
367 | return IRQ_NONE; | ||
368 | |||
369 | /* FIXME: IRQ mask debug */ | ||
370 | if (wil6210_debug_irq_mask(wil, pseudo_cause)) | ||
371 | return IRQ_NONE; | ||
372 | |||
373 | wil6210_mask_irq_pseudo(wil); | ||
374 | |||
375 | /* Discover real IRQ cause | ||
376 | * There are 2 possible phases for every IRQ: | ||
377 | * - hard IRQ handler called right here | ||
378 | * - threaded handler called later | ||
379 | * | ||
380 | * Hard IRQ handler reads and clears ISR. | ||
381 | * | ||
382 | * If threaded handler requested, hard IRQ handler | ||
383 | * returns IRQ_WAKE_THREAD and saves ISR register value | ||
384 | * for the threaded handler use. | ||
385 | * | ||
386 | * voting for wake thread - need at least 1 vote | ||
387 | */ | ||
388 | if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_RX) && | ||
389 | (wil6210_irq_rx(irq, cookie) == IRQ_WAKE_THREAD)) | ||
390 | rc = IRQ_WAKE_THREAD; | ||
391 | |||
392 | if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_TX) && | ||
393 | (wil6210_irq_tx(irq, cookie) == IRQ_WAKE_THREAD)) | ||
394 | rc = IRQ_WAKE_THREAD; | ||
395 | |||
396 | if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_MISC) && | ||
397 | (wil6210_irq_misc(irq, cookie) == IRQ_WAKE_THREAD)) | ||
398 | rc = IRQ_WAKE_THREAD; | ||
399 | |||
400 | /* if thread is requested, it will unmask IRQ */ | ||
401 | if (rc != IRQ_WAKE_THREAD) | ||
402 | wil6210_unmask_irq_pseudo(wil); | ||
403 | |||
404 | wil_dbg_IRQ(wil, "Hard IRQ 0x%08x\n", pseudo_cause); | ||
405 | |||
406 | return rc; | ||
407 | } | ||
408 | |||
409 | static int wil6210_request_3msi(struct wil6210_priv *wil, int irq) | ||
410 | { | ||
411 | int rc; | ||
412 | /* | ||
413 | * IRQ's are in the following order: | ||
414 | * - Tx | ||
415 | * - Rx | ||
416 | * - Misc | ||
417 | */ | ||
418 | |||
419 | rc = request_irq(irq, wil6210_irq_tx, IRQF_SHARED, | ||
420 | WIL_NAME"_tx", wil); | ||
421 | if (rc) | ||
422 | return rc; | ||
423 | |||
424 | rc = request_irq(irq + 1, wil6210_irq_rx, IRQF_SHARED, | ||
425 | WIL_NAME"_rx", wil); | ||
426 | if (rc) | ||
427 | goto free0; | ||
428 | |||
429 | rc = request_threaded_irq(irq + 2, wil6210_irq_misc, | ||
430 | wil6210_irq_misc_thread, | ||
431 | IRQF_SHARED, WIL_NAME"_misc", wil); | ||
432 | if (rc) | ||
433 | goto free1; | ||
434 | |||
435 | return 0; | ||
436 | /* error branch */ | ||
437 | free1: | ||
438 | free_irq(irq + 1, wil); | ||
439 | free0: | ||
440 | free_irq(irq, wil); | ||
441 | |||
442 | return rc; | ||
443 | } | ||
444 | |||
445 | int wil6210_init_irq(struct wil6210_priv *wil, int irq) | ||
446 | { | ||
447 | int rc; | ||
448 | if (wil->n_msi == 3) | ||
449 | rc = wil6210_request_3msi(wil, irq); | ||
450 | else | ||
451 | rc = request_threaded_irq(irq, wil6210_hardirq, | ||
452 | wil6210_thread_irq, | ||
453 | wil->n_msi ? 0 : IRQF_SHARED, | ||
454 | WIL_NAME, wil); | ||
455 | if (rc) | ||
456 | return rc; | ||
457 | |||
458 | wil6210_enable_irq(wil); | ||
459 | |||
460 | return 0; | ||
461 | } | ||
462 | |||
463 | void wil6210_fini_irq(struct wil6210_priv *wil, int irq) | ||
464 | { | ||
465 | wil6210_disable_irq(wil); | ||
466 | free_irq(irq, wil); | ||
467 | if (wil->n_msi == 3) { | ||
468 | free_irq(irq + 1, wil); | ||
469 | free_irq(irq + 2, wil); | ||
470 | } | ||
471 | } | ||
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c new file mode 100644 index 000000000000..95fcd361322b --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/main.c | |||
@@ -0,0 +1,407 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012 Qualcomm Atheros, Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/netdevice.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/ieee80211.h> | ||
21 | #include <linux/wireless.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/moduleparam.h> | ||
24 | #include <linux/if_arp.h> | ||
25 | |||
26 | #include "wil6210.h" | ||
27 | |||
28 | /* | ||
29 | * Due to a hardware issue, | ||
30 | * one has to read/write to/from NIC in 32-bit chunks; | ||
31 | * regular memcpy_fromio and siblings will | ||
32 | * not work on 64-bit platform - it uses 64-bit transactions | ||
33 | * | ||
34 | * Force 32-bit transactions to enable NIC on 64-bit platforms | ||
35 | * | ||
36 | * To avoid byte swap on big endian host, __raw_{read|write}l | ||
37 | * should be used - {read|write}l would swap bytes to provide | ||
38 | * little endian on PCI value in host endianness. | ||
39 | */ | ||
40 | void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src, | ||
41 | size_t count) | ||
42 | { | ||
43 | u32 *d = dst; | ||
44 | const volatile u32 __iomem *s = src; | ||
45 | |||
46 | /* size_t is unsigned, if (count%4 != 0) it will wrap */ | ||
47 | for (count += 4; count > 4; count -= 4) | ||
48 | *d++ = __raw_readl(s++); | ||
49 | } | ||
50 | |||
51 | void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src, | ||
52 | size_t count) | ||
53 | { | ||
54 | volatile u32 __iomem *d = dst; | ||
55 | const u32 *s = src; | ||
56 | |||
57 | for (count += 4; count > 4; count -= 4) | ||
58 | __raw_writel(*s++, d++); | ||
59 | } | ||
60 | |||
61 | static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid) | ||
62 | { | ||
63 | uint i; | ||
64 | struct net_device *ndev = wil_to_ndev(wil); | ||
65 | struct wireless_dev *wdev = wil->wdev; | ||
66 | |||
67 | wil_dbg(wil, "%s()\n", __func__); | ||
68 | |||
69 | wil_link_off(wil); | ||
70 | clear_bit(wil_status_fwconnected, &wil->status); | ||
71 | |||
72 | switch (wdev->sme_state) { | ||
73 | case CFG80211_SME_CONNECTED: | ||
74 | cfg80211_disconnected(ndev, WLAN_STATUS_UNSPECIFIED_FAILURE, | ||
75 | NULL, 0, GFP_KERNEL); | ||
76 | break; | ||
77 | case CFG80211_SME_CONNECTING: | ||
78 | cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0, | ||
79 | WLAN_STATUS_UNSPECIFIED_FAILURE, | ||
80 | GFP_KERNEL); | ||
81 | break; | ||
82 | default: | ||
83 | ; | ||
84 | } | ||
85 | |||
86 | for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) | ||
87 | wil_vring_fini_tx(wil, i); | ||
88 | } | ||
89 | |||
90 | static void wil_disconnect_worker(struct work_struct *work) | ||
91 | { | ||
92 | struct wil6210_priv *wil = container_of(work, | ||
93 | struct wil6210_priv, disconnect_worker); | ||
94 | |||
95 | _wil6210_disconnect(wil, NULL); | ||
96 | } | ||
97 | |||
98 | static void wil_connect_timer_fn(ulong x) | ||
99 | { | ||
100 | struct wil6210_priv *wil = (void *)x; | ||
101 | |||
102 | wil_dbg(wil, "Connect timeout\n"); | ||
103 | |||
104 | /* reschedule to thread context - disconnect won't | ||
105 | * run from atomic context | ||
106 | */ | ||
107 | schedule_work(&wil->disconnect_worker); | ||
108 | } | ||
109 | |||
110 | int wil_priv_init(struct wil6210_priv *wil) | ||
111 | { | ||
112 | wil_dbg(wil, "%s()\n", __func__); | ||
113 | |||
114 | mutex_init(&wil->mutex); | ||
115 | mutex_init(&wil->wmi_mutex); | ||
116 | |||
117 | init_completion(&wil->wmi_ready); | ||
118 | |||
119 | wil->pending_connect_cid = -1; | ||
120 | setup_timer(&wil->connect_timer, wil_connect_timer_fn, (ulong)wil); | ||
121 | |||
122 | INIT_WORK(&wil->wmi_connect_worker, wmi_connect_worker); | ||
123 | INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker); | ||
124 | INIT_WORK(&wil->wmi_event_worker, wmi_event_worker); | ||
125 | |||
126 | INIT_LIST_HEAD(&wil->pending_wmi_ev); | ||
127 | spin_lock_init(&wil->wmi_ev_lock); | ||
128 | |||
129 | wil->wmi_wq = create_singlethread_workqueue(WIL_NAME"_wmi"); | ||
130 | if (!wil->wmi_wq) | ||
131 | return -EAGAIN; | ||
132 | |||
133 | wil->wmi_wq_conn = create_singlethread_workqueue(WIL_NAME"_connect"); | ||
134 | if (!wil->wmi_wq_conn) { | ||
135 | destroy_workqueue(wil->wmi_wq); | ||
136 | return -EAGAIN; | ||
137 | } | ||
138 | |||
139 | /* make shadow copy of registers that should not change on run time */ | ||
140 | wil_memcpy_fromio_32(&wil->mbox_ctl, wil->csr + HOST_MBOX, | ||
141 | sizeof(struct wil6210_mbox_ctl)); | ||
142 | wil_mbox_ring_le2cpus(&wil->mbox_ctl.rx); | ||
143 | wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx); | ||
144 | |||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | void wil6210_disconnect(struct wil6210_priv *wil, void *bssid) | ||
149 | { | ||
150 | del_timer_sync(&wil->connect_timer); | ||
151 | _wil6210_disconnect(wil, bssid); | ||
152 | } | ||
153 | |||
154 | void wil_priv_deinit(struct wil6210_priv *wil) | ||
155 | { | ||
156 | cancel_work_sync(&wil->disconnect_worker); | ||
157 | wil6210_disconnect(wil, NULL); | ||
158 | wmi_event_flush(wil); | ||
159 | destroy_workqueue(wil->wmi_wq_conn); | ||
160 | destroy_workqueue(wil->wmi_wq); | ||
161 | } | ||
162 | |||
163 | static void wil_target_reset(struct wil6210_priv *wil) | ||
164 | { | ||
165 | wil_dbg(wil, "Resetting...\n"); | ||
166 | |||
167 | /* register write */ | ||
168 | #define W(a, v) iowrite32(v, wil->csr + HOSTADDR(a)) | ||
169 | /* register set = read, OR, write */ | ||
170 | #define S(a, v) iowrite32(ioread32(wil->csr + HOSTADDR(a)) | v, \ | ||
171 | wil->csr + HOSTADDR(a)) | ||
172 | |||
173 | /* hpal_perst_from_pad_src_n_mask */ | ||
174 | S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(6)); | ||
175 | /* car_perst_rst_src_n_mask */ | ||
176 | S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(7)); | ||
177 | |||
178 | W(RGF_USER_MAC_CPU_0, BIT(1)); /* mac_cpu_man_rst */ | ||
179 | W(RGF_USER_USER_CPU_0, BIT(1)); /* user_cpu_man_rst */ | ||
180 | |||
181 | msleep(100); | ||
182 | |||
183 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000); | ||
184 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F); | ||
185 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000170); | ||
186 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FC00); | ||
187 | |||
188 | msleep(100); | ||
189 | |||
190 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0); | ||
191 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0); | ||
192 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0); | ||
193 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); | ||
194 | |||
195 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000001); | ||
196 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00000080); | ||
197 | W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); | ||
198 | |||
199 | msleep(2000); | ||
200 | |||
201 | W(RGF_USER_USER_CPU_0, BIT(0)); /* user_cpu_man_de_rst */ | ||
202 | |||
203 | msleep(2000); | ||
204 | |||
205 | wil_dbg(wil, "Reset completed\n"); | ||
206 | |||
207 | #undef W | ||
208 | #undef S | ||
209 | } | ||
210 | |||
211 | void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r) | ||
212 | { | ||
213 | le32_to_cpus(&r->base); | ||
214 | le16_to_cpus(&r->entry_size); | ||
215 | le16_to_cpus(&r->size); | ||
216 | le32_to_cpus(&r->tail); | ||
217 | le32_to_cpus(&r->head); | ||
218 | } | ||
219 | |||
220 | static int wil_wait_for_fw_ready(struct wil6210_priv *wil) | ||
221 | { | ||
222 | ulong to = msecs_to_jiffies(1000); | ||
223 | ulong left = wait_for_completion_timeout(&wil->wmi_ready, to); | ||
224 | if (0 == left) { | ||
225 | wil_err(wil, "Firmware not ready\n"); | ||
226 | return -ETIME; | ||
227 | } else { | ||
228 | wil_dbg(wil, "FW ready after %d ms\n", | ||
229 | jiffies_to_msecs(to-left)); | ||
230 | } | ||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | /* | ||
235 | * We reset all the structures, and we reset the UMAC. | ||
236 | * After calling this routine, you're expected to reload | ||
237 | * the firmware. | ||
238 | */ | ||
239 | int wil_reset(struct wil6210_priv *wil) | ||
240 | { | ||
241 | int rc; | ||
242 | |||
243 | cancel_work_sync(&wil->disconnect_worker); | ||
244 | wil6210_disconnect(wil, NULL); | ||
245 | |||
246 | wmi_event_flush(wil); | ||
247 | |||
248 | flush_workqueue(wil->wmi_wq); | ||
249 | flush_workqueue(wil->wmi_wq_conn); | ||
250 | |||
251 | wil6210_disable_irq(wil); | ||
252 | wil->status = 0; | ||
253 | |||
254 | /* TODO: put MAC in reset */ | ||
255 | wil_target_reset(wil); | ||
256 | |||
257 | /* init after reset */ | ||
258 | wil->pending_connect_cid = -1; | ||
259 | INIT_COMPLETION(wil->wmi_ready); | ||
260 | |||
261 | /* make shadow copy of registers that should not change on run time */ | ||
262 | wil_memcpy_fromio_32(&wil->mbox_ctl, wil->csr + HOST_MBOX, | ||
263 | sizeof(struct wil6210_mbox_ctl)); | ||
264 | wil_mbox_ring_le2cpus(&wil->mbox_ctl.rx); | ||
265 | wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx); | ||
266 | |||
267 | /* TODO: release MAC reset */ | ||
268 | wil6210_enable_irq(wil); | ||
269 | |||
270 | /* we just started MAC, wait for FW ready */ | ||
271 | rc = wil_wait_for_fw_ready(wil); | ||
272 | |||
273 | return rc; | ||
274 | } | ||
275 | |||
276 | |||
277 | void wil_link_on(struct wil6210_priv *wil) | ||
278 | { | ||
279 | struct net_device *ndev = wil_to_ndev(wil); | ||
280 | |||
281 | wil_dbg(wil, "%s()\n", __func__); | ||
282 | |||
283 | netif_carrier_on(ndev); | ||
284 | netif_tx_wake_all_queues(ndev); | ||
285 | } | ||
286 | |||
287 | void wil_link_off(struct wil6210_priv *wil) | ||
288 | { | ||
289 | struct net_device *ndev = wil_to_ndev(wil); | ||
290 | |||
291 | wil_dbg(wil, "%s()\n", __func__); | ||
292 | |||
293 | netif_tx_stop_all_queues(ndev); | ||
294 | netif_carrier_off(ndev); | ||
295 | } | ||
296 | |||
297 | static int __wil_up(struct wil6210_priv *wil) | ||
298 | { | ||
299 | struct net_device *ndev = wil_to_ndev(wil); | ||
300 | struct wireless_dev *wdev = wil->wdev; | ||
301 | struct ieee80211_channel *channel = wdev->preset_chandef.chan; | ||
302 | int rc; | ||
303 | int bi; | ||
304 | u16 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype); | ||
305 | |||
306 | rc = wil_reset(wil); | ||
307 | if (rc) | ||
308 | return rc; | ||
309 | |||
310 | /* FIXME Firmware works now in PBSS mode(ToDS=0, FromDS=0) */ | ||
311 | wmi_nettype = wil_iftype_nl2wmi(NL80211_IFTYPE_ADHOC); | ||
312 | switch (wdev->iftype) { | ||
313 | case NL80211_IFTYPE_STATION: | ||
314 | wil_dbg(wil, "type: STATION\n"); | ||
315 | bi = 0; | ||
316 | ndev->type = ARPHRD_ETHER; | ||
317 | break; | ||
318 | case NL80211_IFTYPE_AP: | ||
319 | wil_dbg(wil, "type: AP\n"); | ||
320 | bi = 100; | ||
321 | ndev->type = ARPHRD_ETHER; | ||
322 | break; | ||
323 | case NL80211_IFTYPE_P2P_CLIENT: | ||
324 | wil_dbg(wil, "type: P2P_CLIENT\n"); | ||
325 | bi = 0; | ||
326 | ndev->type = ARPHRD_ETHER; | ||
327 | break; | ||
328 | case NL80211_IFTYPE_P2P_GO: | ||
329 | wil_dbg(wil, "type: P2P_GO\n"); | ||
330 | bi = 100; | ||
331 | ndev->type = ARPHRD_ETHER; | ||
332 | break; | ||
333 | case NL80211_IFTYPE_MONITOR: | ||
334 | wil_dbg(wil, "type: Monitor\n"); | ||
335 | bi = 0; | ||
336 | ndev->type = ARPHRD_IEEE80211_RADIOTAP; | ||
337 | /* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_RADIOTAP ? */ | ||
338 | break; | ||
339 | default: | ||
340 | return -EOPNOTSUPP; | ||
341 | } | ||
342 | |||
343 | /* Apply profile in the following order: */ | ||
344 | /* SSID and channel for the AP */ | ||
345 | switch (wdev->iftype) { | ||
346 | case NL80211_IFTYPE_AP: | ||
347 | case NL80211_IFTYPE_P2P_GO: | ||
348 | if (wdev->ssid_len == 0) { | ||
349 | wil_err(wil, "SSID not set\n"); | ||
350 | return -EINVAL; | ||
351 | } | ||
352 | wmi_set_ssid(wil, wdev->ssid_len, wdev->ssid); | ||
353 | if (channel) | ||
354 | wmi_set_channel(wil, channel->hw_value); | ||
355 | break; | ||
356 | default: | ||
357 | ; | ||
358 | } | ||
359 | |||
360 | /* MAC address - pre-requisite for other commands */ | ||
361 | wmi_set_mac_address(wil, ndev->dev_addr); | ||
362 | |||
363 | /* Set up beaconing if required. */ | ||
364 | rc = wmi_set_bcon(wil, bi, wmi_nettype); | ||
365 | if (rc) | ||
366 | return rc; | ||
367 | |||
368 | /* Rx VRING. After MAC and beacon */ | ||
369 | wil_rx_init(wil); | ||
370 | |||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | int wil_up(struct wil6210_priv *wil) | ||
375 | { | ||
376 | int rc; | ||
377 | |||
378 | mutex_lock(&wil->mutex); | ||
379 | rc = __wil_up(wil); | ||
380 | mutex_unlock(&wil->mutex); | ||
381 | |||
382 | return rc; | ||
383 | } | ||
384 | |||
385 | static int __wil_down(struct wil6210_priv *wil) | ||
386 | { | ||
387 | if (wil->scan_request) { | ||
388 | cfg80211_scan_done(wil->scan_request, true); | ||
389 | wil->scan_request = NULL; | ||
390 | } | ||
391 | |||
392 | wil6210_disconnect(wil, NULL); | ||
393 | wil_rx_fini(wil); | ||
394 | |||
395 | return 0; | ||
396 | } | ||
397 | |||
398 | int wil_down(struct wil6210_priv *wil) | ||
399 | { | ||
400 | int rc; | ||
401 | |||
402 | mutex_lock(&wil->mutex); | ||
403 | rc = __wil_down(wil); | ||
404 | mutex_unlock(&wil->mutex); | ||
405 | |||
406 | return rc; | ||
407 | } | ||
diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c new file mode 100644 index 000000000000..3068b5cb53a7 --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/netdev.c | |||
@@ -0,0 +1,157 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012 Qualcomm Atheros, Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <linux/netdevice.h> | ||
19 | #include <linux/etherdevice.h> | ||
20 | #include <linux/slab.h> | ||
21 | |||
22 | #include "wil6210.h" | ||
23 | |||
24 | static int wil_open(struct net_device *ndev) | ||
25 | { | ||
26 | struct wil6210_priv *wil = ndev_to_wil(ndev); | ||
27 | |||
28 | return wil_up(wil); | ||
29 | } | ||
30 | |||
31 | static int wil_stop(struct net_device *ndev) | ||
32 | { | ||
33 | struct wil6210_priv *wil = ndev_to_wil(ndev); | ||
34 | |||
35 | return wil_down(wil); | ||
36 | } | ||
37 | |||
38 | /* | ||
39 | * AC to queue mapping | ||
40 | * | ||
41 | * AC_VO -> queue 3 | ||
42 | * AC_VI -> queue 2 | ||
43 | * AC_BE -> queue 1 | ||
44 | * AC_BK -> queue 0 | ||
45 | */ | ||
46 | static u16 wil_select_queue(struct net_device *ndev, struct sk_buff *skb) | ||
47 | { | ||
48 | static const u16 wil_1d_to_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; | ||
49 | struct wil6210_priv *wil = ndev_to_wil(ndev); | ||
50 | u16 rc; | ||
51 | |||
52 | skb->priority = cfg80211_classify8021d(skb); | ||
53 | |||
54 | rc = wil_1d_to_queue[skb->priority]; | ||
55 | |||
56 | wil_dbg_TXRX(wil, "%s() %d -> %d\n", __func__, (int)skb->priority, | ||
57 | (int)rc); | ||
58 | |||
59 | return rc; | ||
60 | } | ||
61 | |||
62 | static const struct net_device_ops wil_netdev_ops = { | ||
63 | .ndo_open = wil_open, | ||
64 | .ndo_stop = wil_stop, | ||
65 | .ndo_start_xmit = wil_start_xmit, | ||
66 | .ndo_select_queue = wil_select_queue, | ||
67 | .ndo_set_mac_address = eth_mac_addr, | ||
68 | .ndo_validate_addr = eth_validate_addr, | ||
69 | }; | ||
70 | |||
71 | void *wil_if_alloc(struct device *dev, void __iomem *csr) | ||
72 | { | ||
73 | struct net_device *ndev; | ||
74 | struct wireless_dev *wdev; | ||
75 | struct wil6210_priv *wil; | ||
76 | struct ieee80211_channel *ch; | ||
77 | int rc = 0; | ||
78 | |||
79 | wdev = wil_cfg80211_init(dev); | ||
80 | if (IS_ERR(wdev)) { | ||
81 | dev_err(dev, "wil_cfg80211_init failed\n"); | ||
82 | return wdev; | ||
83 | } | ||
84 | |||
85 | wil = wdev_to_wil(wdev); | ||
86 | wil->csr = csr; | ||
87 | wil->wdev = wdev; | ||
88 | |||
89 | rc = wil_priv_init(wil); | ||
90 | if (rc) { | ||
91 | dev_err(dev, "wil_priv_init failed\n"); | ||
92 | goto out_wdev; | ||
93 | } | ||
94 | |||
95 | wdev->iftype = NL80211_IFTYPE_STATION; /* TODO */ | ||
96 | /* default monitor channel */ | ||
97 | ch = wdev->wiphy->bands[IEEE80211_BAND_60GHZ]->channels; | ||
98 | cfg80211_chandef_create(&wdev->preset_chandef, ch, NL80211_CHAN_NO_HT); | ||
99 | |||
100 | ndev = alloc_netdev_mqs(0, "wlan%d", ether_setup, WIL6210_TX_QUEUES, 1); | ||
101 | if (!ndev) { | ||
102 | dev_err(dev, "alloc_netdev_mqs failed\n"); | ||
103 | rc = -ENOMEM; | ||
104 | goto out_priv; | ||
105 | } | ||
106 | |||
107 | ndev->netdev_ops = &wil_netdev_ops; | ||
108 | ndev->ieee80211_ptr = wdev; | ||
109 | SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); | ||
110 | wdev->netdev = ndev; | ||
111 | |||
112 | wil_link_off(wil); | ||
113 | |||
114 | return wil; | ||
115 | |||
116 | out_priv: | ||
117 | wil_priv_deinit(wil); | ||
118 | |||
119 | out_wdev: | ||
120 | wil_wdev_free(wil); | ||
121 | |||
122 | return ERR_PTR(rc); | ||
123 | } | ||
124 | |||
125 | void wil_if_free(struct wil6210_priv *wil) | ||
126 | { | ||
127 | struct net_device *ndev = wil_to_ndev(wil); | ||
128 | if (!ndev) | ||
129 | return; | ||
130 | |||
131 | free_netdev(ndev); | ||
132 | wil_priv_deinit(wil); | ||
133 | wil_wdev_free(wil); | ||
134 | } | ||
135 | |||
136 | int wil_if_add(struct wil6210_priv *wil) | ||
137 | { | ||
138 | struct net_device *ndev = wil_to_ndev(wil); | ||
139 | int rc; | ||
140 | |||
141 | rc = register_netdev(ndev); | ||
142 | if (rc < 0) { | ||
143 | dev_err(&ndev->dev, "Failed to register netdev: %d\n", rc); | ||
144 | return rc; | ||
145 | } | ||
146 | |||
147 | wil_link_off(wil); | ||
148 | |||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | void wil_if_remove(struct wil6210_priv *wil) | ||
153 | { | ||
154 | struct net_device *ndev = wil_to_ndev(wil); | ||
155 | |||
156 | unregister_netdev(ndev); | ||
157 | } | ||
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c new file mode 100644 index 000000000000..0fc83edd6bad --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c | |||
@@ -0,0 +1,223 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012 Qualcomm Atheros, Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/netdevice.h> | ||
21 | #include <linux/debugfs.h> | ||
22 | #include <linux/pci.h> | ||
23 | #include <linux/moduleparam.h> | ||
24 | |||
25 | #include "wil6210.h" | ||
26 | |||
27 | static int use_msi = 1; | ||
28 | module_param(use_msi, int, S_IRUGO); | ||
29 | MODULE_PARM_DESC(use_msi, | ||
30 | " Use MSI interrupt: " | ||
31 | "0 - don't, 1 - (default) - single, or 3"); | ||
32 | |||
33 | /* Bus ops */ | ||
34 | static int wil_if_pcie_enable(struct wil6210_priv *wil) | ||
35 | { | ||
36 | struct pci_dev *pdev = wil->pdev; | ||
37 | int rc; | ||
38 | |||
39 | pci_set_master(pdev); | ||
40 | |||
41 | /* | ||
42 | * how many MSI interrupts to request? | ||
43 | */ | ||
44 | switch (use_msi) { | ||
45 | case 3: | ||
46 | case 1: | ||
47 | case 0: | ||
48 | break; | ||
49 | default: | ||
50 | wil_err(wil, "Invalid use_msi=%d, default to 1\n", | ||
51 | use_msi); | ||
52 | use_msi = 1; | ||
53 | } | ||
54 | wil->n_msi = use_msi; | ||
55 | if (wil->n_msi) { | ||
56 | wil_dbg(wil, "Setup %d MSI interrupts\n", use_msi); | ||
57 | rc = pci_enable_msi_block(pdev, wil->n_msi); | ||
58 | if (rc && (wil->n_msi == 3)) { | ||
59 | wil_err(wil, "3 MSI mode failed, try 1 MSI\n"); | ||
60 | wil->n_msi = 1; | ||
61 | rc = pci_enable_msi_block(pdev, wil->n_msi); | ||
62 | } | ||
63 | if (rc) { | ||
64 | wil_err(wil, "pci_enable_msi failed, use INTx\n"); | ||
65 | wil->n_msi = 0; | ||
66 | } | ||
67 | } else { | ||
68 | wil_dbg(wil, "MSI interrupts disabled, use INTx\n"); | ||
69 | } | ||
70 | |||
71 | rc = wil6210_init_irq(wil, pdev->irq); | ||
72 | if (rc) | ||
73 | goto stop_master; | ||
74 | |||
75 | /* need reset here to obtain MAC */ | ||
76 | rc = wil_reset(wil); | ||
77 | if (rc) | ||
78 | goto release_irq; | ||
79 | |||
80 | return 0; | ||
81 | |||
82 | release_irq: | ||
83 | wil6210_fini_irq(wil, pdev->irq); | ||
84 | /* safe to call if no MSI */ | ||
85 | pci_disable_msi(pdev); | ||
86 | stop_master: | ||
87 | pci_clear_master(pdev); | ||
88 | return rc; | ||
89 | } | ||
90 | |||
91 | static int wil_if_pcie_disable(struct wil6210_priv *wil) | ||
92 | { | ||
93 | struct pci_dev *pdev = wil->pdev; | ||
94 | |||
95 | pci_clear_master(pdev); | ||
96 | /* disable and release IRQ */ | ||
97 | wil6210_fini_irq(wil, pdev->irq); | ||
98 | /* safe to call if no MSI */ | ||
99 | pci_disable_msi(pdev); | ||
100 | /* TODO: disable HW */ | ||
101 | |||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) | ||
106 | { | ||
107 | struct wil6210_priv *wil; | ||
108 | struct device *dev = &pdev->dev; | ||
109 | void __iomem *csr; | ||
110 | int rc; | ||
111 | |||
112 | /* check HW */ | ||
113 | dev_info(&pdev->dev, WIL_NAME " device found [%04x:%04x] (rev %x)\n", | ||
114 | (int)pdev->vendor, (int)pdev->device, (int)pdev->revision); | ||
115 | |||
116 | if (pci_resource_len(pdev, 0) != WIL6210_MEM_SIZE) { | ||
117 | dev_err(&pdev->dev, "Not " WIL_NAME "? " | ||
118 | "BAR0 size is %lu while expecting %lu\n", | ||
119 | (ulong)pci_resource_len(pdev, 0), WIL6210_MEM_SIZE); | ||
120 | return -ENODEV; | ||
121 | } | ||
122 | |||
123 | rc = pci_enable_device(pdev); | ||
124 | if (rc) { | ||
125 | dev_err(&pdev->dev, "pci_enable_device failed\n"); | ||
126 | return -ENODEV; | ||
127 | } | ||
128 | /* rollback to err_disable_pdev */ | ||
129 | |||
130 | rc = pci_request_region(pdev, 0, WIL_NAME); | ||
131 | if (rc) { | ||
132 | dev_err(&pdev->dev, "pci_request_region failed\n"); | ||
133 | goto err_disable_pdev; | ||
134 | } | ||
135 | /* rollback to err_release_reg */ | ||
136 | |||
137 | csr = pci_ioremap_bar(pdev, 0); | ||
138 | if (!csr) { | ||
139 | dev_err(&pdev->dev, "pci_ioremap_bar failed\n"); | ||
140 | rc = -ENODEV; | ||
141 | goto err_release_reg; | ||
142 | } | ||
143 | /* rollback to err_iounmap */ | ||
144 | dev_info(&pdev->dev, "CSR at %pR -> %p\n", &pdev->resource[0], csr); | ||
145 | |||
146 | wil = wil_if_alloc(dev, csr); | ||
147 | if (IS_ERR(wil)) { | ||
148 | rc = (int)PTR_ERR(wil); | ||
149 | dev_err(dev, "wil_if_alloc failed: %d\n", rc); | ||
150 | goto err_iounmap; | ||
151 | } | ||
152 | /* rollback to if_free */ | ||
153 | |||
154 | pci_set_drvdata(pdev, wil); | ||
155 | wil->pdev = pdev; | ||
156 | |||
157 | /* FW should raise IRQ when ready */ | ||
158 | rc = wil_if_pcie_enable(wil); | ||
159 | if (rc) { | ||
160 | wil_err(wil, "Enable device failed\n"); | ||
161 | goto if_free; | ||
162 | } | ||
163 | /* rollback to bus_disable */ | ||
164 | |||
165 | rc = wil_if_add(wil); | ||
166 | if (rc) { | ||
167 | wil_err(wil, "wil_if_add failed: %d\n", rc); | ||
168 | goto bus_disable; | ||
169 | } | ||
170 | |||
171 | wil6210_debugfs_init(wil); | ||
172 | |||
173 | /* check FW is alive */ | ||
174 | wmi_echo(wil); | ||
175 | |||
176 | return 0; | ||
177 | |||
178 | bus_disable: | ||
179 | wil_if_pcie_disable(wil); | ||
180 | if_free: | ||
181 | wil_if_free(wil); | ||
182 | err_iounmap: | ||
183 | pci_iounmap(pdev, csr); | ||
184 | err_release_reg: | ||
185 | pci_release_region(pdev, 0); | ||
186 | err_disable_pdev: | ||
187 | pci_disable_device(pdev); | ||
188 | |||
189 | return rc; | ||
190 | } | ||
191 | |||
192 | static void wil_pcie_remove(struct pci_dev *pdev) | ||
193 | { | ||
194 | struct wil6210_priv *wil = pci_get_drvdata(pdev); | ||
195 | |||
196 | wil6210_debugfs_remove(wil); | ||
197 | wil_if_pcie_disable(wil); | ||
198 | wil_if_remove(wil); | ||
199 | wil_if_free(wil); | ||
200 | pci_iounmap(pdev, wil->csr); | ||
201 | pci_release_region(pdev, 0); | ||
202 | pci_disable_device(pdev); | ||
203 | pci_set_drvdata(pdev, NULL); | ||
204 | } | ||
205 | |||
206 | static DEFINE_PCI_DEVICE_TABLE(wil6210_pcie_ids) = { | ||
207 | { PCI_DEVICE(0x1ae9, 0x0301) }, | ||
208 | { /* end: all zeroes */ }, | ||
209 | }; | ||
210 | MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids); | ||
211 | |||
212 | static struct pci_driver wil6210_driver = { | ||
213 | .probe = wil_pcie_probe, | ||
214 | .remove = wil_pcie_remove, | ||
215 | .id_table = wil6210_pcie_ids, | ||
216 | .name = WIL_NAME, | ||
217 | }; | ||
218 | |||
219 | module_pci_driver(wil6210_driver); | ||
220 | |||
221 | MODULE_LICENSE("Dual BSD/GPL"); | ||
222 | MODULE_AUTHOR("Qualcomm Atheros <wil6210@qca.qualcomm.com>"); | ||
223 | MODULE_DESCRIPTION("Driver for 60g WiFi WIL6210 card"); | ||
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c new file mode 100644 index 000000000000..f29c294413cf --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/txrx.c | |||
@@ -0,0 +1,871 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012 Qualcomm Atheros, Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/netdevice.h> | ||
19 | #include <linux/etherdevice.h> | ||
20 | #include <linux/hardirq.h> | ||
21 | #include <net/ieee80211_radiotap.h> | ||
22 | #include <linux/if_arp.h> | ||
23 | #include <linux/moduleparam.h> | ||
24 | |||
25 | #include "wil6210.h" | ||
26 | #include "wmi.h" | ||
27 | #include "txrx.h" | ||
28 | |||
29 | static bool rtap_include_phy_info; | ||
30 | module_param(rtap_include_phy_info, bool, S_IRUGO); | ||
31 | MODULE_PARM_DESC(rtap_include_phy_info, | ||
32 | " Include PHY info in the radiotap header, default - no"); | ||
33 | |||
34 | static inline int wil_vring_is_empty(struct vring *vring) | ||
35 | { | ||
36 | return vring->swhead == vring->swtail; | ||
37 | } | ||
38 | |||
39 | static inline u32 wil_vring_next_tail(struct vring *vring) | ||
40 | { | ||
41 | return (vring->swtail + 1) % vring->size; | ||
42 | } | ||
43 | |||
44 | static inline void wil_vring_advance_head(struct vring *vring, int n) | ||
45 | { | ||
46 | vring->swhead = (vring->swhead + n) % vring->size; | ||
47 | } | ||
48 | |||
49 | static inline int wil_vring_is_full(struct vring *vring) | ||
50 | { | ||
51 | return wil_vring_next_tail(vring) == vring->swhead; | ||
52 | } | ||
53 | /* | ||
54 | * Available space in Tx Vring | ||
55 | */ | ||
56 | static inline int wil_vring_avail_tx(struct vring *vring) | ||
57 | { | ||
58 | u32 swhead = vring->swhead; | ||
59 | u32 swtail = vring->swtail; | ||
60 | int used = (vring->size + swhead - swtail) % vring->size; | ||
61 | |||
62 | return vring->size - used - 1; | ||
63 | } | ||
64 | |||
65 | static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring) | ||
66 | { | ||
67 | struct device *dev = wil_to_dev(wil); | ||
68 | size_t sz = vring->size * sizeof(vring->va[0]); | ||
69 | uint i; | ||
70 | |||
71 | BUILD_BUG_ON(sizeof(vring->va[0]) != 32); | ||
72 | |||
73 | vring->swhead = 0; | ||
74 | vring->swtail = 0; | ||
75 | vring->ctx = kzalloc(vring->size * sizeof(vring->ctx[0]), GFP_KERNEL); | ||
76 | if (!vring->ctx) { | ||
77 | wil_err(wil, "vring_alloc [%d] failed to alloc ctx mem\n", | ||
78 | vring->size); | ||
79 | vring->va = NULL; | ||
80 | return -ENOMEM; | ||
81 | } | ||
82 | /* | ||
83 | * vring->va should be aligned on its size rounded up to power of 2 | ||
84 | * This is granted by the dma_alloc_coherent | ||
85 | */ | ||
86 | vring->va = dma_alloc_coherent(dev, sz, &vring->pa, GFP_KERNEL); | ||
87 | if (!vring->va) { | ||
88 | wil_err(wil, "vring_alloc [%d] failed to alloc DMA mem\n", | ||
89 | vring->size); | ||
90 | kfree(vring->ctx); | ||
91 | vring->ctx = NULL; | ||
92 | return -ENOMEM; | ||
93 | } | ||
94 | /* initially, all descriptors are SW owned | ||
95 | * For Tx and Rx, ownership bit is at the same location, thus | ||
96 | * we can use any | ||
97 | */ | ||
98 | for (i = 0; i < vring->size; i++) { | ||
99 | volatile struct vring_tx_desc *d = &(vring->va[i].tx); | ||
100 | d->dma.status = TX_DMA_STATUS_DU; | ||
101 | } | ||
102 | |||
103 | wil_dbg(wil, "vring[%d] 0x%p:0x%016llx 0x%p\n", vring->size, | ||
104 | vring->va, (unsigned long long)vring->pa, vring->ctx); | ||
105 | |||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | static void wil_vring_free(struct wil6210_priv *wil, struct vring *vring, | ||
110 | int tx) | ||
111 | { | ||
112 | struct device *dev = wil_to_dev(wil); | ||
113 | size_t sz = vring->size * sizeof(vring->va[0]); | ||
114 | |||
115 | while (!wil_vring_is_empty(vring)) { | ||
116 | if (tx) { | ||
117 | volatile struct vring_tx_desc *d = | ||
118 | &vring->va[vring->swtail].tx; | ||
119 | dma_addr_t pa = d->dma.addr_low | | ||
120 | ((u64)d->dma.addr_high << 32); | ||
121 | struct sk_buff *skb = vring->ctx[vring->swtail]; | ||
122 | if (skb) { | ||
123 | dma_unmap_single(dev, pa, d->dma.length, | ||
124 | DMA_TO_DEVICE); | ||
125 | dev_kfree_skb_any(skb); | ||
126 | vring->ctx[vring->swtail] = NULL; | ||
127 | } else { | ||
128 | dma_unmap_page(dev, pa, d->dma.length, | ||
129 | DMA_TO_DEVICE); | ||
130 | } | ||
131 | vring->swtail = wil_vring_next_tail(vring); | ||
132 | } else { /* rx */ | ||
133 | volatile struct vring_rx_desc *d = | ||
134 | &vring->va[vring->swtail].rx; | ||
135 | dma_addr_t pa = d->dma.addr_low | | ||
136 | ((u64)d->dma.addr_high << 32); | ||
137 | struct sk_buff *skb = vring->ctx[vring->swhead]; | ||
138 | dma_unmap_single(dev, pa, d->dma.length, | ||
139 | DMA_FROM_DEVICE); | ||
140 | kfree_skb(skb); | ||
141 | wil_vring_advance_head(vring, 1); | ||
142 | } | ||
143 | } | ||
144 | dma_free_coherent(dev, sz, (void *)vring->va, vring->pa); | ||
145 | kfree(vring->ctx); | ||
146 | vring->pa = 0; | ||
147 | vring->va = NULL; | ||
148 | vring->ctx = NULL; | ||
149 | } | ||
150 | |||
151 | /** | ||
152 | * Allocate one skb for Rx VRING | ||
153 | * | ||
154 | * Safe to call from IRQ | ||
155 | */ | ||
156 | static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct vring *vring, | ||
157 | u32 i, int headroom) | ||
158 | { | ||
159 | struct device *dev = wil_to_dev(wil); | ||
160 | unsigned int sz = RX_BUF_LEN; | ||
161 | volatile struct vring_rx_desc *d = &(vring->va[i].rx); | ||
162 | dma_addr_t pa; | ||
163 | |||
164 | /* TODO align */ | ||
165 | struct sk_buff *skb = dev_alloc_skb(sz + headroom); | ||
166 | if (unlikely(!skb)) | ||
167 | return -ENOMEM; | ||
168 | |||
169 | skb_reserve(skb, headroom); | ||
170 | skb_put(skb, sz); | ||
171 | |||
172 | pa = dma_map_single(dev, skb->data, skb->len, DMA_FROM_DEVICE); | ||
173 | if (unlikely(dma_mapping_error(dev, pa))) { | ||
174 | kfree_skb(skb); | ||
175 | return -ENOMEM; | ||
176 | } | ||
177 | |||
178 | d->dma.d0 = BIT(9) | RX_DMA_D0_CMD_DMA_IT; | ||
179 | d->dma.addr_low = lower_32_bits(pa); | ||
180 | d->dma.addr_high = (u16)upper_32_bits(pa); | ||
181 | /* ip_length don't care */ | ||
182 | /* b11 don't care */ | ||
183 | /* error don't care */ | ||
184 | d->dma.status = 0; /* BIT(0) should be 0 for HW_OWNED */ | ||
185 | d->dma.length = sz; | ||
186 | vring->ctx[i] = skb; | ||
187 | |||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | /** | ||
192 | * Adds radiotap header | ||
193 | * | ||
194 | * Any error indicated as "Bad FCS" | ||
195 | * | ||
196 | * Vendor data for 04:ce:14-1 (Wilocity-1) consists of: | ||
197 | * - Rx descriptor: 32 bytes | ||
198 | * - Phy info | ||
199 | */ | ||
200 | static void wil_rx_add_radiotap_header(struct wil6210_priv *wil, | ||
201 | struct sk_buff *skb, | ||
202 | volatile struct vring_rx_desc *d) | ||
203 | { | ||
204 | struct wireless_dev *wdev = wil->wdev; | ||
205 | struct wil6210_rtap { | ||
206 | struct ieee80211_radiotap_header rthdr; | ||
207 | /* fields should be in the order of bits in rthdr.it_present */ | ||
208 | /* flags */ | ||
209 | u8 flags; | ||
210 | /* channel */ | ||
211 | __le16 chnl_freq __aligned(2); | ||
212 | __le16 chnl_flags; | ||
213 | /* MCS */ | ||
214 | u8 mcs_present; | ||
215 | u8 mcs_flags; | ||
216 | u8 mcs_index; | ||
217 | } __packed; | ||
218 | struct wil6210_rtap_vendor { | ||
219 | struct wil6210_rtap rtap; | ||
220 | /* vendor */ | ||
221 | u8 vendor_oui[3] __aligned(2); | ||
222 | u8 vendor_ns; | ||
223 | __le16 vendor_skip; | ||
224 | u8 vendor_data[0]; | ||
225 | } __packed; | ||
226 | struct wil6210_rtap_vendor *rtap_vendor; | ||
227 | int rtap_len = sizeof(struct wil6210_rtap); | ||
228 | int phy_length = 0; /* phy info header size, bytes */ | ||
229 | static char phy_data[128]; | ||
230 | struct ieee80211_channel *ch = wdev->preset_chandef.chan; | ||
231 | |||
232 | if (rtap_include_phy_info) { | ||
233 | rtap_len = sizeof(*rtap_vendor) + sizeof(*d); | ||
234 | /* calculate additional length */ | ||
235 | if (d->dma.status & RX_DMA_STATUS_PHY_INFO) { | ||
236 | /** | ||
237 | * PHY info starts from 8-byte boundary | ||
238 | * there are 8-byte lines, last line may be partially | ||
239 | * written (HW bug), thus FW configures for last line | ||
240 | * to be excessive. Driver skips this last line. | ||
241 | */ | ||
242 | int len = min_t(int, 8 + sizeof(phy_data), | ||
243 | wil_rxdesc_phy_length(d)); | ||
244 | if (len > 8) { | ||
245 | void *p = skb_tail_pointer(skb); | ||
246 | void *pa = PTR_ALIGN(p, 8); | ||
247 | if (skb_tailroom(skb) >= len + (pa - p)) { | ||
248 | phy_length = len - 8; | ||
249 | memcpy(phy_data, pa, phy_length); | ||
250 | } | ||
251 | } | ||
252 | } | ||
253 | rtap_len += phy_length; | ||
254 | } | ||
255 | |||
256 | if (skb_headroom(skb) < rtap_len && | ||
257 | pskb_expand_head(skb, rtap_len, 0, GFP_ATOMIC)) { | ||
258 | wil_err(wil, "Unable to expand headrom to %d\n", rtap_len); | ||
259 | return; | ||
260 | } | ||
261 | |||
262 | rtap_vendor = (void *)skb_push(skb, rtap_len); | ||
263 | memset(rtap_vendor, 0, rtap_len); | ||
264 | |||
265 | rtap_vendor->rtap.rthdr.it_version = PKTHDR_RADIOTAP_VERSION; | ||
266 | rtap_vendor->rtap.rthdr.it_len = cpu_to_le16(rtap_len); | ||
267 | rtap_vendor->rtap.rthdr.it_present = cpu_to_le32( | ||
268 | (1 << IEEE80211_RADIOTAP_FLAGS) | | ||
269 | (1 << IEEE80211_RADIOTAP_CHANNEL) | | ||
270 | (1 << IEEE80211_RADIOTAP_MCS)); | ||
271 | if (d->dma.status & RX_DMA_STATUS_ERROR) | ||
272 | rtap_vendor->rtap.flags |= IEEE80211_RADIOTAP_F_BADFCS; | ||
273 | |||
274 | rtap_vendor->rtap.chnl_freq = cpu_to_le16(ch ? ch->center_freq : 58320); | ||
275 | rtap_vendor->rtap.chnl_flags = cpu_to_le16(0); | ||
276 | |||
277 | rtap_vendor->rtap.mcs_present = IEEE80211_RADIOTAP_MCS_HAVE_MCS; | ||
278 | rtap_vendor->rtap.mcs_flags = 0; | ||
279 | rtap_vendor->rtap.mcs_index = wil_rxdesc_mcs(d); | ||
280 | |||
281 | if (rtap_include_phy_info) { | ||
282 | rtap_vendor->rtap.rthdr.it_present |= cpu_to_le32(1 << | ||
283 | IEEE80211_RADIOTAP_VENDOR_NAMESPACE); | ||
284 | /* OUI for Wilocity 04:ce:14 */ | ||
285 | rtap_vendor->vendor_oui[0] = 0x04; | ||
286 | rtap_vendor->vendor_oui[1] = 0xce; | ||
287 | rtap_vendor->vendor_oui[2] = 0x14; | ||
288 | rtap_vendor->vendor_ns = 1; | ||
289 | /* Rx descriptor + PHY data */ | ||
290 | rtap_vendor->vendor_skip = cpu_to_le16(sizeof(*d) + | ||
291 | phy_length); | ||
292 | memcpy(rtap_vendor->vendor_data, (void *)d, sizeof(*d)); | ||
293 | memcpy(rtap_vendor->vendor_data + sizeof(*d), phy_data, | ||
294 | phy_length); | ||
295 | } | ||
296 | } | ||
297 | |||
298 | /* | ||
299 | * Fast swap in place between 2 registers | ||
300 | */ | ||
301 | static void wil_swap_u16(u16 *a, u16 *b) | ||
302 | { | ||
303 | *a ^= *b; | ||
304 | *b ^= *a; | ||
305 | *a ^= *b; | ||
306 | } | ||
307 | |||
308 | static void wil_swap_ethaddr(void *data) | ||
309 | { | ||
310 | struct ethhdr *eth = data; | ||
311 | u16 *s = (u16 *)eth->h_source; | ||
312 | u16 *d = (u16 *)eth->h_dest; | ||
313 | |||
314 | wil_swap_u16(s++, d++); | ||
315 | wil_swap_u16(s++, d++); | ||
316 | wil_swap_u16(s, d); | ||
317 | } | ||
318 | |||
319 | /** | ||
320 | * reap 1 frame from @swhead | ||
321 | * | ||
322 | * Safe to call from IRQ | ||
323 | */ | ||
324 | static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, | ||
325 | struct vring *vring) | ||
326 | { | ||
327 | struct device *dev = wil_to_dev(wil); | ||
328 | struct net_device *ndev = wil_to_ndev(wil); | ||
329 | volatile struct vring_rx_desc *d; | ||
330 | struct sk_buff *skb; | ||
331 | dma_addr_t pa; | ||
332 | unsigned int sz = RX_BUF_LEN; | ||
333 | u8 ftype; | ||
334 | u8 ds_bits; | ||
335 | |||
336 | if (wil_vring_is_empty(vring)) | ||
337 | return NULL; | ||
338 | |||
339 | d = &(vring->va[vring->swhead].rx); | ||
340 | if (!(d->dma.status & RX_DMA_STATUS_DU)) { | ||
341 | /* it is not error, we just reached end of Rx done area */ | ||
342 | return NULL; | ||
343 | } | ||
344 | |||
345 | pa = d->dma.addr_low | ((u64)d->dma.addr_high << 32); | ||
346 | skb = vring->ctx[vring->swhead]; | ||
347 | dma_unmap_single(dev, pa, sz, DMA_FROM_DEVICE); | ||
348 | skb_trim(skb, d->dma.length); | ||
349 | |||
350 | wil->stats.last_mcs_rx = wil_rxdesc_mcs(d); | ||
351 | |||
352 | /* use radiotap header only if required */ | ||
353 | if (ndev->type == ARPHRD_IEEE80211_RADIOTAP) | ||
354 | wil_rx_add_radiotap_header(wil, skb, d); | ||
355 | |||
356 | wil_dbg_TXRX(wil, "Rx[%3d] : %d bytes\n", vring->swhead, d->dma.length); | ||
357 | wil_hex_dump_TXRX("Rx ", DUMP_PREFIX_NONE, 32, 4, | ||
358 | (const void *)d, sizeof(*d), false); | ||
359 | |||
360 | wil_vring_advance_head(vring, 1); | ||
361 | |||
362 | /* no extra checks if in sniffer mode */ | ||
363 | if (ndev->type != ARPHRD_ETHER) | ||
364 | return skb; | ||
365 | /* | ||
366 | * Non-data frames may be delivered through Rx DMA channel (ex: BAR) | ||
367 | * Driver should recognize it by frame type, that is found | ||
368 | * in Rx descriptor. If type is not data, it is 802.11 frame as is | ||
369 | */ | ||
370 | ftype = wil_rxdesc_ftype(d) << 2; | ||
371 | if (ftype != IEEE80211_FTYPE_DATA) { | ||
372 | wil_dbg_TXRX(wil, "Non-data frame ftype 0x%08x\n", ftype); | ||
373 | /* TODO: process it */ | ||
374 | kfree_skb(skb); | ||
375 | return NULL; | ||
376 | } | ||
377 | |||
378 | if (skb->len < ETH_HLEN) { | ||
379 | wil_err(wil, "Short frame, len = %d\n", skb->len); | ||
380 | /* TODO: process it (i.e. BAR) */ | ||
381 | kfree_skb(skb); | ||
382 | return NULL; | ||
383 | } | ||
384 | |||
385 | ds_bits = wil_rxdesc_ds_bits(d); | ||
386 | if (ds_bits == 1) { | ||
387 | /* | ||
388 | * HW bug - in ToDS mode, i.e. Rx on AP side, | ||
389 | * addresses get swapped | ||
390 | */ | ||
391 | wil_swap_ethaddr(skb->data); | ||
392 | } | ||
393 | |||
394 | return skb; | ||
395 | } | ||
396 | |||
397 | /** | ||
398 | * allocate and fill up to @count buffers in rx ring | ||
399 | * buffers posted at @swtail | ||
400 | */ | ||
401 | static int wil_rx_refill(struct wil6210_priv *wil, int count) | ||
402 | { | ||
403 | struct net_device *ndev = wil_to_ndev(wil); | ||
404 | struct vring *v = &wil->vring_rx; | ||
405 | u32 next_tail; | ||
406 | int rc = 0; | ||
407 | int headroom = ndev->type == ARPHRD_IEEE80211_RADIOTAP ? | ||
408 | WIL6210_RTAP_SIZE : 0; | ||
409 | |||
410 | for (; next_tail = wil_vring_next_tail(v), | ||
411 | (next_tail != v->swhead) && (count-- > 0); | ||
412 | v->swtail = next_tail) { | ||
413 | rc = wil_vring_alloc_skb(wil, v, v->swtail, headroom); | ||
414 | if (rc) { | ||
415 | wil_err(wil, "Error %d in wil_rx_refill[%d]\n", | ||
416 | rc, v->swtail); | ||
417 | break; | ||
418 | } | ||
419 | } | ||
420 | iowrite32(v->swtail, wil->csr + HOSTADDR(v->hwtail)); | ||
421 | |||
422 | return rc; | ||
423 | } | ||
424 | |||
425 | /* | ||
426 | * Pass Rx packet to the netif. Update statistics. | ||
427 | */ | ||
428 | static void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) | ||
429 | { | ||
430 | int rc; | ||
431 | unsigned int len = skb->len; | ||
432 | |||
433 | if (in_interrupt()) | ||
434 | rc = netif_rx(skb); | ||
435 | else | ||
436 | rc = netif_rx_ni(skb); | ||
437 | |||
438 | if (likely(rc == NET_RX_SUCCESS)) { | ||
439 | ndev->stats.rx_packets++; | ||
440 | ndev->stats.rx_bytes += len; | ||
441 | |||
442 | } else { | ||
443 | ndev->stats.rx_dropped++; | ||
444 | } | ||
445 | } | ||
446 | |||
447 | /** | ||
448 | * Proceed all completed skb's from Rx VRING | ||
449 | * | ||
450 | * Safe to call from IRQ | ||
451 | */ | ||
452 | void wil_rx_handle(struct wil6210_priv *wil) | ||
453 | { | ||
454 | struct net_device *ndev = wil_to_ndev(wil); | ||
455 | struct vring *v = &wil->vring_rx; | ||
456 | struct sk_buff *skb; | ||
457 | |||
458 | if (!v->va) { | ||
459 | wil_err(wil, "Rx IRQ while Rx not yet initialized\n"); | ||
460 | return; | ||
461 | } | ||
462 | wil_dbg_TXRX(wil, "%s()\n", __func__); | ||
463 | while (NULL != (skb = wil_vring_reap_rx(wil, v))) { | ||
464 | wil_hex_dump_TXRX("Rx ", DUMP_PREFIX_OFFSET, 16, 1, | ||
465 | skb->data, skb_headlen(skb), false); | ||
466 | |||
467 | skb_orphan(skb); | ||
468 | |||
469 | if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) { | ||
470 | skb->dev = ndev; | ||
471 | skb_reset_mac_header(skb); | ||
472 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
473 | skb->pkt_type = PACKET_OTHERHOST; | ||
474 | skb->protocol = htons(ETH_P_802_2); | ||
475 | |||
476 | } else { | ||
477 | skb->protocol = eth_type_trans(skb, ndev); | ||
478 | } | ||
479 | |||
480 | wil_netif_rx_any(skb, ndev); | ||
481 | } | ||
482 | wil_rx_refill(wil, v->size); | ||
483 | } | ||
484 | |||
485 | int wil_rx_init(struct wil6210_priv *wil) | ||
486 | { | ||
487 | struct net_device *ndev = wil_to_ndev(wil); | ||
488 | struct wireless_dev *wdev = wil->wdev; | ||
489 | struct vring *vring = &wil->vring_rx; | ||
490 | int rc; | ||
491 | struct wmi_cfg_rx_chain_cmd cmd = { | ||
492 | .action = WMI_RX_CHAIN_ADD, | ||
493 | .rx_sw_ring = { | ||
494 | .max_mpdu_size = cpu_to_le16(RX_BUF_LEN), | ||
495 | }, | ||
496 | .mid = 0, /* TODO - what is it? */ | ||
497 | .decap_trans_type = WMI_DECAP_TYPE_802_3, | ||
498 | }; | ||
499 | struct { | ||
500 | struct wil6210_mbox_hdr_wmi wmi; | ||
501 | struct wmi_cfg_rx_chain_done_event evt; | ||
502 | } __packed evt; | ||
503 | |||
504 | vring->size = WIL6210_RX_RING_SIZE; | ||
505 | rc = wil_vring_alloc(wil, vring); | ||
506 | if (rc) | ||
507 | return rc; | ||
508 | |||
509 | cmd.rx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa); | ||
510 | cmd.rx_sw_ring.ring_size = cpu_to_le16(vring->size); | ||
511 | if (wdev->iftype == NL80211_IFTYPE_MONITOR) { | ||
512 | struct ieee80211_channel *ch = wdev->preset_chandef.chan; | ||
513 | |||
514 | cmd.sniffer_cfg.mode = cpu_to_le32(WMI_SNIFFER_ON); | ||
515 | if (ch) | ||
516 | cmd.sniffer_cfg.channel = ch->hw_value - 1; | ||
517 | cmd.sniffer_cfg.phy_info_mode = | ||
518 | cpu_to_le32(ndev->type == ARPHRD_IEEE80211_RADIOTAP); | ||
519 | cmd.sniffer_cfg.phy_support = | ||
520 | cpu_to_le32((wil->monitor_flags & MONITOR_FLAG_CONTROL) | ||
521 | ? WMI_SNIFFER_CP : WMI_SNIFFER_DP); | ||
522 | } | ||
523 | /* typical time for secure PCP is 840ms */ | ||
524 | rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, &cmd, sizeof(cmd), | ||
525 | WMI_CFG_RX_CHAIN_DONE_EVENTID, &evt, sizeof(evt), 2000); | ||
526 | if (rc) | ||
527 | goto err_free; | ||
528 | |||
529 | vring->hwtail = le32_to_cpu(evt.evt.rx_ring_tail_ptr); | ||
530 | |||
531 | wil_dbg(wil, "Rx init: status %d tail 0x%08x\n", | ||
532 | le32_to_cpu(evt.evt.status), vring->hwtail); | ||
533 | |||
534 | rc = wil_rx_refill(wil, vring->size); | ||
535 | if (rc) | ||
536 | goto err_free; | ||
537 | |||
538 | return 0; | ||
539 | err_free: | ||
540 | wil_vring_free(wil, vring, 0); | ||
541 | |||
542 | return rc; | ||
543 | } | ||
544 | |||
545 | void wil_rx_fini(struct wil6210_priv *wil) | ||
546 | { | ||
547 | struct vring *vring = &wil->vring_rx; | ||
548 | |||
549 | if (vring->va) { | ||
550 | int rc; | ||
551 | struct wmi_cfg_rx_chain_cmd cmd = { | ||
552 | .action = cpu_to_le32(WMI_RX_CHAIN_DEL), | ||
553 | .rx_sw_ring = { | ||
554 | .max_mpdu_size = cpu_to_le16(RX_BUF_LEN), | ||
555 | }, | ||
556 | }; | ||
557 | struct { | ||
558 | struct wil6210_mbox_hdr_wmi wmi; | ||
559 | struct wmi_cfg_rx_chain_done_event cfg; | ||
560 | } __packed wmi_rx_cfg_reply; | ||
561 | |||
562 | rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, &cmd, sizeof(cmd), | ||
563 | WMI_CFG_RX_CHAIN_DONE_EVENTID, | ||
564 | &wmi_rx_cfg_reply, sizeof(wmi_rx_cfg_reply), | ||
565 | 100); | ||
566 | wil_vring_free(wil, vring, 0); | ||
567 | } | ||
568 | } | ||
569 | |||
570 | int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, | ||
571 | int cid, int tid) | ||
572 | { | ||
573 | int rc; | ||
574 | struct wmi_vring_cfg_cmd cmd = { | ||
575 | .action = cpu_to_le32(WMI_VRING_CMD_ADD), | ||
576 | .vring_cfg = { | ||
577 | .tx_sw_ring = { | ||
578 | .max_mpdu_size = cpu_to_le16(TX_BUF_LEN), | ||
579 | }, | ||
580 | .ringid = id, | ||
581 | .cidxtid = (cid & 0xf) | ((tid & 0xf) << 4), | ||
582 | .encap_trans_type = WMI_VRING_ENC_TYPE_802_3, | ||
583 | .mac_ctrl = 0, | ||
584 | .to_resolution = 0, | ||
585 | .agg_max_wsize = 16, | ||
586 | .schd_params = { | ||
587 | .priority = cpu_to_le16(0), | ||
588 | .timeslot_us = cpu_to_le16(0xfff), | ||
589 | }, | ||
590 | }, | ||
591 | }; | ||
592 | struct { | ||
593 | struct wil6210_mbox_hdr_wmi wmi; | ||
594 | struct wmi_vring_cfg_done_event cmd; | ||
595 | } __packed reply; | ||
596 | struct vring *vring = &wil->vring_tx[id]; | ||
597 | |||
598 | if (vring->va) { | ||
599 | wil_err(wil, "Tx ring [%d] already allocated\n", id); | ||
600 | rc = -EINVAL; | ||
601 | goto out; | ||
602 | } | ||
603 | |||
604 | vring->size = size; | ||
605 | rc = wil_vring_alloc(wil, vring); | ||
606 | if (rc) | ||
607 | goto out; | ||
608 | |||
609 | cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa); | ||
610 | cmd.vring_cfg.tx_sw_ring.ring_size = cpu_to_le16(vring->size); | ||
611 | |||
612 | rc = wmi_call(wil, WMI_VRING_CFG_CMDID, &cmd, sizeof(cmd), | ||
613 | WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), 100); | ||
614 | if (rc) | ||
615 | goto out_free; | ||
616 | |||
617 | if (reply.cmd.status != WMI_VRING_CFG_SUCCESS) { | ||
618 | wil_err(wil, "Tx config failed, status 0x%02x\n", | ||
619 | reply.cmd.status); | ||
620 | goto out_free; | ||
621 | } | ||
622 | vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr); | ||
623 | |||
624 | return 0; | ||
625 | out_free: | ||
626 | wil_vring_free(wil, vring, 1); | ||
627 | out: | ||
628 | |||
629 | return rc; | ||
630 | } | ||
631 | |||
632 | void wil_vring_fini_tx(struct wil6210_priv *wil, int id) | ||
633 | { | ||
634 | struct vring *vring = &wil->vring_tx[id]; | ||
635 | |||
636 | if (!vring->va) | ||
637 | return; | ||
638 | |||
639 | wil_vring_free(wil, vring, 1); | ||
640 | } | ||
641 | |||
642 | static struct vring *wil_find_tx_vring(struct wil6210_priv *wil, | ||
643 | struct sk_buff *skb) | ||
644 | { | ||
645 | struct vring *v = &wil->vring_tx[0]; | ||
646 | |||
647 | if (v->va) | ||
648 | return v; | ||
649 | |||
650 | return NULL; | ||
651 | } | ||
652 | |||
653 | static int wil_tx_desc_map(volatile struct vring_tx_desc *d, | ||
654 | dma_addr_t pa, u32 len) | ||
655 | { | ||
656 | d->dma.addr_low = lower_32_bits(pa); | ||
657 | d->dma.addr_high = (u16)upper_32_bits(pa); | ||
658 | d->dma.ip_length = 0; | ||
659 | /* 0..6: mac_length; 7:ip_version 0-IP6 1-IP4*/ | ||
660 | d->dma.b11 = 0/*14 | BIT(7)*/; | ||
661 | d->dma.error = 0; | ||
662 | d->dma.status = 0; /* BIT(0) should be 0 for HW_OWNED */ | ||
663 | d->dma.length = len; | ||
664 | d->dma.d0 = 0; | ||
665 | d->mac.d[0] = 0; | ||
666 | d->mac.d[1] = 0; | ||
667 | d->mac.d[2] = 0; | ||
668 | d->mac.ucode_cmd = 0; | ||
669 | /* use dst index 0 */ | ||
670 | d->mac.d[1] |= BIT(MAC_CFG_DESC_TX_1_DST_INDEX_EN_POS) | | ||
671 | (0 << MAC_CFG_DESC_TX_1_DST_INDEX_POS); | ||
672 | /* translation type: 0 - bypass; 1 - 802.3; 2 - native wifi */ | ||
673 | d->mac.d[2] = BIT(MAC_CFG_DESC_TX_2_SNAP_HDR_INSERTION_EN_POS) | | ||
674 | (1 << MAC_CFG_DESC_TX_2_L2_TRANSLATION_TYPE_POS); | ||
675 | |||
676 | return 0; | ||
677 | } | ||
678 | |||
679 | static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, | ||
680 | struct sk_buff *skb) | ||
681 | { | ||
682 | struct device *dev = wil_to_dev(wil); | ||
683 | volatile struct vring_tx_desc *d; | ||
684 | u32 swhead = vring->swhead; | ||
685 | int avail = wil_vring_avail_tx(vring); | ||
686 | int nr_frags = skb_shinfo(skb)->nr_frags; | ||
687 | uint f; | ||
688 | int vring_index = vring - wil->vring_tx; | ||
689 | uint i = swhead; | ||
690 | dma_addr_t pa; | ||
691 | |||
692 | wil_dbg_TXRX(wil, "%s()\n", __func__); | ||
693 | |||
694 | if (avail < vring->size/8) | ||
695 | netif_tx_stop_all_queues(wil_to_ndev(wil)); | ||
696 | if (avail < 1 + nr_frags) { | ||
697 | wil_err(wil, "Tx ring full. No space for %d fragments\n", | ||
698 | 1 + nr_frags); | ||
699 | return -ENOMEM; | ||
700 | } | ||
701 | d = &(vring->va[i].tx); | ||
702 | |||
703 | /* FIXME FW can accept only unicast frames for the peer */ | ||
704 | memcpy(skb->data, wil->dst_addr[vring_index], ETH_ALEN); | ||
705 | |||
706 | pa = dma_map_single(dev, skb->data, | ||
707 | skb_headlen(skb), DMA_TO_DEVICE); | ||
708 | |||
709 | wil_dbg_TXRX(wil, "Tx skb %d bytes %p -> %#08llx\n", skb_headlen(skb), | ||
710 | skb->data, (unsigned long long)pa); | ||
711 | wil_hex_dump_TXRX("Tx ", DUMP_PREFIX_OFFSET, 16, 1, | ||
712 | skb->data, skb_headlen(skb), false); | ||
713 | |||
714 | if (unlikely(dma_mapping_error(dev, pa))) | ||
715 | return -EINVAL; | ||
716 | /* 1-st segment */ | ||
717 | wil_tx_desc_map(d, pa, skb_headlen(skb)); | ||
718 | d->mac.d[2] |= ((nr_frags + 1) << | ||
719 | MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_POS); | ||
720 | /* middle segments */ | ||
721 | for (f = 0; f < nr_frags; f++) { | ||
722 | const struct skb_frag_struct *frag = | ||
723 | &skb_shinfo(skb)->frags[f]; | ||
724 | int len = skb_frag_size(frag); | ||
725 | i = (swhead + f + 1) % vring->size; | ||
726 | d = &(vring->va[i].tx); | ||
727 | pa = skb_frag_dma_map(dev, frag, 0, skb_frag_size(frag), | ||
728 | DMA_TO_DEVICE); | ||
729 | if (unlikely(dma_mapping_error(dev, pa))) | ||
730 | goto dma_error; | ||
731 | wil_tx_desc_map(d, pa, len); | ||
732 | vring->ctx[i] = NULL; | ||
733 | } | ||
734 | /* for the last seg only */ | ||
735 | d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_EOP_POS); | ||
736 | d->dma.d0 |= BIT(9); /* BUG: undocumented bit */ | ||
737 | d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_DMA_IT_POS); | ||
738 | d->dma.d0 |= (vring_index << DMA_CFG_DESC_TX_0_QID_POS); | ||
739 | |||
740 | wil_hex_dump_TXRX("Tx ", DUMP_PREFIX_NONE, 32, 4, | ||
741 | (const void *)d, sizeof(*d), false); | ||
742 | |||
743 | /* advance swhead */ | ||
744 | wil_vring_advance_head(vring, nr_frags + 1); | ||
745 | wil_dbg_TXRX(wil, "Tx swhead %d -> %d\n", swhead, vring->swhead); | ||
746 | iowrite32(vring->swhead, wil->csr + HOSTADDR(vring->hwtail)); | ||
747 | /* hold reference to skb | ||
748 | * to prevent skb release before accounting | ||
749 | * in case of immediate "tx done" | ||
750 | */ | ||
751 | vring->ctx[i] = skb_get(skb); | ||
752 | |||
753 | return 0; | ||
754 | dma_error: | ||
755 | /* unmap what we have mapped */ | ||
756 | /* Note: increment @f to operate with positive index */ | ||
757 | for (f++; f > 0; f--) { | ||
758 | i = (swhead + f) % vring->size; | ||
759 | d = &(vring->va[i].tx); | ||
760 | d->dma.status = TX_DMA_STATUS_DU; | ||
761 | pa = d->dma.addr_low | ((u64)d->dma.addr_high << 32); | ||
762 | if (vring->ctx[i]) | ||
763 | dma_unmap_single(dev, pa, d->dma.length, DMA_TO_DEVICE); | ||
764 | else | ||
765 | dma_unmap_page(dev, pa, d->dma.length, DMA_TO_DEVICE); | ||
766 | } | ||
767 | |||
768 | return -EINVAL; | ||
769 | } | ||
770 | |||
771 | |||
772 | netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) | ||
773 | { | ||
774 | struct wil6210_priv *wil = ndev_to_wil(ndev); | ||
775 | struct vring *vring; | ||
776 | int rc; | ||
777 | |||
778 | wil_dbg_TXRX(wil, "%s()\n", __func__); | ||
779 | if (!test_bit(wil_status_fwready, &wil->status)) { | ||
780 | wil_err(wil, "FW not ready\n"); | ||
781 | goto drop; | ||
782 | } | ||
783 | if (!test_bit(wil_status_fwconnected, &wil->status)) { | ||
784 | wil_err(wil, "FW not connected\n"); | ||
785 | goto drop; | ||
786 | } | ||
787 | if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) { | ||
788 | wil_err(wil, "Xmit in monitor mode not supported\n"); | ||
789 | goto drop; | ||
790 | } | ||
791 | if (skb->protocol == cpu_to_be16(ETH_P_PAE)) { | ||
792 | rc = wmi_tx_eapol(wil, skb); | ||
793 | } else { | ||
794 | /* find vring */ | ||
795 | vring = wil_find_tx_vring(wil, skb); | ||
796 | if (!vring) { | ||
797 | wil_err(wil, "No Tx VRING available\n"); | ||
798 | goto drop; | ||
799 | } | ||
800 | /* set up vring entry */ | ||
801 | rc = wil_tx_vring(wil, vring, skb); | ||
802 | } | ||
803 | switch (rc) { | ||
804 | case 0: | ||
805 | ndev->stats.tx_packets++; | ||
806 | ndev->stats.tx_bytes += skb->len; | ||
807 | dev_kfree_skb_any(skb); | ||
808 | return NETDEV_TX_OK; | ||
809 | case -ENOMEM: | ||
810 | return NETDEV_TX_BUSY; | ||
811 | default: | ||
812 | ; /* goto drop; */ | ||
813 | break; | ||
814 | } | ||
815 | drop: | ||
816 | netif_tx_stop_all_queues(ndev); | ||
817 | ndev->stats.tx_dropped++; | ||
818 | dev_kfree_skb_any(skb); | ||
819 | |||
820 | return NET_XMIT_DROP; | ||
821 | } | ||
822 | |||
823 | /** | ||
824 | * Clean up transmitted skb's from the Tx VRING | ||
825 | * | ||
826 | * Safe to call from IRQ | ||
827 | */ | ||
828 | void wil_tx_complete(struct wil6210_priv *wil, int ringid) | ||
829 | { | ||
830 | struct device *dev = wil_to_dev(wil); | ||
831 | struct vring *vring = &wil->vring_tx[ringid]; | ||
832 | |||
833 | if (!vring->va) { | ||
834 | wil_err(wil, "Tx irq[%d]: vring not initialized\n", ringid); | ||
835 | return; | ||
836 | } | ||
837 | |||
838 | wil_dbg_TXRX(wil, "%s(%d)\n", __func__, ringid); | ||
839 | |||
840 | while (!wil_vring_is_empty(vring)) { | ||
841 | volatile struct vring_tx_desc *d = &vring->va[vring->swtail].tx; | ||
842 | dma_addr_t pa; | ||
843 | struct sk_buff *skb; | ||
844 | if (!(d->dma.status & TX_DMA_STATUS_DU)) | ||
845 | break; | ||
846 | |||
847 | wil_dbg_TXRX(wil, | ||
848 | "Tx[%3d] : %d bytes, status 0x%02x err 0x%02x\n", | ||
849 | vring->swtail, d->dma.length, d->dma.status, | ||
850 | d->dma.error); | ||
851 | wil_hex_dump_TXRX("TxC ", DUMP_PREFIX_NONE, 32, 4, | ||
852 | (const void *)d, sizeof(*d), false); | ||
853 | |||
854 | pa = d->dma.addr_low | ((u64)d->dma.addr_high << 32); | ||
855 | skb = vring->ctx[vring->swtail]; | ||
856 | if (skb) { | ||
857 | dma_unmap_single(dev, pa, d->dma.length, DMA_TO_DEVICE); | ||
858 | dev_kfree_skb_any(skb); | ||
859 | vring->ctx[vring->swtail] = NULL; | ||
860 | } else { | ||
861 | dma_unmap_page(dev, pa, d->dma.length, DMA_TO_DEVICE); | ||
862 | } | ||
863 | d->dma.addr_low = 0; | ||
864 | d->dma.addr_high = 0; | ||
865 | d->dma.length = 0; | ||
866 | d->dma.status = TX_DMA_STATUS_DU; | ||
867 | vring->swtail = wil_vring_next_tail(vring); | ||
868 | } | ||
869 | if (wil_vring_avail_tx(vring) > vring->size/4) | ||
870 | netif_tx_wake_all_queues(wil_to_ndev(wil)); | ||
871 | } | ||
diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h new file mode 100644 index 000000000000..45a61f597c5c --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/txrx.h | |||
@@ -0,0 +1,362 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012 Qualcomm Atheros, Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #ifndef WIL6210_TXRX_H | ||
18 | #define WIL6210_TXRX_H | ||
19 | |||
20 | #define BUF_SW_OWNED (1) | ||
21 | #define BUF_HW_OWNED (0) | ||
22 | |||
23 | /* size of max. Rx packet */ | ||
24 | #define RX_BUF_LEN (2048) | ||
25 | #define TX_BUF_LEN (2048) | ||
26 | /* how many bytes to reserve for rtap header? */ | ||
27 | #define WIL6210_RTAP_SIZE (128) | ||
28 | |||
29 | /* Tx/Rx path */ | ||
30 | /* | ||
31 | * Tx descriptor - MAC part | ||
32 | * [dword 0] | ||
33 | * bit 0.. 9 : lifetime_expiry_value:10 | ||
34 | * bit 10 : interrup_en:1 | ||
35 | * bit 11 : status_en:1 | ||
36 | * bit 12..13 : txss_override:2 | ||
37 | * bit 14 : timestamp_insertion:1 | ||
38 | * bit 15 : duration_preserve:1 | ||
39 | * bit 16..21 : reserved0:6 | ||
40 | * bit 22..26 : mcs_index:5 | ||
41 | * bit 27 : mcs_en:1 | ||
42 | * bit 28..29 : reserved1:2 | ||
43 | * bit 30 : reserved2:1 | ||
44 | * bit 31 : sn_preserved:1 | ||
45 | * [dword 1] | ||
46 | * bit 0.. 3 : pkt_mode:4 | ||
47 | * bit 4 : pkt_mode_en:1 | ||
48 | * bit 5.. 7 : reserved0:3 | ||
49 | * bit 8..13 : reserved1:6 | ||
50 | * bit 14 : reserved2:1 | ||
51 | * bit 15 : ack_policy_en:1 | ||
52 | * bit 16..19 : dst_index:4 | ||
53 | * bit 20 : dst_index_en:1 | ||
54 | * bit 21..22 : ack_policy:2 | ||
55 | * bit 23 : lifetime_en:1 | ||
56 | * bit 24..30 : max_retry:7 | ||
57 | * bit 31 : max_retry_en:1 | ||
58 | * [dword 2] | ||
59 | * bit 0.. 7 : num_of_descriptors:8 | ||
60 | * bit 8..17 : reserved:10 | ||
61 | * bit 18..19 : l2_translation_type:2 | ||
62 | * bit 20 : snap_hdr_insertion_en:1 | ||
63 | * bit 21 : vlan_removal_en:1 | ||
64 | * bit 22..31 : reserved0:10 | ||
65 | * [dword 3] | ||
66 | * bit 0.. 31: ucode_cmd:32 | ||
67 | */ | ||
68 | struct vring_tx_mac { | ||
69 | u32 d[3]; | ||
70 | u32 ucode_cmd; | ||
71 | } __packed; | ||
72 | |||
73 | /* TX MAC Dword 0 */ | ||
74 | #define MAC_CFG_DESC_TX_0_LIFETIME_EXPIRY_VALUE_POS 0 | ||
75 | #define MAC_CFG_DESC_TX_0_LIFETIME_EXPIRY_VALUE_LEN 10 | ||
76 | #define MAC_CFG_DESC_TX_0_LIFETIME_EXPIRY_VALUE_MSK 0x3FF | ||
77 | |||
78 | #define MAC_CFG_DESC_TX_0_INTERRUP_EN_POS 10 | ||
79 | #define MAC_CFG_DESC_TX_0_INTERRUP_EN_LEN 1 | ||
80 | #define MAC_CFG_DESC_TX_0_INTERRUP_EN_MSK 0x400 | ||
81 | |||
82 | #define MAC_CFG_DESC_TX_0_STATUS_EN_POS 11 | ||
83 | #define MAC_CFG_DESC_TX_0_STATUS_EN_LEN 1 | ||
84 | #define MAC_CFG_DESC_TX_0_STATUS_EN_MSK 0x800 | ||
85 | |||
86 | #define MAC_CFG_DESC_TX_0_TXSS_OVERRIDE_POS 12 | ||
87 | #define MAC_CFG_DESC_TX_0_TXSS_OVERRIDE_LEN 2 | ||
88 | #define MAC_CFG_DESC_TX_0_TXSS_OVERRIDE_MSK 0x3000 | ||
89 | |||
90 | #define MAC_CFG_DESC_TX_0_TIMESTAMP_INSERTION_POS 14 | ||
91 | #define MAC_CFG_DESC_TX_0_TIMESTAMP_INSERTION_LEN 1 | ||
92 | #define MAC_CFG_DESC_TX_0_TIMESTAMP_INSERTION_MSK 0x4000 | ||
93 | |||
94 | #define MAC_CFG_DESC_TX_0_DURATION_PRESERVE_POS 15 | ||
95 | #define MAC_CFG_DESC_TX_0_DURATION_PRESERVE_LEN 1 | ||
96 | #define MAC_CFG_DESC_TX_0_DURATION_PRESERVE_MSK 0x8000 | ||
97 | |||
98 | #define MAC_CFG_DESC_TX_0_MCS_INDEX_POS 22 | ||
99 | #define MAC_CFG_DESC_TX_0_MCS_INDEX_LEN 5 | ||
100 | #define MAC_CFG_DESC_TX_0_MCS_INDEX_MSK 0x7C00000 | ||
101 | |||
102 | #define MAC_CFG_DESC_TX_0_MCS_EN_POS 27 | ||
103 | #define MAC_CFG_DESC_TX_0_MCS_EN_LEN 1 | ||
104 | #define MAC_CFG_DESC_TX_0_MCS_EN_MSK 0x8000000 | ||
105 | |||
106 | #define MAC_CFG_DESC_TX_0_SN_PRESERVED_POS 31 | ||
107 | #define MAC_CFG_DESC_TX_0_SN_PRESERVED_LEN 1 | ||
108 | #define MAC_CFG_DESC_TX_0_SN_PRESERVED_MSK 0x80000000 | ||
109 | |||
110 | /* TX MAC Dword 1 */ | ||
111 | #define MAC_CFG_DESC_TX_1_PKT_MODE_POS 0 | ||
112 | #define MAC_CFG_DESC_TX_1_PKT_MODE_LEN 4 | ||
113 | #define MAC_CFG_DESC_TX_1_PKT_MODE_MSK 0xF | ||
114 | |||
115 | #define MAC_CFG_DESC_TX_1_PKT_MODE_EN_POS 4 | ||
116 | #define MAC_CFG_DESC_TX_1_PKT_MODE_EN_LEN 1 | ||
117 | #define MAC_CFG_DESC_TX_1_PKT_MODE_EN_MSK 0x10 | ||
118 | |||
119 | #define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_POS 15 | ||
120 | #define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_LEN 1 | ||
121 | #define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_MSK 0x8000 | ||
122 | |||
123 | #define MAC_CFG_DESC_TX_1_DST_INDEX_POS 16 | ||
124 | #define MAC_CFG_DESC_TX_1_DST_INDEX_LEN 4 | ||
125 | #define MAC_CFG_DESC_TX_1_DST_INDEX_MSK 0xF0000 | ||
126 | |||
127 | #define MAC_CFG_DESC_TX_1_DST_INDEX_EN_POS 20 | ||
128 | #define MAC_CFG_DESC_TX_1_DST_INDEX_EN_LEN 1 | ||
129 | #define MAC_CFG_DESC_TX_1_DST_INDEX_EN_MSK 0x100000 | ||
130 | |||
131 | #define MAC_CFG_DESC_TX_1_ACK_POLICY_POS 21 | ||
132 | #define MAC_CFG_DESC_TX_1_ACK_POLICY_LEN 2 | ||
133 | #define MAC_CFG_DESC_TX_1_ACK_POLICY_MSK 0x600000 | ||
134 | |||
135 | #define MAC_CFG_DESC_TX_1_LIFETIME_EN_POS 23 | ||
136 | #define MAC_CFG_DESC_TX_1_LIFETIME_EN_LEN 1 | ||
137 | #define MAC_CFG_DESC_TX_1_LIFETIME_EN_MSK 0x800000 | ||
138 | |||
139 | #define MAC_CFG_DESC_TX_1_MAX_RETRY_POS 24 | ||
140 | #define MAC_CFG_DESC_TX_1_MAX_RETRY_LEN 7 | ||
141 | #define MAC_CFG_DESC_TX_1_MAX_RETRY_MSK 0x7F000000 | ||
142 | |||
143 | #define MAC_CFG_DESC_TX_1_MAX_RETRY_EN_POS 31 | ||
144 | #define MAC_CFG_DESC_TX_1_MAX_RETRY_EN_LEN 1 | ||
145 | #define MAC_CFG_DESC_TX_1_MAX_RETRY_EN_MSK 0x80000000 | ||
146 | |||
147 | /* TX MAC Dword 2 */ | ||
148 | #define MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_POS 0 | ||
149 | #define MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_LEN 8 | ||
150 | #define MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_MSK 0xFF | ||
151 | |||
152 | #define MAC_CFG_DESC_TX_2_RESERVED_POS 8 | ||
153 | #define MAC_CFG_DESC_TX_2_RESERVED_LEN 10 | ||
154 | #define MAC_CFG_DESC_TX_2_RESERVED_MSK 0x3FF00 | ||
155 | |||
156 | #define MAC_CFG_DESC_TX_2_L2_TRANSLATION_TYPE_POS 18 | ||
157 | #define MAC_CFG_DESC_TX_2_L2_TRANSLATION_TYPE_LEN 2 | ||
158 | #define MAC_CFG_DESC_TX_2_L2_TRANSLATION_TYPE_MSK 0xC0000 | ||
159 | |||
160 | #define MAC_CFG_DESC_TX_2_SNAP_HDR_INSERTION_EN_POS 20 | ||
161 | #define MAC_CFG_DESC_TX_2_SNAP_HDR_INSERTION_EN_LEN 1 | ||
162 | #define MAC_CFG_DESC_TX_2_SNAP_HDR_INSERTION_EN_MSK 0x100000 | ||
163 | |||
164 | #define MAC_CFG_DESC_TX_2_VLAN_REMOVAL_EN_POS 21 | ||
165 | #define MAC_CFG_DESC_TX_2_VLAN_REMOVAL_EN_LEN 1 | ||
166 | #define MAC_CFG_DESC_TX_2_VLAN_REMOVAL_EN_MSK 0x200000 | ||
167 | |||
168 | /* TX MAC Dword 3 */ | ||
169 | #define MAC_CFG_DESC_TX_3_UCODE_CMD_POS 0 | ||
170 | #define MAC_CFG_DESC_TX_3_UCODE_CMD_LEN 32 | ||
171 | #define MAC_CFG_DESC_TX_3_UCODE_CMD_MSK 0xFFFFFFFF | ||
172 | |||
173 | /* TX DMA Dword 0 */ | ||
174 | #define DMA_CFG_DESC_TX_0_L4_LENGTH_POS 0 | ||
175 | #define DMA_CFG_DESC_TX_0_L4_LENGTH_LEN 8 | ||
176 | #define DMA_CFG_DESC_TX_0_L4_LENGTH_MSK 0xFF | ||
177 | |||
178 | #define DMA_CFG_DESC_TX_0_CMD_EOP_POS 8 | ||
179 | #define DMA_CFG_DESC_TX_0_CMD_EOP_LEN 1 | ||
180 | #define DMA_CFG_DESC_TX_0_CMD_EOP_MSK 0x100 | ||
181 | |||
182 | #define DMA_CFG_DESC_TX_0_CMD_DMA_IT_POS 10 | ||
183 | #define DMA_CFG_DESC_TX_0_CMD_DMA_IT_LEN 1 | ||
184 | #define DMA_CFG_DESC_TX_0_CMD_DMA_IT_MSK 0x400 | ||
185 | |||
186 | #define DMA_CFG_DESC_TX_0_SEGMENT_BUF_DETAILS_POS 11 | ||
187 | #define DMA_CFG_DESC_TX_0_SEGMENT_BUF_DETAILS_LEN 2 | ||
188 | #define DMA_CFG_DESC_TX_0_SEGMENT_BUF_DETAILS_MSK 0x1800 | ||
189 | |||
190 | #define DMA_CFG_DESC_TX_0_TCP_SEG_EN_POS 13 | ||
191 | #define DMA_CFG_DESC_TX_0_TCP_SEG_EN_LEN 1 | ||
192 | #define DMA_CFG_DESC_TX_0_TCP_SEG_EN_MSK 0x2000 | ||
193 | |||
194 | #define DMA_CFG_DESC_TX_0_IPV4_CHECKSUM_EN_POS 14 | ||
195 | #define DMA_CFG_DESC_TX_0_IPV4_CHECKSUM_EN_LEN 1 | ||
196 | #define DMA_CFG_DESC_TX_0_IPV4_CHECKSUM_EN_MSK 0x4000 | ||
197 | |||
198 | #define DMA_CFG_DESC_TX_0_TCP_UDP_CHECKSUM_EN_POS 15 | ||
199 | #define DMA_CFG_DESC_TX_0_TCP_UDP_CHECKSUM_EN_LEN 1 | ||
200 | #define DMA_CFG_DESC_TX_0_TCP_UDP_CHECKSUM_EN_MSK 0x8000 | ||
201 | |||
202 | #define DMA_CFG_DESC_TX_0_QID_POS 16 | ||
203 | #define DMA_CFG_DESC_TX_0_QID_LEN 5 | ||
204 | #define DMA_CFG_DESC_TX_0_QID_MSK 0x1F0000 | ||
205 | |||
206 | #define DMA_CFG_DESC_TX_0_PSEUDO_HEADER_CALC_EN_POS 21 | ||
207 | #define DMA_CFG_DESC_TX_0_PSEUDO_HEADER_CALC_EN_LEN 1 | ||
208 | #define DMA_CFG_DESC_TX_0_PSEUDO_HEADER_CALC_EN_MSK 0x200000 | ||
209 | |||
210 | #define DMA_CFG_DESC_TX_0_L4_TYPE_POS 30 | ||
211 | #define DMA_CFG_DESC_TX_0_L4_TYPE_LEN 2 | ||
212 | #define DMA_CFG_DESC_TX_0_L4_TYPE_MSK 0xC0000000 | ||
213 | |||
214 | |||
215 | #define TX_DMA_STATUS_DU BIT(0) | ||
216 | |||
217 | struct vring_tx_dma { | ||
218 | u32 d0; | ||
219 | u32 addr_low; | ||
220 | u16 addr_high; | ||
221 | u8 ip_length; | ||
222 | u8 b11; /* 0..6: mac_length; 7:ip_version */ | ||
223 | u8 error; /* 0..2: err; 3..7: reserved; */ | ||
224 | u8 status; /* 0: used; 1..7; reserved */ | ||
225 | u16 length; | ||
226 | } __packed; | ||
227 | |||
228 | /* | ||
229 | * Rx descriptor - MAC part | ||
230 | * [dword 0] | ||
231 | * bit 0.. 3 : tid:4 The QoS (b3-0) TID Field | ||
232 | * bit 4.. 6 : connection_id:3 :The Source index that was found during | ||
233 | * Parsing the TA. This field is used to define the source of the packet | ||
234 | * bit 7 : reserved:1 | ||
235 | * bit 8.. 9 : mac_id:2 : The MAC virtual Ring number (always zero) | ||
236 | * bit 10..11 : frame_type:2 : The FC Control (b3-2) - MPDU Type | ||
237 | * (management, data, control and extension) | ||
238 | * bit 12..15 : frame_subtype:4 : The FC Control (b7-4) - Frame Subtype | ||
239 | * bit 16..27 : seq_number:12 The received Sequence number field | ||
240 | * bit 28..31 : extended:4 extended subtype | ||
241 | * [dword 1] | ||
242 | * bit 0.. 3 : reserved | ||
243 | * bit 4.. 5 : key_id:2 | ||
244 | * bit 6 : decrypt_bypass:1 | ||
245 | * bit 7 : security:1 | ||
246 | * bit 8.. 9 : ds_bits:2 | ||
247 | * bit 10 : a_msdu_present:1 from qos header | ||
248 | * bit 11 : a_msdu_type:1 from qos header | ||
249 | * bit 12 : a_mpdu:1 part of AMPDU aggregation | ||
250 | * bit 13 : broadcast:1 | ||
251 | * bit 14 : mutlicast:1 | ||
252 | * bit 15 : reserved:1 | ||
253 | * bit 16..20 : rx_mac_qid:5 The Queue Identifier that the packet | ||
254 | * is received from | ||
255 | * bit 21..24 : mcs:4 | ||
256 | * bit 25..28 : mic_icr:4 | ||
257 | * bit 29..31 : reserved:3 | ||
258 | * [dword 2] | ||
259 | * bit 0.. 2 : time_slot:3 The timeslot that the MPDU is received | ||
260 | * bit 3 : fc_protocol_ver:1 The FC Control (b0) - Protocol Version | ||
261 | * bit 4 : fc_order:1 The FC Control (b15) -Order | ||
262 | * bit 5.. 7 : qos_ack_policy:3 The QoS (b6-5) ack policy Field | ||
263 | * bit 8 : esop:1 The QoS (b4) ESOP field | ||
264 | * bit 9 : qos_rdg_more_ppdu:1 The QoS (b9) RDG field | ||
265 | * bit 10..14 : qos_reserved:5 The QoS (b14-10) Reserved field | ||
266 | * bit 15 : qos_ac_constraint:1 | ||
267 | * bit 16..31 : pn_15_0:16 low 2 bytes of PN | ||
268 | * [dword 3] | ||
269 | * bit 0..31 : pn_47_16:32 high 4 bytes of PN | ||
270 | */ | ||
271 | struct vring_rx_mac { | ||
272 | u32 d0; | ||
273 | u32 d1; | ||
274 | u16 w4; | ||
275 | u16 pn_15_0; | ||
276 | u32 pn_47_16; | ||
277 | } __packed; | ||
278 | |||
279 | /* | ||
280 | * Rx descriptor - DMA part | ||
281 | * [dword 0] | ||
282 | * bit 0.. 7 : l4_length:8 layer 4 length | ||
283 | * bit 8.. 9 : reserved:2 | ||
284 | * bit 10 : cmd_dma_it:1 | ||
285 | * bit 11..15 : reserved:5 | ||
286 | * bit 16..29 : phy_info_length:14 | ||
287 | * bit 30..31 : l4_type:2 valid if the L4I bit is set in the status field | ||
288 | * [dword 1] | ||
289 | * bit 0..31 : addr_low:32 The payload buffer low address | ||
290 | * [dword 2] | ||
291 | * bit 0..15 : addr_high:16 The payload buffer high address | ||
292 | * bit 16..23 : ip_length:8 | ||
293 | * bit 24..30 : mac_length:7 | ||
294 | * bit 31 : ip_version:1 | ||
295 | * [dword 3] | ||
296 | * [byte 12] error | ||
297 | * [byte 13] status | ||
298 | * bit 0 : du:1 | ||
299 | * bit 1 : eop:1 | ||
300 | * bit 2 : error:1 | ||
301 | * bit 3 : mi:1 | ||
302 | * bit 4 : l3_identified:1 | ||
303 | * bit 5 : l4_identified:1 | ||
304 | * bit 6 : phy_info_included:1 | ||
305 | * bit 7 : reserved:1 | ||
306 | * [word 7] length | ||
307 | * | ||
308 | */ | ||
309 | |||
310 | #define RX_DMA_D0_CMD_DMA_IT BIT(10) | ||
311 | |||
312 | #define RX_DMA_STATUS_DU BIT(0) | ||
313 | #define RX_DMA_STATUS_ERROR BIT(2) | ||
314 | #define RX_DMA_STATUS_PHY_INFO BIT(6) | ||
315 | |||
316 | struct vring_rx_dma { | ||
317 | u32 d0; | ||
318 | u32 addr_low; | ||
319 | u16 addr_high; | ||
320 | u8 ip_length; | ||
321 | u8 b11; | ||
322 | u8 error; | ||
323 | u8 status; | ||
324 | u16 length; | ||
325 | } __packed; | ||
326 | |||
327 | struct vring_tx_desc { | ||
328 | struct vring_tx_mac mac; | ||
329 | struct vring_tx_dma dma; | ||
330 | } __packed; | ||
331 | |||
332 | struct vring_rx_desc { | ||
333 | struct vring_rx_mac mac; | ||
334 | struct vring_rx_dma dma; | ||
335 | } __packed; | ||
336 | |||
337 | union vring_desc { | ||
338 | struct vring_tx_desc tx; | ||
339 | struct vring_rx_desc rx; | ||
340 | } __packed; | ||
341 | |||
342 | static inline int wil_rxdesc_phy_length(volatile struct vring_rx_desc *d) | ||
343 | { | ||
344 | return WIL_GET_BITS(d->dma.d0, 16, 29); | ||
345 | } | ||
346 | |||
347 | static inline int wil_rxdesc_mcs(volatile struct vring_rx_desc *d) | ||
348 | { | ||
349 | return WIL_GET_BITS(d->mac.d1, 21, 24); | ||
350 | } | ||
351 | |||
352 | static inline int wil_rxdesc_ds_bits(volatile struct vring_rx_desc *d) | ||
353 | { | ||
354 | return WIL_GET_BITS(d->mac.d1, 8, 9); | ||
355 | } | ||
356 | |||
357 | static inline int wil_rxdesc_ftype(volatile struct vring_rx_desc *d) | ||
358 | { | ||
359 | return WIL_GET_BITS(d->mac.d0, 10, 11); | ||
360 | } | ||
361 | |||
362 | #endif /* WIL6210_TXRX_H */ | ||
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h new file mode 100644 index 000000000000..9bcfffa4006c --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/wil6210.h | |||
@@ -0,0 +1,363 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012 Qualcomm Atheros, Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #ifndef __WIL6210_H__ | ||
18 | #define __WIL6210_H__ | ||
19 | |||
20 | #include <linux/netdevice.h> | ||
21 | #include <linux/wireless.h> | ||
22 | #include <net/cfg80211.h> | ||
23 | |||
24 | #include "dbg_hexdump.h" | ||
25 | |||
26 | #define WIL_NAME "wil6210" | ||
27 | |||
28 | /** | ||
29 | * extract bits [@b0:@b1] (inclusive) from the value @x | ||
30 | * it should be @b0 <= @b1, or result is incorrect | ||
31 | */ | ||
32 | static inline u32 WIL_GET_BITS(u32 x, int b0, int b1) | ||
33 | { | ||
34 | return (x >> b0) & ((1 << (b1 - b0 + 1)) - 1); | ||
35 | } | ||
36 | |||
37 | #define WIL6210_MEM_SIZE (2*1024*1024UL) | ||
38 | |||
39 | #define WIL6210_TX_QUEUES (4) | ||
40 | |||
41 | #define WIL6210_RX_RING_SIZE (128) | ||
42 | #define WIL6210_TX_RING_SIZE (128) | ||
43 | #define WIL6210_MAX_TX_RINGS (24) | ||
44 | |||
45 | /* Hardware definitions begin */ | ||
46 | |||
47 | /* | ||
48 | * Mapping | ||
49 | * RGF File | Host addr | FW addr | ||
50 | * | | | ||
51 | * user_rgf | 0x000000 | 0x880000 | ||
52 | * dma_rgf | 0x001000 | 0x881000 | ||
53 | * pcie_rgf | 0x002000 | 0x882000 | ||
54 | * | | | ||
55 | */ | ||
56 | |||
57 | /* Where various structures placed in host address space */ | ||
58 | #define WIL6210_FW_HOST_OFF (0x880000UL) | ||
59 | |||
60 | #define HOSTADDR(fwaddr) (fwaddr - WIL6210_FW_HOST_OFF) | ||
61 | |||
62 | /* | ||
63 | * Interrupt control registers block | ||
64 | * | ||
65 | * each interrupt controlled by the same bit in all registers | ||
66 | */ | ||
67 | struct RGF_ICR { | ||
68 | u32 ICC; /* Cause Control, RW: 0 - W1C, 1 - COR */ | ||
69 | u32 ICR; /* Cause, W1C/COR depending on ICC */ | ||
70 | u32 ICM; /* Cause masked (ICR & ~IMV), W1C/COR depending on ICC */ | ||
71 | u32 ICS; /* Cause Set, WO */ | ||
72 | u32 IMV; /* Mask, RW+S/C */ | ||
73 | u32 IMS; /* Mask Set, write 1 to set */ | ||
74 | u32 IMC; /* Mask Clear, write 1 to clear */ | ||
75 | } __packed; | ||
76 | |||
77 | /* registers - FW addresses */ | ||
78 | #define RGF_USER_USER_SCRATCH_PAD (0x8802bc) | ||
79 | #define RGF_USER_USER_ICR (0x880b4c) /* struct RGF_ICR */ | ||
80 | #define BIT_USER_USER_ICR_SW_INT_2 BIT(18) | ||
81 | #define RGF_USER_CLKS_CTL_SW_RST_MASK_0 (0x880b14) | ||
82 | #define RGF_USER_MAC_CPU_0 (0x8801fc) | ||
83 | #define RGF_USER_USER_CPU_0 (0x8801e0) | ||
84 | #define RGF_USER_CLKS_CTL_SW_RST_VEC_0 (0x880b04) | ||
85 | #define RGF_USER_CLKS_CTL_SW_RST_VEC_1 (0x880b08) | ||
86 | #define RGF_USER_CLKS_CTL_SW_RST_VEC_2 (0x880b0c) | ||
87 | #define RGF_USER_CLKS_CTL_SW_RST_VEC_3 (0x880b10) | ||
88 | |||
89 | #define RGF_DMA_PSEUDO_CAUSE (0x881c68) | ||
90 | #define RGF_DMA_PSEUDO_CAUSE_MASK_SW (0x881c6c) | ||
91 | #define RGF_DMA_PSEUDO_CAUSE_MASK_FW (0x881c70) | ||
92 | #define BIT_DMA_PSEUDO_CAUSE_RX BIT(0) | ||
93 | #define BIT_DMA_PSEUDO_CAUSE_TX BIT(1) | ||
94 | #define BIT_DMA_PSEUDO_CAUSE_MISC BIT(2) | ||
95 | |||
96 | #define RGF_DMA_EP_TX_ICR (0x881bb4) /* struct RGF_ICR */ | ||
97 | #define BIT_DMA_EP_TX_ICR_TX_DONE BIT(0) | ||
98 | #define BIT_DMA_EP_TX_ICR_TX_DONE_N(n) BIT(n+1) /* n = [0..23] */ | ||
99 | #define RGF_DMA_EP_RX_ICR (0x881bd0) /* struct RGF_ICR */ | ||
100 | #define BIT_DMA_EP_RX_ICR_RX_DONE BIT(0) | ||
101 | #define RGF_DMA_EP_MISC_ICR (0x881bec) /* struct RGF_ICR */ | ||
102 | #define BIT_DMA_EP_MISC_ICR_RX_HTRSH BIT(0) | ||
103 | #define BIT_DMA_EP_MISC_ICR_TX_NO_ACT BIT(1) | ||
104 | #define BIT_DMA_EP_MISC_ICR_FW_INT0 BIT(28) | ||
105 | #define BIT_DMA_EP_MISC_ICR_FW_INT1 BIT(29) | ||
106 | |||
107 | /* Interrupt moderation control */ | ||
108 | #define RGF_DMA_ITR_CNT_TRSH (0x881c5c) | ||
109 | #define RGF_DMA_ITR_CNT_DATA (0x881c60) | ||
110 | #define RGF_DMA_ITR_CNT_CRL (0x881C64) | ||
111 | #define BIT_DMA_ITR_CNT_CRL_EN BIT(0) | ||
112 | #define BIT_DMA_ITR_CNT_CRL_EXT_TICK BIT(1) | ||
113 | #define BIT_DMA_ITR_CNT_CRL_FOREVER BIT(2) | ||
114 | #define BIT_DMA_ITR_CNT_CRL_CLR BIT(3) | ||
115 | #define BIT_DMA_ITR_CNT_CRL_REACH_TRSH BIT(4) | ||
116 | |||
117 | /* popular locations */ | ||
118 | #define HOST_MBOX HOSTADDR(RGF_USER_USER_SCRATCH_PAD) | ||
119 | #define HOST_SW_INT (HOSTADDR(RGF_USER_USER_ICR) + \ | ||
120 | offsetof(struct RGF_ICR, ICS)) | ||
121 | #define SW_INT_MBOX BIT_USER_USER_ICR_SW_INT_2 | ||
122 | |||
123 | /* ISR register bits */ | ||
124 | #define ISR_MISC_FW_READY BIT_DMA_EP_MISC_ICR_FW_INT0 | ||
125 | #define ISR_MISC_MBOX_EVT BIT_DMA_EP_MISC_ICR_FW_INT1 | ||
126 | |||
127 | /* Hardware definitions end */ | ||
128 | |||
129 | struct wil6210_mbox_ring { | ||
130 | u32 base; | ||
131 | u16 entry_size; /* max. size of mbox entry, incl. all headers */ | ||
132 | u16 size; | ||
133 | u32 tail; | ||
134 | u32 head; | ||
135 | } __packed; | ||
136 | |||
137 | struct wil6210_mbox_ring_desc { | ||
138 | __le32 sync; | ||
139 | __le32 addr; | ||
140 | } __packed; | ||
141 | |||
142 | /* at HOST_OFF_WIL6210_MBOX_CTL */ | ||
143 | struct wil6210_mbox_ctl { | ||
144 | struct wil6210_mbox_ring tx; | ||
145 | struct wil6210_mbox_ring rx; | ||
146 | } __packed; | ||
147 | |||
148 | struct wil6210_mbox_hdr { | ||
149 | __le16 seq; | ||
150 | __le16 len; /* payload, bytes after this header */ | ||
151 | __le16 type; | ||
152 | u8 flags; | ||
153 | u8 reserved; | ||
154 | } __packed; | ||
155 | |||
156 | #define WIL_MBOX_HDR_TYPE_WMI (0) | ||
157 | |||
158 | /* max. value for wil6210_mbox_hdr.len */ | ||
159 | #define MAX_MBOXITEM_SIZE (240) | ||
160 | |||
161 | struct wil6210_mbox_hdr_wmi { | ||
162 | u8 reserved0[2]; | ||
163 | __le16 id; | ||
164 | __le16 info1; /* bits [0..3] - device_id, rest - unused */ | ||
165 | u8 reserved1[2]; | ||
166 | } __packed; | ||
167 | |||
168 | struct pending_wmi_event { | ||
169 | struct list_head list; | ||
170 | struct { | ||
171 | struct wil6210_mbox_hdr hdr; | ||
172 | struct wil6210_mbox_hdr_wmi wmi; | ||
173 | u8 data[0]; | ||
174 | } __packed event; | ||
175 | }; | ||
176 | |||
177 | union vring_desc; | ||
178 | |||
179 | struct vring { | ||
180 | dma_addr_t pa; | ||
181 | volatile union vring_desc *va; /* vring_desc[size], WriteBack by DMA */ | ||
182 | u16 size; /* number of vring_desc elements */ | ||
183 | u32 swtail; | ||
184 | u32 swhead; | ||
185 | u32 hwtail; /* write here to inform hw */ | ||
186 | void **ctx; /* void *ctx[size] - software context */ | ||
187 | }; | ||
188 | |||
189 | enum { /* for wil6210_priv.status */ | ||
190 | wil_status_fwready = 0, | ||
191 | wil_status_fwconnected, | ||
192 | wil_status_dontscan, | ||
193 | wil_status_irqen, /* FIXME: interrupts enabled - for debug */ | ||
194 | }; | ||
195 | |||
196 | struct pci_dev; | ||
197 | |||
198 | struct wil6210_stats { | ||
199 | u64 tsf; | ||
200 | u32 snr; | ||
201 | u16 last_mcs_rx; | ||
202 | u16 bf_mcs; /* last BF, used for Tx */ | ||
203 | u16 my_rx_sector; | ||
204 | u16 my_tx_sector; | ||
205 | u16 peer_rx_sector; | ||
206 | u16 peer_tx_sector; | ||
207 | }; | ||
208 | |||
209 | struct wil6210_priv { | ||
210 | struct pci_dev *pdev; | ||
211 | int n_msi; | ||
212 | struct wireless_dev *wdev; | ||
213 | void __iomem *csr; | ||
214 | ulong status; | ||
215 | /* profile */ | ||
216 | u32 monitor_flags; | ||
217 | u32 secure_pcp; /* create secure PCP? */ | ||
218 | int sinfo_gen; | ||
219 | /* cached ISR registers */ | ||
220 | u32 isr_misc; | ||
221 | /* mailbox related */ | ||
222 | struct mutex wmi_mutex; | ||
223 | struct wil6210_mbox_ctl mbox_ctl; | ||
224 | struct completion wmi_ready; | ||
225 | u16 wmi_seq; | ||
226 | u16 reply_id; /**< wait for this WMI event */ | ||
227 | void *reply_buf; | ||
228 | u16 reply_size; | ||
229 | struct workqueue_struct *wmi_wq; /* for deferred calls */ | ||
230 | struct work_struct wmi_event_worker; | ||
231 | struct workqueue_struct *wmi_wq_conn; /* for connect worker */ | ||
232 | struct work_struct wmi_connect_worker; | ||
233 | struct work_struct disconnect_worker; | ||
234 | struct timer_list connect_timer; | ||
235 | int pending_connect_cid; | ||
236 | struct list_head pending_wmi_ev; | ||
237 | /* | ||
238 | * protect pending_wmi_ev | ||
239 | * - fill in IRQ from wil6210_irq_misc, | ||
240 | * - consumed in thread by wmi_event_worker | ||
241 | */ | ||
242 | spinlock_t wmi_ev_lock; | ||
243 | /* DMA related */ | ||
244 | struct vring vring_rx; | ||
245 | struct vring vring_tx[WIL6210_MAX_TX_RINGS]; | ||
246 | u8 dst_addr[WIL6210_MAX_TX_RINGS][ETH_ALEN]; | ||
247 | /* scan */ | ||
248 | struct cfg80211_scan_request *scan_request; | ||
249 | |||
250 | struct mutex mutex; /* for wil6210_priv access in wil_{up|down} */ | ||
251 | /* statistics */ | ||
252 | struct wil6210_stats stats; | ||
253 | /* debugfs */ | ||
254 | struct dentry *debug; | ||
255 | struct debugfs_blob_wrapper fw_code_blob; | ||
256 | struct debugfs_blob_wrapper fw_data_blob; | ||
257 | struct debugfs_blob_wrapper fw_peri_blob; | ||
258 | struct debugfs_blob_wrapper uc_code_blob; | ||
259 | struct debugfs_blob_wrapper uc_data_blob; | ||
260 | struct debugfs_blob_wrapper rgf_blob; | ||
261 | }; | ||
262 | |||
263 | #define wil_to_wiphy(i) (i->wdev->wiphy) | ||
264 | #define wil_to_dev(i) (wiphy_dev(wil_to_wiphy(i))) | ||
265 | #define wiphy_to_wil(w) (struct wil6210_priv *)(wiphy_priv(w)) | ||
266 | #define wil_to_wdev(i) (i->wdev) | ||
267 | #define wdev_to_wil(w) (struct wil6210_priv *)(wdev_priv(w)) | ||
268 | #define wil_to_ndev(i) (wil_to_wdev(i)->netdev) | ||
269 | #define ndev_to_wil(n) (wdev_to_wil(n->ieee80211_ptr)) | ||
270 | |||
271 | #define wil_dbg(wil, fmt, arg...) netdev_dbg(wil_to_ndev(wil), fmt, ##arg) | ||
272 | #define wil_info(wil, fmt, arg...) netdev_info(wil_to_ndev(wil), fmt, ##arg) | ||
273 | #define wil_err(wil, fmt, arg...) netdev_err(wil_to_ndev(wil), fmt, ##arg) | ||
274 | |||
275 | #define wil_dbg_IRQ(wil, fmt, arg...) wil_dbg(wil, "DBG[ IRQ]" fmt, ##arg) | ||
276 | #define wil_dbg_TXRX(wil, fmt, arg...) wil_dbg(wil, "DBG[TXRX]" fmt, ##arg) | ||
277 | #define wil_dbg_WMI(wil, fmt, arg...) wil_dbg(wil, "DBG[ WMI]" fmt, ##arg) | ||
278 | |||
279 | #define wil_hex_dump_TXRX(prefix_str, prefix_type, rowsize, \ | ||
280 | groupsize, buf, len, ascii) \ | ||
281 | wil_print_hex_dump_debug("DBG[TXRX]" prefix_str,\ | ||
282 | prefix_type, rowsize, \ | ||
283 | groupsize, buf, len, ascii) | ||
284 | |||
285 | #define wil_hex_dump_WMI(prefix_str, prefix_type, rowsize, \ | ||
286 | groupsize, buf, len, ascii) \ | ||
287 | wil_print_hex_dump_debug("DBG[ WMI]" prefix_str,\ | ||
288 | prefix_type, rowsize, \ | ||
289 | groupsize, buf, len, ascii) | ||
290 | |||
291 | void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src, | ||
292 | size_t count); | ||
293 | void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src, | ||
294 | size_t count); | ||
295 | |||
296 | void *wil_if_alloc(struct device *dev, void __iomem *csr); | ||
297 | void wil_if_free(struct wil6210_priv *wil); | ||
298 | int wil_if_add(struct wil6210_priv *wil); | ||
299 | void wil_if_remove(struct wil6210_priv *wil); | ||
300 | int wil_priv_init(struct wil6210_priv *wil); | ||
301 | void wil_priv_deinit(struct wil6210_priv *wil); | ||
302 | int wil_reset(struct wil6210_priv *wil); | ||
303 | void wil_link_on(struct wil6210_priv *wil); | ||
304 | void wil_link_off(struct wil6210_priv *wil); | ||
305 | int wil_up(struct wil6210_priv *wil); | ||
306 | int wil_down(struct wil6210_priv *wil); | ||
307 | void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r); | ||
308 | |||
309 | void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr); | ||
310 | void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr); | ||
311 | int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr, | ||
312 | struct wil6210_mbox_hdr *hdr); | ||
313 | int wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len); | ||
314 | void wmi_recv_cmd(struct wil6210_priv *wil); | ||
315 | int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len, | ||
316 | u16 reply_id, void *reply, u8 reply_size, int to_msec); | ||
317 | void wmi_connect_worker(struct work_struct *work); | ||
318 | void wmi_event_worker(struct work_struct *work); | ||
319 | void wmi_event_flush(struct wil6210_priv *wil); | ||
320 | int wmi_set_ssid(struct wil6210_priv *wil, u8 ssid_len, const void *ssid); | ||
321 | int wmi_get_ssid(struct wil6210_priv *wil, u8 *ssid_len, void *ssid); | ||
322 | int wmi_set_channel(struct wil6210_priv *wil, int channel); | ||
323 | int wmi_get_channel(struct wil6210_priv *wil, int *channel); | ||
324 | int wmi_tx_eapol(struct wil6210_priv *wil, struct sk_buff *skb); | ||
325 | int wmi_del_cipher_key(struct wil6210_priv *wil, u8 key_index, | ||
326 | const void *mac_addr); | ||
327 | int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index, | ||
328 | const void *mac_addr, int key_len, const void *key); | ||
329 | int wmi_echo(struct wil6210_priv *wil); | ||
330 | int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie); | ||
331 | |||
332 | int wil6210_init_irq(struct wil6210_priv *wil, int irq); | ||
333 | void wil6210_fini_irq(struct wil6210_priv *wil, int irq); | ||
334 | void wil6210_disable_irq(struct wil6210_priv *wil); | ||
335 | void wil6210_enable_irq(struct wil6210_priv *wil); | ||
336 | |||
337 | int wil6210_debugfs_init(struct wil6210_priv *wil); | ||
338 | void wil6210_debugfs_remove(struct wil6210_priv *wil); | ||
339 | |||
340 | struct wireless_dev *wil_cfg80211_init(struct device *dev); | ||
341 | void wil_wdev_free(struct wil6210_priv *wil); | ||
342 | |||
343 | int wmi_set_mac_address(struct wil6210_priv *wil, void *addr); | ||
344 | int wmi_set_bcon(struct wil6210_priv *wil, int bi, u8 wmi_nettype); | ||
345 | void wil6210_disconnect(struct wil6210_priv *wil, void *bssid); | ||
346 | |||
347 | int wil_rx_init(struct wil6210_priv *wil); | ||
348 | void wil_rx_fini(struct wil6210_priv *wil); | ||
349 | |||
350 | /* TX API */ | ||
351 | int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, | ||
352 | int cid, int tid); | ||
353 | void wil_vring_fini_tx(struct wil6210_priv *wil, int id); | ||
354 | |||
355 | netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev); | ||
356 | void wil_tx_complete(struct wil6210_priv *wil, int ringid); | ||
357 | |||
358 | /* RX API */ | ||
359 | void wil_rx_handle(struct wil6210_priv *wil); | ||
360 | |||
361 | int wil_iftype_nl2wmi(enum nl80211_iftype type); | ||
362 | |||
363 | #endif /* __WIL6210_H__ */ | ||
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c new file mode 100644 index 000000000000..12915f6e7617 --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/wmi.c | |||
@@ -0,0 +1,975 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012 Qualcomm Atheros, Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include <linux/pci.h> | ||
18 | #include <linux/io.h> | ||
19 | #include <linux/list.h> | ||
20 | #include <linux/etherdevice.h> | ||
21 | |||
22 | #include "wil6210.h" | ||
23 | #include "wmi.h" | ||
24 | |||
25 | /** | ||
26 | * WMI event receiving - theory of operations | ||
27 | * | ||
28 | * When firmware about to report WMI event, it fills memory area | ||
29 | * in the mailbox and raises misc. IRQ. Thread interrupt handler invoked for | ||
30 | * the misc IRQ, function @wmi_recv_cmd called by thread IRQ handler. | ||
31 | * | ||
32 | * @wmi_recv_cmd reads event, allocates memory chunk and attaches it to the | ||
33 | * event list @wil->pending_wmi_ev. Then, work queue @wil->wmi_wq wakes up | ||
34 | * and handles events within the @wmi_event_worker. Every event get detached | ||
35 | * from list, processed and deleted. | ||
36 | * | ||
37 | * Purpose for this mechanism is to release IRQ thread; otherwise, | ||
38 | * if WMI event handling involves another WMI command flow, this 2-nd flow | ||
39 | * won't be completed because of blocked IRQ thread. | ||
40 | */ | ||
41 | |||
42 | /** | ||
43 | * Addressing - theory of operations | ||
44 | * | ||
45 | * There are several buses present on the WIL6210 card. | ||
46 | * Same memory areas are visible at different address on | ||
47 | * the different busses. There are 3 main bus masters: | ||
48 | * - MAC CPU (ucode) | ||
49 | * - User CPU (firmware) | ||
50 | * - AHB (host) | ||
51 | * | ||
52 | * On the PCI bus, there is one BAR (BAR0) of 2Mb size, exposing | ||
53 | * AHB addresses starting from 0x880000 | ||
54 | * | ||
55 | * Internally, firmware uses addresses that allows faster access but | ||
56 | * are invisible from the host. To read from these addresses, alternative | ||
57 | * AHB address must be used. | ||
58 | * | ||
59 | * Memory mapping | ||
60 | * Linker address PCI/Host address | ||
61 | * 0x880000 .. 0xa80000 2Mb BAR0 | ||
62 | * 0x800000 .. 0x807000 0x900000 .. 0x907000 28k DCCM | ||
63 | * 0x840000 .. 0x857000 0x908000 .. 0x91f000 92k PERIPH | ||
64 | */ | ||
65 | |||
66 | /** | ||
67 | * @fw_mapping provides memory remapping table | ||
68 | */ | ||
69 | static const struct { | ||
70 | u32 from; /* linker address - from, inclusive */ | ||
71 | u32 to; /* linker address - to, exclusive */ | ||
72 | u32 host; /* PCI/Host address - BAR0 + 0x880000 */ | ||
73 | } fw_mapping[] = { | ||
74 | {0x000000, 0x040000, 0x8c0000}, /* FW code RAM 256k */ | ||
75 | {0x800000, 0x808000, 0x900000}, /* FW data RAM 32k */ | ||
76 | {0x840000, 0x860000, 0x908000}, /* peripheral data RAM 128k/96k used */ | ||
77 | {0x880000, 0x88a000, 0x880000}, /* various RGF */ | ||
78 | {0x8c0000, 0x932000, 0x8c0000}, /* trivial mapping for upper area */ | ||
79 | /* | ||
80 | * 920000..930000 ucode code RAM | ||
81 | * 930000..932000 ucode data RAM | ||
82 | */ | ||
83 | }; | ||
84 | |||
85 | /** | ||
86 | * return AHB address for given firmware/ucode internal (linker) address | ||
87 | * @x - internal address | ||
88 | * If address have no valid AHB mapping, return 0 | ||
89 | */ | ||
90 | static u32 wmi_addr_remap(u32 x) | ||
91 | { | ||
92 | uint i; | ||
93 | |||
94 | for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) { | ||
95 | if ((x >= fw_mapping[i].from) && (x < fw_mapping[i].to)) | ||
96 | return x + fw_mapping[i].host - fw_mapping[i].from; | ||
97 | } | ||
98 | |||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | /** | ||
103 | * Check address validity for WMI buffer; remap if needed | ||
104 | * @ptr - internal (linker) fw/ucode address | ||
105 | * | ||
106 | * Valid buffer should be DWORD aligned | ||
107 | * | ||
108 | * return address for accessing buffer from the host; | ||
109 | * if buffer is not valid, return NULL. | ||
110 | */ | ||
111 | void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr_) | ||
112 | { | ||
113 | u32 off; | ||
114 | u32 ptr = le32_to_cpu(ptr_); | ||
115 | |||
116 | if (ptr % 4) | ||
117 | return NULL; | ||
118 | |||
119 | ptr = wmi_addr_remap(ptr); | ||
120 | if (ptr < WIL6210_FW_HOST_OFF) | ||
121 | return NULL; | ||
122 | |||
123 | off = HOSTADDR(ptr); | ||
124 | if (off > WIL6210_MEM_SIZE - 4) | ||
125 | return NULL; | ||
126 | |||
127 | return wil->csr + off; | ||
128 | } | ||
129 | |||
130 | /** | ||
131 | * Check address validity | ||
132 | */ | ||
133 | void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr) | ||
134 | { | ||
135 | u32 off; | ||
136 | |||
137 | if (ptr % 4) | ||
138 | return NULL; | ||
139 | |||
140 | if (ptr < WIL6210_FW_HOST_OFF) | ||
141 | return NULL; | ||
142 | |||
143 | off = HOSTADDR(ptr); | ||
144 | if (off > WIL6210_MEM_SIZE - 4) | ||
145 | return NULL; | ||
146 | |||
147 | return wil->csr + off; | ||
148 | } | ||
149 | |||
150 | int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr, | ||
151 | struct wil6210_mbox_hdr *hdr) | ||
152 | { | ||
153 | void __iomem *src = wmi_buffer(wil, ptr); | ||
154 | if (!src) | ||
155 | return -EINVAL; | ||
156 | |||
157 | wil_memcpy_fromio_32(hdr, src, sizeof(*hdr)); | ||
158 | |||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) | ||
163 | { | ||
164 | struct { | ||
165 | struct wil6210_mbox_hdr hdr; | ||
166 | struct wil6210_mbox_hdr_wmi wmi; | ||
167 | } __packed cmd = { | ||
168 | .hdr = { | ||
169 | .type = WIL_MBOX_HDR_TYPE_WMI, | ||
170 | .flags = 0, | ||
171 | .len = cpu_to_le16(sizeof(cmd.wmi) + len), | ||
172 | }, | ||
173 | .wmi = { | ||
174 | .id = cpu_to_le16(cmdid), | ||
175 | .info1 = 0, | ||
176 | }, | ||
177 | }; | ||
178 | struct wil6210_mbox_ring *r = &wil->mbox_ctl.tx; | ||
179 | struct wil6210_mbox_ring_desc d_head; | ||
180 | u32 next_head; | ||
181 | void __iomem *dst; | ||
182 | void __iomem *head = wmi_addr(wil, r->head); | ||
183 | uint retry; | ||
184 | |||
185 | if (sizeof(cmd) + len > r->entry_size) { | ||
186 | wil_err(wil, "WMI size too large: %d bytes, max is %d\n", | ||
187 | (int)(sizeof(cmd) + len), r->entry_size); | ||
188 | return -ERANGE; | ||
189 | |||
190 | } | ||
191 | |||
192 | might_sleep(); | ||
193 | |||
194 | if (!test_bit(wil_status_fwready, &wil->status)) { | ||
195 | wil_err(wil, "FW not ready\n"); | ||
196 | return -EAGAIN; | ||
197 | } | ||
198 | |||
199 | if (!head) { | ||
200 | wil_err(wil, "WMI head is garbage: 0x%08x\n", r->head); | ||
201 | return -EINVAL; | ||
202 | } | ||
203 | /* read Tx head till it is not busy */ | ||
204 | for (retry = 5; retry > 0; retry--) { | ||
205 | wil_memcpy_fromio_32(&d_head, head, sizeof(d_head)); | ||
206 | if (d_head.sync == 0) | ||
207 | break; | ||
208 | msleep(20); | ||
209 | } | ||
210 | if (d_head.sync != 0) { | ||
211 | wil_err(wil, "WMI head busy\n"); | ||
212 | return -EBUSY; | ||
213 | } | ||
214 | /* next head */ | ||
215 | next_head = r->base + ((r->head - r->base + sizeof(d_head)) % r->size); | ||
216 | wil_dbg_WMI(wil, "Head 0x%08x -> 0x%08x\n", r->head, next_head); | ||
217 | /* wait till FW finish with previous command */ | ||
218 | for (retry = 5; retry > 0; retry--) { | ||
219 | r->tail = ioread32(wil->csr + HOST_MBOX + | ||
220 | offsetof(struct wil6210_mbox_ctl, tx.tail)); | ||
221 | if (next_head != r->tail) | ||
222 | break; | ||
223 | msleep(20); | ||
224 | } | ||
225 | if (next_head == r->tail) { | ||
226 | wil_err(wil, "WMI ring full\n"); | ||
227 | return -EBUSY; | ||
228 | } | ||
229 | dst = wmi_buffer(wil, d_head.addr); | ||
230 | if (!dst) { | ||
231 | wil_err(wil, "invalid WMI buffer: 0x%08x\n", | ||
232 | le32_to_cpu(d_head.addr)); | ||
233 | return -EINVAL; | ||
234 | } | ||
235 | cmd.hdr.seq = cpu_to_le16(++wil->wmi_seq); | ||
236 | /* set command */ | ||
237 | wil_dbg_WMI(wil, "WMI command 0x%04x [%d]\n", cmdid, len); | ||
238 | wil_hex_dump_WMI("Cmd ", DUMP_PREFIX_OFFSET, 16, 1, &cmd, | ||
239 | sizeof(cmd), true); | ||
240 | wil_hex_dump_WMI("cmd ", DUMP_PREFIX_OFFSET, 16, 1, buf, | ||
241 | len, true); | ||
242 | wil_memcpy_toio_32(dst, &cmd, sizeof(cmd)); | ||
243 | wil_memcpy_toio_32(dst + sizeof(cmd), buf, len); | ||
244 | /* mark entry as full */ | ||
245 | iowrite32(1, wil->csr + HOSTADDR(r->head) + | ||
246 | offsetof(struct wil6210_mbox_ring_desc, sync)); | ||
247 | /* advance next ptr */ | ||
248 | iowrite32(r->head = next_head, wil->csr + HOST_MBOX + | ||
249 | offsetof(struct wil6210_mbox_ctl, tx.head)); | ||
250 | |||
251 | /* interrupt to FW */ | ||
252 | iowrite32(SW_INT_MBOX, wil->csr + HOST_SW_INT); | ||
253 | |||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | int wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) | ||
258 | { | ||
259 | int rc; | ||
260 | |||
261 | mutex_lock(&wil->wmi_mutex); | ||
262 | rc = __wmi_send(wil, cmdid, buf, len); | ||
263 | mutex_unlock(&wil->wmi_mutex); | ||
264 | |||
265 | return rc; | ||
266 | } | ||
267 | |||
268 | /*=== Event handlers ===*/ | ||
269 | static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len) | ||
270 | { | ||
271 | struct net_device *ndev = wil_to_ndev(wil); | ||
272 | struct wireless_dev *wdev = wil->wdev; | ||
273 | struct wmi_ready_event *evt = d; | ||
274 | u32 ver = le32_to_cpu(evt->sw_version); | ||
275 | |||
276 | wil_dbg_WMI(wil, "FW ver. %d; MAC %pM\n", ver, evt->mac); | ||
277 | |||
278 | if (!is_valid_ether_addr(ndev->dev_addr)) { | ||
279 | memcpy(ndev->dev_addr, evt->mac, ETH_ALEN); | ||
280 | memcpy(ndev->perm_addr, evt->mac, ETH_ALEN); | ||
281 | } | ||
282 | snprintf(wdev->wiphy->fw_version, sizeof(wdev->wiphy->fw_version), | ||
283 | "%d", ver); | ||
284 | } | ||
285 | |||
286 | static void wmi_evt_fw_ready(struct wil6210_priv *wil, int id, void *d, | ||
287 | int len) | ||
288 | { | ||
289 | wil_dbg_WMI(wil, "WMI: FW ready\n"); | ||
290 | |||
291 | set_bit(wil_status_fwready, &wil->status); | ||
292 | /* reuse wmi_ready for the firmware ready indication */ | ||
293 | complete(&wil->wmi_ready); | ||
294 | } | ||
295 | |||
296 | static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len) | ||
297 | { | ||
298 | struct wmi_rx_mgmt_packet_event *data = d; | ||
299 | struct wiphy *wiphy = wil_to_wiphy(wil); | ||
300 | struct ieee80211_mgmt *rx_mgmt_frame = | ||
301 | (struct ieee80211_mgmt *)data->payload; | ||
302 | int ch_no = data->info.channel+1; | ||
303 | u32 freq = ieee80211_channel_to_frequency(ch_no, | ||
304 | IEEE80211_BAND_60GHZ); | ||
305 | struct ieee80211_channel *channel = ieee80211_get_channel(wiphy, freq); | ||
306 | /* TODO convert LE to CPU */ | ||
307 | s32 signal = 0; /* TODO */ | ||
308 | __le16 fc = rx_mgmt_frame->frame_control; | ||
309 | u32 d_len = le32_to_cpu(data->info.len); | ||
310 | u16 d_status = le16_to_cpu(data->info.status); | ||
311 | |||
312 | wil_dbg_WMI(wil, "MGMT: channel %d MCS %d SNR %d\n", | ||
313 | data->info.channel, data->info.mcs, data->info.snr); | ||
314 | wil_dbg_WMI(wil, "status 0x%04x len %d stype %04x\n", d_status, d_len, | ||
315 | le16_to_cpu(data->info.stype)); | ||
316 | wil_dbg_WMI(wil, "qid %d mid %d cid %d\n", | ||
317 | data->info.qid, data->info.mid, data->info.cid); | ||
318 | |||
319 | if (!channel) { | ||
320 | wil_err(wil, "Frame on unsupported channel\n"); | ||
321 | return; | ||
322 | } | ||
323 | |||
324 | if (ieee80211_is_beacon(fc) || ieee80211_is_probe_resp(fc)) { | ||
325 | struct cfg80211_bss *bss; | ||
326 | u64 tsf = le64_to_cpu(rx_mgmt_frame->u.beacon.timestamp); | ||
327 | u16 cap = le16_to_cpu(rx_mgmt_frame->u.beacon.capab_info); | ||
328 | u16 bi = le16_to_cpu(rx_mgmt_frame->u.beacon.beacon_int); | ||
329 | const u8 *ie_buf = rx_mgmt_frame->u.beacon.variable; | ||
330 | size_t ie_len = d_len - offsetof(struct ieee80211_mgmt, | ||
331 | u.beacon.variable); | ||
332 | wil_dbg_WMI(wil, "Capability info : 0x%04x\n", cap); | ||
333 | |||
334 | bss = cfg80211_inform_bss(wiphy, channel, rx_mgmt_frame->bssid, | ||
335 | tsf, cap, bi, ie_buf, ie_len, | ||
336 | signal, GFP_KERNEL); | ||
337 | if (bss) { | ||
338 | wil_dbg_WMI(wil, "Added BSS %pM\n", | ||
339 | rx_mgmt_frame->bssid); | ||
340 | cfg80211_put_bss(bss); | ||
341 | } else { | ||
342 | wil_err(wil, "cfg80211_inform_bss() failed\n"); | ||
343 | } | ||
344 | } | ||
345 | } | ||
346 | |||
347 | static void wmi_evt_scan_complete(struct wil6210_priv *wil, int id, | ||
348 | void *d, int len) | ||
349 | { | ||
350 | if (wil->scan_request) { | ||
351 | struct wmi_scan_complete_event *data = d; | ||
352 | bool aborted = (data->status != 0); | ||
353 | |||
354 | wil_dbg_WMI(wil, "SCAN_COMPLETE(0x%08x)\n", data->status); | ||
355 | cfg80211_scan_done(wil->scan_request, aborted); | ||
356 | wil->scan_request = NULL; | ||
357 | } else { | ||
358 | wil_err(wil, "SCAN_COMPLETE while not scanning\n"); | ||
359 | } | ||
360 | } | ||
361 | |||
362 | static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) | ||
363 | { | ||
364 | struct net_device *ndev = wil_to_ndev(wil); | ||
365 | struct wireless_dev *wdev = wil->wdev; | ||
366 | struct wmi_connect_event *evt = d; | ||
367 | int ch; /* channel number */ | ||
368 | struct station_info sinfo; | ||
369 | u8 *assoc_req_ie, *assoc_resp_ie; | ||
370 | size_t assoc_req_ielen, assoc_resp_ielen; | ||
371 | /* capinfo(u16) + listen_interval(u16) + IEs */ | ||
372 | const size_t assoc_req_ie_offset = sizeof(u16) * 2; | ||
373 | /* capinfo(u16) + status_code(u16) + associd(u16) + IEs */ | ||
374 | const size_t assoc_resp_ie_offset = sizeof(u16) * 3; | ||
375 | |||
376 | if (len < sizeof(*evt)) { | ||
377 | wil_err(wil, "Connect event too short : %d bytes\n", len); | ||
378 | return; | ||
379 | } | ||
380 | if (len != sizeof(*evt) + evt->beacon_ie_len + evt->assoc_req_len + | ||
381 | evt->assoc_resp_len) { | ||
382 | wil_err(wil, | ||
383 | "Connect event corrupted : %d != %d + %d + %d + %d\n", | ||
384 | len, (int)sizeof(*evt), evt->beacon_ie_len, | ||
385 | evt->assoc_req_len, evt->assoc_resp_len); | ||
386 | return; | ||
387 | } | ||
388 | ch = evt->channel + 1; | ||
389 | wil_dbg_WMI(wil, "Connect %pM channel [%d] cid %d\n", | ||
390 | evt->bssid, ch, evt->cid); | ||
391 | wil_hex_dump_WMI("connect AI : ", DUMP_PREFIX_OFFSET, 16, 1, | ||
392 | evt->assoc_info, len - sizeof(*evt), true); | ||
393 | |||
394 | /* figure out IE's */ | ||
395 | assoc_req_ie = &evt->assoc_info[evt->beacon_ie_len + | ||
396 | assoc_req_ie_offset]; | ||
397 | assoc_req_ielen = evt->assoc_req_len - assoc_req_ie_offset; | ||
398 | if (evt->assoc_req_len <= assoc_req_ie_offset) { | ||
399 | assoc_req_ie = NULL; | ||
400 | assoc_req_ielen = 0; | ||
401 | } | ||
402 | |||
403 | assoc_resp_ie = &evt->assoc_info[evt->beacon_ie_len + | ||
404 | evt->assoc_req_len + | ||
405 | assoc_resp_ie_offset]; | ||
406 | assoc_resp_ielen = evt->assoc_resp_len - assoc_resp_ie_offset; | ||
407 | if (evt->assoc_resp_len <= assoc_resp_ie_offset) { | ||
408 | assoc_resp_ie = NULL; | ||
409 | assoc_resp_ielen = 0; | ||
410 | } | ||
411 | |||
412 | if ((wdev->iftype == NL80211_IFTYPE_STATION) || | ||
413 | (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) { | ||
414 | if (wdev->sme_state != CFG80211_SME_CONNECTING) { | ||
415 | wil_err(wil, "Not in connecting state\n"); | ||
416 | return; | ||
417 | } | ||
418 | del_timer_sync(&wil->connect_timer); | ||
419 | cfg80211_connect_result(ndev, evt->bssid, | ||
420 | assoc_req_ie, assoc_req_ielen, | ||
421 | assoc_resp_ie, assoc_resp_ielen, | ||
422 | WLAN_STATUS_SUCCESS, GFP_KERNEL); | ||
423 | |||
424 | } else if ((wdev->iftype == NL80211_IFTYPE_AP) || | ||
425 | (wdev->iftype == NL80211_IFTYPE_P2P_GO)) { | ||
426 | memset(&sinfo, 0, sizeof(sinfo)); | ||
427 | |||
428 | sinfo.generation = wil->sinfo_gen++; | ||
429 | |||
430 | if (assoc_req_ie) { | ||
431 | sinfo.assoc_req_ies = assoc_req_ie; | ||
432 | sinfo.assoc_req_ies_len = assoc_req_ielen; | ||
433 | sinfo.filled |= STATION_INFO_ASSOC_REQ_IES; | ||
434 | } | ||
435 | |||
436 | cfg80211_new_sta(ndev, evt->bssid, &sinfo, GFP_KERNEL); | ||
437 | } | ||
438 | set_bit(wil_status_fwconnected, &wil->status); | ||
439 | |||
440 | /* FIXME FW can transmit only ucast frames to peer */ | ||
441 | /* FIXME real ring_id instead of hard coded 0 */ | ||
442 | memcpy(wil->dst_addr[0], evt->bssid, ETH_ALEN); | ||
443 | |||
444 | wil->pending_connect_cid = evt->cid; | ||
445 | queue_work(wil->wmi_wq_conn, &wil->wmi_connect_worker); | ||
446 | } | ||
447 | |||
448 | static void wmi_evt_disconnect(struct wil6210_priv *wil, int id, | ||
449 | void *d, int len) | ||
450 | { | ||
451 | struct wmi_disconnect_event *evt = d; | ||
452 | |||
453 | wil_dbg_WMI(wil, "Disconnect %pM reason %d proto %d wmi\n", | ||
454 | evt->bssid, | ||
455 | evt->protocol_reason_status, evt->disconnect_reason); | ||
456 | |||
457 | wil->sinfo_gen++; | ||
458 | |||
459 | wil6210_disconnect(wil, evt->bssid); | ||
460 | clear_bit(wil_status_dontscan, &wil->status); | ||
461 | } | ||
462 | |||
463 | static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len) | ||
464 | { | ||
465 | struct wmi_notify_req_done_event *evt = d; | ||
466 | |||
467 | if (len < sizeof(*evt)) { | ||
468 | wil_err(wil, "Short NOTIFY event\n"); | ||
469 | return; | ||
470 | } | ||
471 | |||
472 | wil->stats.tsf = le64_to_cpu(evt->tsf); | ||
473 | wil->stats.snr = le32_to_cpu(evt->snr_val); | ||
474 | wil->stats.bf_mcs = le16_to_cpu(evt->bf_mcs); | ||
475 | wil->stats.my_rx_sector = le16_to_cpu(evt->my_rx_sector); | ||
476 | wil->stats.my_tx_sector = le16_to_cpu(evt->my_tx_sector); | ||
477 | wil->stats.peer_rx_sector = le16_to_cpu(evt->other_rx_sector); | ||
478 | wil->stats.peer_tx_sector = le16_to_cpu(evt->other_tx_sector); | ||
479 | wil_dbg_WMI(wil, "Link status, MCS %d TSF 0x%016llx\n" | ||
480 | "BF status 0x%08x SNR 0x%08x\n" | ||
481 | "Tx Tpt %d goodput %d Rx goodput %d\n" | ||
482 | "Sectors(rx:tx) my %d:%d peer %d:%d\n", | ||
483 | wil->stats.bf_mcs, wil->stats.tsf, evt->status, | ||
484 | wil->stats.snr, le32_to_cpu(evt->tx_tpt), | ||
485 | le32_to_cpu(evt->tx_goodput), le32_to_cpu(evt->rx_goodput), | ||
486 | wil->stats.my_rx_sector, wil->stats.my_tx_sector, | ||
487 | wil->stats.peer_rx_sector, wil->stats.peer_tx_sector); | ||
488 | } | ||
489 | |||
490 | /* | ||
491 | * Firmware reports EAPOL frame using WME event. | ||
492 | * Reconstruct Ethernet frame and deliver it via normal Rx | ||
493 | */ | ||
494 | static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id, | ||
495 | void *d, int len) | ||
496 | { | ||
497 | struct net_device *ndev = wil_to_ndev(wil); | ||
498 | struct wmi_eapol_rx_event *evt = d; | ||
499 | u16 eapol_len = le16_to_cpu(evt->eapol_len); | ||
500 | int sz = eapol_len + ETH_HLEN; | ||
501 | struct sk_buff *skb; | ||
502 | struct ethhdr *eth; | ||
503 | |||
504 | wil_dbg_WMI(wil, "EAPOL len %d from %pM\n", eapol_len, | ||
505 | evt->src_mac); | ||
506 | |||
507 | if (eapol_len > 196) { /* TODO: revisit size limit */ | ||
508 | wil_err(wil, "EAPOL too large\n"); | ||
509 | return; | ||
510 | } | ||
511 | |||
512 | skb = alloc_skb(sz, GFP_KERNEL); | ||
513 | if (!skb) { | ||
514 | wil_err(wil, "Failed to allocate skb\n"); | ||
515 | return; | ||
516 | } | ||
517 | eth = (struct ethhdr *)skb_put(skb, ETH_HLEN); | ||
518 | memcpy(eth->h_dest, ndev->dev_addr, ETH_ALEN); | ||
519 | memcpy(eth->h_source, evt->src_mac, ETH_ALEN); | ||
520 | eth->h_proto = cpu_to_be16(ETH_P_PAE); | ||
521 | memcpy(skb_put(skb, eapol_len), evt->eapol, eapol_len); | ||
522 | skb->protocol = eth_type_trans(skb, ndev); | ||
523 | if (likely(netif_rx_ni(skb) == NET_RX_SUCCESS)) { | ||
524 | ndev->stats.rx_packets++; | ||
525 | ndev->stats.rx_bytes += skb->len; | ||
526 | } else { | ||
527 | ndev->stats.rx_dropped++; | ||
528 | } | ||
529 | } | ||
530 | |||
531 | static const struct { | ||
532 | int eventid; | ||
533 | void (*handler)(struct wil6210_priv *wil, int eventid, | ||
534 | void *data, int data_len); | ||
535 | } wmi_evt_handlers[] = { | ||
536 | {WMI_READY_EVENTID, wmi_evt_ready}, | ||
537 | {WMI_FW_READY_EVENTID, wmi_evt_fw_ready}, | ||
538 | {WMI_RX_MGMT_PACKET_EVENTID, wmi_evt_rx_mgmt}, | ||
539 | {WMI_SCAN_COMPLETE_EVENTID, wmi_evt_scan_complete}, | ||
540 | {WMI_CONNECT_EVENTID, wmi_evt_connect}, | ||
541 | {WMI_DISCONNECT_EVENTID, wmi_evt_disconnect}, | ||
542 | {WMI_NOTIFY_REQ_DONE_EVENTID, wmi_evt_notify}, | ||
543 | {WMI_EAPOL_RX_EVENTID, wmi_evt_eapol_rx}, | ||
544 | }; | ||
545 | |||
546 | /* | ||
547 | * Run in IRQ context | ||
548 | * Extract WMI command from mailbox. Queue it to the @wil->pending_wmi_ev | ||
549 | * that will be eventually handled by the @wmi_event_worker in the thread | ||
550 | * context of thread "wil6210_wmi" | ||
551 | */ | ||
552 | void wmi_recv_cmd(struct wil6210_priv *wil) | ||
553 | { | ||
554 | struct wil6210_mbox_ring_desc d_tail; | ||
555 | struct wil6210_mbox_hdr hdr; | ||
556 | struct wil6210_mbox_ring *r = &wil->mbox_ctl.rx; | ||
557 | struct pending_wmi_event *evt; | ||
558 | u8 *cmd; | ||
559 | void __iomem *src; | ||
560 | ulong flags; | ||
561 | |||
562 | for (;;) { | ||
563 | u16 len; | ||
564 | |||
565 | r->head = ioread32(wil->csr + HOST_MBOX + | ||
566 | offsetof(struct wil6210_mbox_ctl, rx.head)); | ||
567 | if (r->tail == r->head) | ||
568 | return; | ||
569 | |||
570 | /* read cmd from tail */ | ||
571 | wil_memcpy_fromio_32(&d_tail, wil->csr + HOSTADDR(r->tail), | ||
572 | sizeof(struct wil6210_mbox_ring_desc)); | ||
573 | if (d_tail.sync == 0) { | ||
574 | wil_err(wil, "Mbox evt not owned by FW?\n"); | ||
575 | return; | ||
576 | } | ||
577 | |||
578 | if (0 != wmi_read_hdr(wil, d_tail.addr, &hdr)) { | ||
579 | wil_err(wil, "Mbox evt at 0x%08x?\n", | ||
580 | le32_to_cpu(d_tail.addr)); | ||
581 | return; | ||
582 | } | ||
583 | |||
584 | len = le16_to_cpu(hdr.len); | ||
585 | src = wmi_buffer(wil, d_tail.addr) + | ||
586 | sizeof(struct wil6210_mbox_hdr); | ||
587 | evt = kmalloc(ALIGN(offsetof(struct pending_wmi_event, | ||
588 | event.wmi) + len, 4), | ||
589 | GFP_KERNEL); | ||
590 | if (!evt) { | ||
591 | wil_err(wil, "kmalloc for WMI event (%d) failed\n", | ||
592 | len); | ||
593 | return; | ||
594 | } | ||
595 | evt->event.hdr = hdr; | ||
596 | cmd = (void *)&evt->event.wmi; | ||
597 | wil_memcpy_fromio_32(cmd, src, len); | ||
598 | /* mark entry as empty */ | ||
599 | iowrite32(0, wil->csr + HOSTADDR(r->tail) + | ||
600 | offsetof(struct wil6210_mbox_ring_desc, sync)); | ||
601 | /* indicate */ | ||
602 | wil_dbg_WMI(wil, "Mbox evt %04x %04x %04x %02x\n", | ||
603 | le16_to_cpu(hdr.seq), len, le16_to_cpu(hdr.type), | ||
604 | hdr.flags); | ||
605 | if ((hdr.type == WIL_MBOX_HDR_TYPE_WMI) && | ||
606 | (len >= sizeof(struct wil6210_mbox_hdr_wmi))) { | ||
607 | wil_dbg_WMI(wil, "WMI event 0x%04x\n", | ||
608 | evt->event.wmi.id); | ||
609 | } | ||
610 | wil_hex_dump_WMI("evt ", DUMP_PREFIX_OFFSET, 16, 1, | ||
611 | &evt->event.hdr, sizeof(hdr) + len, true); | ||
612 | |||
613 | /* advance tail */ | ||
614 | r->tail = r->base + ((r->tail - r->base + | ||
615 | sizeof(struct wil6210_mbox_ring_desc)) % r->size); | ||
616 | iowrite32(r->tail, wil->csr + HOST_MBOX + | ||
617 | offsetof(struct wil6210_mbox_ctl, rx.tail)); | ||
618 | |||
619 | /* add to the pending list */ | ||
620 | spin_lock_irqsave(&wil->wmi_ev_lock, flags); | ||
621 | list_add_tail(&evt->list, &wil->pending_wmi_ev); | ||
622 | spin_unlock_irqrestore(&wil->wmi_ev_lock, flags); | ||
623 | { | ||
624 | int q = queue_work(wil->wmi_wq, | ||
625 | &wil->wmi_event_worker); | ||
626 | wil_dbg_WMI(wil, "queue_work -> %d\n", q); | ||
627 | } | ||
628 | } | ||
629 | } | ||
630 | |||
631 | int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len, | ||
632 | u16 reply_id, void *reply, u8 reply_size, int to_msec) | ||
633 | { | ||
634 | int rc; | ||
635 | int remain; | ||
636 | |||
637 | mutex_lock(&wil->wmi_mutex); | ||
638 | |||
639 | rc = __wmi_send(wil, cmdid, buf, len); | ||
640 | if (rc) | ||
641 | goto out; | ||
642 | |||
643 | wil->reply_id = reply_id; | ||
644 | wil->reply_buf = reply; | ||
645 | wil->reply_size = reply_size; | ||
646 | remain = wait_for_completion_timeout(&wil->wmi_ready, | ||
647 | msecs_to_jiffies(to_msec)); | ||
648 | if (0 == remain) { | ||
649 | wil_err(wil, "wmi_call(0x%04x->0x%04x) timeout %d msec\n", | ||
650 | cmdid, reply_id, to_msec); | ||
651 | rc = -ETIME; | ||
652 | } else { | ||
653 | wil_dbg_WMI(wil, | ||
654 | "wmi_call(0x%04x->0x%04x) completed in %d msec\n", | ||
655 | cmdid, reply_id, | ||
656 | to_msec - jiffies_to_msecs(remain)); | ||
657 | } | ||
658 | wil->reply_id = 0; | ||
659 | wil->reply_buf = NULL; | ||
660 | wil->reply_size = 0; | ||
661 | out: | ||
662 | mutex_unlock(&wil->wmi_mutex); | ||
663 | |||
664 | return rc; | ||
665 | } | ||
666 | |||
667 | int wmi_echo(struct wil6210_priv *wil) | ||
668 | { | ||
669 | struct wmi_echo_cmd cmd = { | ||
670 | .value = cpu_to_le32(0x12345678), | ||
671 | }; | ||
672 | |||
673 | return wmi_call(wil, WMI_ECHO_CMDID, &cmd, sizeof(cmd), | ||
674 | WMI_ECHO_RSP_EVENTID, NULL, 0, 20); | ||
675 | } | ||
676 | |||
677 | int wmi_set_mac_address(struct wil6210_priv *wil, void *addr) | ||
678 | { | ||
679 | struct wmi_set_mac_address_cmd cmd; | ||
680 | |||
681 | memcpy(cmd.mac, addr, ETH_ALEN); | ||
682 | |||
683 | wil_dbg_WMI(wil, "Set MAC %pM\n", addr); | ||
684 | |||
685 | return wmi_send(wil, WMI_SET_MAC_ADDRESS_CMDID, &cmd, sizeof(cmd)); | ||
686 | } | ||
687 | |||
688 | int wmi_set_bcon(struct wil6210_priv *wil, int bi, u8 wmi_nettype) | ||
689 | { | ||
690 | struct wmi_bcon_ctrl_cmd cmd = { | ||
691 | .bcon_interval = cpu_to_le16(bi), | ||
692 | .network_type = wmi_nettype, | ||
693 | .disable_sec_offload = 1, | ||
694 | }; | ||
695 | |||
696 | if (!wil->secure_pcp) | ||
697 | cmd.disable_sec = 1; | ||
698 | |||
699 | return wmi_send(wil, WMI_BCON_CTRL_CMDID, &cmd, sizeof(cmd)); | ||
700 | } | ||
701 | |||
702 | int wmi_set_ssid(struct wil6210_priv *wil, u8 ssid_len, const void *ssid) | ||
703 | { | ||
704 | struct wmi_set_ssid_cmd cmd = { | ||
705 | .ssid_len = cpu_to_le32(ssid_len), | ||
706 | }; | ||
707 | |||
708 | if (ssid_len > sizeof(cmd.ssid)) | ||
709 | return -EINVAL; | ||
710 | |||
711 | memcpy(cmd.ssid, ssid, ssid_len); | ||
712 | |||
713 | return wmi_send(wil, WMI_SET_SSID_CMDID, &cmd, sizeof(cmd)); | ||
714 | } | ||
715 | |||
716 | int wmi_get_ssid(struct wil6210_priv *wil, u8 *ssid_len, void *ssid) | ||
717 | { | ||
718 | int rc; | ||
719 | struct { | ||
720 | struct wil6210_mbox_hdr_wmi wmi; | ||
721 | struct wmi_set_ssid_cmd cmd; | ||
722 | } __packed reply; | ||
723 | int len; /* reply.cmd.ssid_len in CPU order */ | ||
724 | |||
725 | rc = wmi_call(wil, WMI_GET_SSID_CMDID, NULL, 0, WMI_GET_SSID_EVENTID, | ||
726 | &reply, sizeof(reply), 20); | ||
727 | if (rc) | ||
728 | return rc; | ||
729 | |||
730 | len = le32_to_cpu(reply.cmd.ssid_len); | ||
731 | if (len > sizeof(reply.cmd.ssid)) | ||
732 | return -EINVAL; | ||
733 | |||
734 | *ssid_len = len; | ||
735 | memcpy(ssid, reply.cmd.ssid, len); | ||
736 | |||
737 | return 0; | ||
738 | } | ||
739 | |||
740 | int wmi_set_channel(struct wil6210_priv *wil, int channel) | ||
741 | { | ||
742 | struct wmi_set_pcp_channel_cmd cmd = { | ||
743 | .channel = channel - 1, | ||
744 | }; | ||
745 | |||
746 | return wmi_send(wil, WMI_SET_PCP_CHANNEL_CMDID, &cmd, sizeof(cmd)); | ||
747 | } | ||
748 | |||
749 | int wmi_get_channel(struct wil6210_priv *wil, int *channel) | ||
750 | { | ||
751 | int rc; | ||
752 | struct { | ||
753 | struct wil6210_mbox_hdr_wmi wmi; | ||
754 | struct wmi_set_pcp_channel_cmd cmd; | ||
755 | } __packed reply; | ||
756 | |||
757 | rc = wmi_call(wil, WMI_GET_PCP_CHANNEL_CMDID, NULL, 0, | ||
758 | WMI_GET_PCP_CHANNEL_EVENTID, &reply, sizeof(reply), 20); | ||
759 | if (rc) | ||
760 | return rc; | ||
761 | |||
762 | if (reply.cmd.channel > 3) | ||
763 | return -EINVAL; | ||
764 | |||
765 | *channel = reply.cmd.channel + 1; | ||
766 | |||
767 | return 0; | ||
768 | } | ||
769 | |||
770 | int wmi_tx_eapol(struct wil6210_priv *wil, struct sk_buff *skb) | ||
771 | { | ||
772 | struct wmi_eapol_tx_cmd *cmd; | ||
773 | struct ethhdr *eth; | ||
774 | u16 eapol_len = skb->len - ETH_HLEN; | ||
775 | void *eapol = skb->data + ETH_HLEN; | ||
776 | uint i; | ||
777 | int rc; | ||
778 | |||
779 | skb_set_mac_header(skb, 0); | ||
780 | eth = eth_hdr(skb); | ||
781 | wil_dbg_WMI(wil, "EAPOL %d bytes to %pM\n", eapol_len, eth->h_dest); | ||
782 | for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) { | ||
783 | if (memcmp(wil->dst_addr[i], eth->h_dest, ETH_ALEN) == 0) | ||
784 | goto found_dest; | ||
785 | } | ||
786 | |||
787 | return -EINVAL; | ||
788 | |||
789 | found_dest: | ||
790 | /* find out eapol data & len */ | ||
791 | cmd = kzalloc(sizeof(*cmd) + eapol_len, GFP_KERNEL); | ||
792 | if (!cmd) | ||
793 | return -EINVAL; | ||
794 | |||
795 | memcpy(cmd->dst_mac, eth->h_dest, ETH_ALEN); | ||
796 | cmd->eapol_len = cpu_to_le16(eapol_len); | ||
797 | memcpy(cmd->eapol, eapol, eapol_len); | ||
798 | rc = wmi_send(wil, WMI_EAPOL_TX_CMDID, cmd, sizeof(*cmd) + eapol_len); | ||
799 | kfree(cmd); | ||
800 | |||
801 | return rc; | ||
802 | } | ||
803 | |||
804 | int wmi_del_cipher_key(struct wil6210_priv *wil, u8 key_index, | ||
805 | const void *mac_addr) | ||
806 | { | ||
807 | struct wmi_delete_cipher_key_cmd cmd = { | ||
808 | .key_index = key_index, | ||
809 | }; | ||
810 | |||
811 | if (mac_addr) | ||
812 | memcpy(cmd.mac, mac_addr, WMI_MAC_LEN); | ||
813 | |||
814 | return wmi_send(wil, WMI_DELETE_CIPHER_KEY_CMDID, &cmd, sizeof(cmd)); | ||
815 | } | ||
816 | |||
817 | int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index, | ||
818 | const void *mac_addr, int key_len, const void *key) | ||
819 | { | ||
820 | struct wmi_add_cipher_key_cmd cmd = { | ||
821 | .key_index = key_index, | ||
822 | .key_usage = WMI_KEY_USE_PAIRWISE, | ||
823 | .key_len = key_len, | ||
824 | }; | ||
825 | |||
826 | if (!key || (key_len > sizeof(cmd.key))) | ||
827 | return -EINVAL; | ||
828 | |||
829 | memcpy(cmd.key, key, key_len); | ||
830 | if (mac_addr) | ||
831 | memcpy(cmd.mac, mac_addr, WMI_MAC_LEN); | ||
832 | |||
833 | return wmi_send(wil, WMI_ADD_CIPHER_KEY_CMDID, &cmd, sizeof(cmd)); | ||
834 | } | ||
835 | |||
836 | int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie) | ||
837 | { | ||
838 | int rc; | ||
839 | u16 len = sizeof(struct wmi_set_appie_cmd) + ie_len; | ||
840 | struct wmi_set_appie_cmd *cmd = kzalloc(len, GFP_KERNEL); | ||
841 | if (!cmd) { | ||
842 | wil_err(wil, "kmalloc(%d) failed\n", len); | ||
843 | return -ENOMEM; | ||
844 | } | ||
845 | |||
846 | cmd->mgmt_frm_type = type; | ||
847 | /* BUG: FW API define ieLen as u8. Will fix FW */ | ||
848 | cmd->ie_len = cpu_to_le16(ie_len); | ||
849 | memcpy(cmd->ie_info, ie, ie_len); | ||
850 | rc = wmi_send(wil, WMI_SET_APPIE_CMDID, &cmd, len); | ||
851 | kfree(cmd); | ||
852 | |||
853 | return rc; | ||
854 | } | ||
855 | |||
856 | void wmi_event_flush(struct wil6210_priv *wil) | ||
857 | { | ||
858 | struct pending_wmi_event *evt, *t; | ||
859 | |||
860 | wil_dbg_WMI(wil, "%s()\n", __func__); | ||
861 | |||
862 | list_for_each_entry_safe(evt, t, &wil->pending_wmi_ev, list) { | ||
863 | list_del(&evt->list); | ||
864 | kfree(evt); | ||
865 | } | ||
866 | } | ||
867 | |||
868 | static bool wmi_evt_call_handler(struct wil6210_priv *wil, int id, | ||
869 | void *d, int len) | ||
870 | { | ||
871 | uint i; | ||
872 | |||
873 | for (i = 0; i < ARRAY_SIZE(wmi_evt_handlers); i++) { | ||
874 | if (wmi_evt_handlers[i].eventid == id) { | ||
875 | wmi_evt_handlers[i].handler(wil, id, d, len); | ||
876 | return true; | ||
877 | } | ||
878 | } | ||
879 | |||
880 | return false; | ||
881 | } | ||
882 | |||
883 | static void wmi_event_handle(struct wil6210_priv *wil, | ||
884 | struct wil6210_mbox_hdr *hdr) | ||
885 | { | ||
886 | u16 len = le16_to_cpu(hdr->len); | ||
887 | |||
888 | if ((hdr->type == WIL_MBOX_HDR_TYPE_WMI) && | ||
889 | (len >= sizeof(struct wil6210_mbox_hdr_wmi))) { | ||
890 | struct wil6210_mbox_hdr_wmi *wmi = (void *)(&hdr[1]); | ||
891 | void *evt_data = (void *)(&wmi[1]); | ||
892 | u16 id = le16_to_cpu(wmi->id); | ||
893 | /* check if someone waits for this event */ | ||
894 | if (wil->reply_id && wil->reply_id == id) { | ||
895 | if (wil->reply_buf) { | ||
896 | memcpy(wil->reply_buf, wmi, | ||
897 | min(len, wil->reply_size)); | ||
898 | } else { | ||
899 | wmi_evt_call_handler(wil, id, evt_data, | ||
900 | len - sizeof(*wmi)); | ||
901 | } | ||
902 | wil_dbg_WMI(wil, "Complete WMI 0x%04x\n", id); | ||
903 | complete(&wil->wmi_ready); | ||
904 | return; | ||
905 | } | ||
906 | /* unsolicited event */ | ||
907 | /* search for handler */ | ||
908 | if (!wmi_evt_call_handler(wil, id, evt_data, | ||
909 | len - sizeof(*wmi))) { | ||
910 | wil_err(wil, "Unhandled event 0x%04x\n", id); | ||
911 | } | ||
912 | } else { | ||
913 | wil_err(wil, "Unknown event type\n"); | ||
914 | print_hex_dump(KERN_ERR, "evt?? ", DUMP_PREFIX_OFFSET, 16, 1, | ||
915 | hdr, sizeof(*hdr) + len, true); | ||
916 | } | ||
917 | } | ||
918 | |||
919 | /* | ||
920 | * Retrieve next WMI event from the pending list | ||
921 | */ | ||
922 | static struct list_head *next_wmi_ev(struct wil6210_priv *wil) | ||
923 | { | ||
924 | ulong flags; | ||
925 | struct list_head *ret = NULL; | ||
926 | |||
927 | spin_lock_irqsave(&wil->wmi_ev_lock, flags); | ||
928 | |||
929 | if (!list_empty(&wil->pending_wmi_ev)) { | ||
930 | ret = wil->pending_wmi_ev.next; | ||
931 | list_del(ret); | ||
932 | } | ||
933 | |||
934 | spin_unlock_irqrestore(&wil->wmi_ev_lock, flags); | ||
935 | |||
936 | return ret; | ||
937 | } | ||
938 | |||
939 | /* | ||
940 | * Handler for the WMI events | ||
941 | */ | ||
942 | void wmi_event_worker(struct work_struct *work) | ||
943 | { | ||
944 | struct wil6210_priv *wil = container_of(work, struct wil6210_priv, | ||
945 | wmi_event_worker); | ||
946 | struct pending_wmi_event *evt; | ||
947 | struct list_head *lh; | ||
948 | |||
949 | while ((lh = next_wmi_ev(wil)) != NULL) { | ||
950 | evt = list_entry(lh, struct pending_wmi_event, list); | ||
951 | wmi_event_handle(wil, &evt->event.hdr); | ||
952 | kfree(evt); | ||
953 | } | ||
954 | } | ||
955 | |||
956 | void wmi_connect_worker(struct work_struct *work) | ||
957 | { | ||
958 | int rc; | ||
959 | struct wil6210_priv *wil = container_of(work, struct wil6210_priv, | ||
960 | wmi_connect_worker); | ||
961 | |||
962 | if (wil->pending_connect_cid < 0) { | ||
963 | wil_err(wil, "No connection pending\n"); | ||
964 | return; | ||
965 | } | ||
966 | |||
967 | wil_dbg_WMI(wil, "Configure for connection CID %d\n", | ||
968 | wil->pending_connect_cid); | ||
969 | |||
970 | rc = wil_vring_init_tx(wil, 0, WIL6210_TX_RING_SIZE, | ||
971 | wil->pending_connect_cid, 0); | ||
972 | wil->pending_connect_cid = -1; | ||
973 | if (rc == 0) | ||
974 | wil_link_on(wil); | ||
975 | } | ||
diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h new file mode 100644 index 000000000000..3bbf87572b07 --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/wmi.h | |||
@@ -0,0 +1,1116 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012 Qualcomm Atheros, Inc. | ||
3 | * Copyright (c) 2006-2012 Wilocity . | ||
4 | * | ||
5 | * Permission to use, copy, modify, and/or distribute this software for any | ||
6 | * purpose with or without fee is hereby granted, provided that the above | ||
7 | * copyright notice and this permission notice appear in all copies. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
16 | */ | ||
17 | |||
18 | /* | ||
19 | * This file contains the definitions of the WMI protocol specified in the | ||
20 | * Wireless Module Interface (WMI) for the Wilocity | ||
21 | * MARLON 60 Gigabit wireless solution. | ||
22 | * It includes definitions of all the commands and events. | ||
23 | * Commands are messages from the host to the WM. | ||
24 | * Events are messages from the WM to the host. | ||
25 | */ | ||
26 | |||
27 | #ifndef __WILOCITY_WMI_H__ | ||
28 | #define __WILOCITY_WMI_H__ | ||
29 | |||
30 | /* General */ | ||
31 | |||
32 | #define WMI_MAC_LEN (6) | ||
33 | #define WMI_PROX_RANGE_NUM (3) | ||
34 | |||
35 | /* List of Commands */ | ||
36 | enum wmi_command_id { | ||
37 | WMI_CONNECT_CMDID = 0x0001, | ||
38 | WMI_DISCONNECT_CMDID = 0x0003, | ||
39 | WMI_START_SCAN_CMDID = 0x0007, | ||
40 | WMI_SET_BSS_FILTER_CMDID = 0x0009, | ||
41 | WMI_SET_PROBED_SSID_CMDID = 0x000a, | ||
42 | WMI_SET_LISTEN_INT_CMDID = 0x000b, | ||
43 | WMI_BCON_CTRL_CMDID = 0x000f, | ||
44 | WMI_ADD_CIPHER_KEY_CMDID = 0x0016, | ||
45 | WMI_DELETE_CIPHER_KEY_CMDID = 0x0017, | ||
46 | WMI_SET_APPIE_CMDID = 0x003f, | ||
47 | WMI_GET_APPIE_CMDID = 0x0040, | ||
48 | WMI_SET_WSC_STATUS_CMDID = 0x0041, | ||
49 | WMI_PXMT_RANGE_CFG_CMDID = 0x0042, | ||
50 | WMI_PXMT_SNR2_RANGE_CFG_CMDID = 0x0043, | ||
51 | WMI_FAST_MEM_ACC_MODE_CMDID = 0x0300, | ||
52 | WMI_MEM_READ_CMDID = 0x0800, | ||
53 | WMI_MEM_WR_CMDID = 0x0801, | ||
54 | WMI_ECHO_CMDID = 0x0803, | ||
55 | WMI_DEEP_ECHO_CMDID = 0x0804, | ||
56 | WMI_CONFIG_MAC_CMDID = 0x0805, | ||
57 | WMI_CONFIG_PHY_DEBUG_CMDID = 0x0806, | ||
58 | WMI_ADD_STATION_CMDID = 0x0807, | ||
59 | WMI_ADD_DEBUG_TX_PCKT_CMDID = 0x0808, | ||
60 | WMI_PHY_GET_STATISTICS_CMDID = 0x0809, | ||
61 | WMI_FS_TUNE_CMDID = 0x080a, | ||
62 | WMI_CORR_MEASURE_CMDID = 0x080b, | ||
63 | WMI_TEMP_SENSE_CMDID = 0x080e, | ||
64 | WMI_DC_CALIB_CMDID = 0x080f, | ||
65 | WMI_SEND_TONE_CMDID = 0x0810, | ||
66 | WMI_IQ_TX_CALIB_CMDID = 0x0811, | ||
67 | WMI_IQ_RX_CALIB_CMDID = 0x0812, | ||
68 | WMI_SET_UCODE_IDLE_CMDID = 0x0813, | ||
69 | WMI_SET_WORK_MODE_CMDID = 0x0815, | ||
70 | WMI_LO_LEAKAGE_CALIB_CMDID = 0x0816, | ||
71 | WMI_MARLON_R_ACTIVATE_CMDID = 0x0817, | ||
72 | WMI_MARLON_R_READ_CMDID = 0x0818, | ||
73 | WMI_MARLON_R_WRITE_CMDID = 0x0819, | ||
74 | WMI_MARLON_R_TXRX_SEL_CMDID = 0x081a, | ||
75 | MAC_IO_STATIC_PARAMS_CMDID = 0x081b, | ||
76 | MAC_IO_DYNAMIC_PARAMS_CMDID = 0x081c, | ||
77 | WMI_SILENT_RSSI_CALIB_CMDID = 0x081d, | ||
78 | WMI_CFG_RX_CHAIN_CMDID = 0x0820, | ||
79 | WMI_VRING_CFG_CMDID = 0x0821, | ||
80 | WMI_RX_ON_CMDID = 0x0822, | ||
81 | WMI_VRING_BA_EN_CMDID = 0x0823, | ||
82 | WMI_VRING_BA_DIS_CMDID = 0x0824, | ||
83 | WMI_RCP_ADDBA_RESP_CMDID = 0x0825, | ||
84 | WMI_RCP_DELBA_CMDID = 0x0826, | ||
85 | WMI_SET_SSID_CMDID = 0x0827, | ||
86 | WMI_GET_SSID_CMDID = 0x0828, | ||
87 | WMI_SET_PCP_CHANNEL_CMDID = 0x0829, | ||
88 | WMI_GET_PCP_CHANNEL_CMDID = 0x082a, | ||
89 | WMI_SW_TX_REQ_CMDID = 0x082b, | ||
90 | WMI_RX_OFF_CMDID = 0x082c, | ||
91 | WMI_READ_MAC_RXQ_CMDID = 0x0830, | ||
92 | WMI_READ_MAC_TXQ_CMDID = 0x0831, | ||
93 | WMI_WRITE_MAC_RXQ_CMDID = 0x0832, | ||
94 | WMI_WRITE_MAC_TXQ_CMDID = 0x0833, | ||
95 | WMI_WRITE_MAC_XQ_FIELD_CMDID = 0x0834, | ||
96 | WMI_MLME_PUSH_CMDID = 0x0835, | ||
97 | WMI_BEAMFORMING_MGMT_CMDID = 0x0836, | ||
98 | WMI_BF_TXSS_MGMT_CMDID = 0x0837, | ||
99 | WMI_BF_SM_MGMT_CMDID = 0x0838, | ||
100 | WMI_BF_RXSS_MGMT_CMDID = 0x0839, | ||
101 | WMI_SET_SECTORS_CMDID = 0x0849, | ||
102 | WMI_MAINTAIN_PAUSE_CMDID = 0x0850, | ||
103 | WMI_MAINTAIN_RESUME_CMDID = 0x0851, | ||
104 | WMI_RS_MGMT_CMDID = 0x0852, | ||
105 | WMI_RF_MGMT_CMDID = 0x0853, | ||
106 | /* Performance monitoring commands */ | ||
107 | WMI_BF_CTRL_CMDID = 0x0862, | ||
108 | WMI_NOTIFY_REQ_CMDID = 0x0863, | ||
109 | WMI_GET_STATUS_CMDID = 0x0864, | ||
110 | WMI_UNIT_TEST_CMDID = 0x0900, | ||
111 | WMI_HICCUP_CMDID = 0x0901, | ||
112 | WMI_FLASH_READ_CMDID = 0x0902, | ||
113 | WMI_FLASH_WRITE_CMDID = 0x0903, | ||
114 | WMI_SECURITY_UNIT_TEST_CMDID = 0x0904, | ||
115 | |||
116 | WMI_SET_MAC_ADDRESS_CMDID = 0xf003, | ||
117 | WMI_ABORT_SCAN_CMDID = 0xf007, | ||
118 | WMI_SET_PMK_CMDID = 0xf028, | ||
119 | |||
120 | WMI_SET_PROMISCUOUS_MODE_CMDID = 0xf041, | ||
121 | WMI_GET_PMK_CMDID = 0xf048, | ||
122 | WMI_SET_PASSPHRASE_CMDID = 0xf049, | ||
123 | WMI_SEND_ASSOC_RES_CMDID = 0xf04a, | ||
124 | WMI_SET_ASSOC_REQ_RELAY_CMDID = 0xf04b, | ||
125 | WMI_EAPOL_TX_CMDID = 0xf04c, | ||
126 | WMI_MAC_ADDR_REQ_CMDID = 0xf04d, | ||
127 | WMI_FW_VER_CMDID = 0xf04e, | ||
128 | }; | ||
129 | |||
130 | /* | ||
131 | * Commands data structures | ||
132 | */ | ||
133 | |||
134 | /* | ||
135 | * Frame Types | ||
136 | */ | ||
137 | enum wmi_mgmt_frame_type { | ||
138 | WMI_FRAME_BEACON = 0, | ||
139 | WMI_FRAME_PROBE_REQ = 1, | ||
140 | WMI_FRAME_PROBE_RESP = 2, | ||
141 | WMI_FRAME_ASSOC_REQ = 3, | ||
142 | WMI_FRAME_ASSOC_RESP = 4, | ||
143 | WMI_NUM_MGMT_FRAME, | ||
144 | }; | ||
145 | |||
146 | /* | ||
147 | * WMI_CONNECT_CMDID | ||
148 | */ | ||
149 | enum wmi_network_type { | ||
150 | WMI_NETTYPE_INFRA = 0x01, | ||
151 | WMI_NETTYPE_ADHOC = 0x02, | ||
152 | WMI_NETTYPE_ADHOC_CREATOR = 0x04, | ||
153 | WMI_NETTYPE_AP = 0x10, | ||
154 | WMI_NETTYPE_P2P = 0x20, | ||
155 | WMI_NETTYPE_WBE = 0x40, /* PCIE over 60g */ | ||
156 | }; | ||
157 | |||
158 | enum wmi_dot11_auth_mode { | ||
159 | WMI_AUTH11_OPEN = 0x01, | ||
160 | WMI_AUTH11_SHARED = 0x02, | ||
161 | WMI_AUTH11_LEAP = 0x04, | ||
162 | WMI_AUTH11_WSC = 0x08, | ||
163 | }; | ||
164 | |||
165 | enum wmi_auth_mode { | ||
166 | WMI_AUTH_NONE = 0x01, | ||
167 | WMI_AUTH_WPA = 0x02, | ||
168 | WMI_AUTH_WPA2 = 0x04, | ||
169 | WMI_AUTH_WPA_PSK = 0x08, | ||
170 | WMI_AUTH_WPA2_PSK = 0x10, | ||
171 | WMI_AUTH_WPA_CCKM = 0x20, | ||
172 | WMI_AUTH_WPA2_CCKM = 0x40, | ||
173 | }; | ||
174 | |||
175 | enum wmi_crypto_type { | ||
176 | WMI_CRYPT_NONE = 0x01, | ||
177 | WMI_CRYPT_WEP = 0x02, | ||
178 | WMI_CRYPT_TKIP = 0x04, | ||
179 | WMI_CRYPT_AES = 0x08, | ||
180 | WMI_CRYPT_AES_GCMP = 0x20, | ||
181 | }; | ||
182 | |||
183 | |||
184 | enum wmi_connect_ctrl_flag_bits { | ||
185 | WMI_CONNECT_ASSOC_POLICY_USER = 0x0001, | ||
186 | WMI_CONNECT_SEND_REASSOC = 0x0002, | ||
187 | WMI_CONNECT_IGNORE_WPAx_GROUP_CIPHER = 0x0004, | ||
188 | WMI_CONNECT_PROFILE_MATCH_DONE = 0x0008, | ||
189 | WMI_CONNECT_IGNORE_AAC_BEACON = 0x0010, | ||
190 | WMI_CONNECT_CSA_FOLLOW_BSS = 0x0020, | ||
191 | WMI_CONNECT_DO_WPA_OFFLOAD = 0x0040, | ||
192 | WMI_CONNECT_DO_NOT_DEAUTH = 0x0080, | ||
193 | }; | ||
194 | |||
195 | #define WMI_MAX_SSID_LEN (32) | ||
196 | |||
197 | struct wmi_connect_cmd { | ||
198 | u8 network_type; | ||
199 | u8 dot11_auth_mode; | ||
200 | u8 auth_mode; | ||
201 | u8 pairwise_crypto_type; | ||
202 | u8 pairwise_crypto_len; | ||
203 | u8 group_crypto_type; | ||
204 | u8 group_crypto_len; | ||
205 | u8 ssid_len; | ||
206 | u8 ssid[WMI_MAX_SSID_LEN]; | ||
207 | u8 channel; | ||
208 | u8 reserved0; | ||
209 | u8 bssid[WMI_MAC_LEN]; | ||
210 | __le32 ctrl_flags; | ||
211 | u8 dst_mac[WMI_MAC_LEN]; | ||
212 | u8 reserved1[2]; | ||
213 | } __packed; | ||
214 | |||
215 | |||
216 | /* | ||
217 | * WMI_RECONNECT_CMDID | ||
218 | */ | ||
219 | struct wmi_reconnect_cmd { | ||
220 | u8 channel; /* hint */ | ||
221 | u8 reserved; | ||
222 | u8 bssid[WMI_MAC_LEN]; /* mandatory if set */ | ||
223 | } __packed; | ||
224 | |||
225 | |||
226 | /* | ||
227 | * WMI_SET_PMK_CMDID | ||
228 | */ | ||
229 | |||
230 | #define WMI_MIN_KEY_INDEX (0) | ||
231 | #define WMI_MAX_KEY_INDEX (3) | ||
232 | #define WMI_MAX_KEY_LEN (32) | ||
233 | #define WMI_PASSPHRASE_LEN (64) | ||
234 | #define WMI_PMK_LEN (32) | ||
235 | |||
236 | struct wmi_set_pmk_cmd { | ||
237 | u8 pmk[WMI_PMK_LEN]; | ||
238 | } __packed; | ||
239 | |||
240 | |||
241 | /* | ||
242 | * WMI_SET_PASSPHRASE_CMDID | ||
243 | */ | ||
244 | struct wmi_set_passphrase_cmd { | ||
245 | u8 ssid[WMI_MAX_SSID_LEN]; | ||
246 | u8 passphrase[WMI_PASSPHRASE_LEN]; | ||
247 | u8 ssid_len; | ||
248 | u8 passphrase_len; | ||
249 | } __packed; | ||
250 | |||
251 | /* | ||
252 | * WMI_ADD_CIPHER_KEY_CMDID | ||
253 | */ | ||
254 | enum wmi_key_usage { | ||
255 | WMI_KEY_USE_PAIRWISE = 0, | ||
256 | WMI_KEY_USE_GROUP = 1, | ||
257 | WMI_KEY_USE_TX = 2, /* default Tx Key - Static WEP only */ | ||
258 | }; | ||
259 | |||
260 | struct wmi_add_cipher_key_cmd { | ||
261 | u8 key_index; | ||
262 | u8 key_type; | ||
263 | u8 key_usage; /* enum wmi_key_usage */ | ||
264 | u8 key_len; | ||
265 | u8 key_rsc[8]; /* key replay sequence counter */ | ||
266 | u8 key[WMI_MAX_KEY_LEN]; | ||
267 | u8 key_op_ctrl; /* Additional Key Control information */ | ||
268 | u8 mac[WMI_MAC_LEN]; | ||
269 | } __packed; | ||
270 | |||
271 | /* | ||
272 | * WMI_DELETE_CIPHER_KEY_CMDID | ||
273 | */ | ||
274 | struct wmi_delete_cipher_key_cmd { | ||
275 | u8 key_index; | ||
276 | u8 mac[WMI_MAC_LEN]; | ||
277 | } __packed; | ||
278 | |||
279 | |||
280 | /* | ||
281 | * WMI_START_SCAN_CMDID | ||
282 | * | ||
283 | * Start L1 scan operation | ||
284 | * | ||
285 | * Returned events: | ||
286 | * - WMI_RX_MGMT_PACKET_EVENTID - for every probe resp. | ||
287 | * - WMI_SCAN_COMPLETE_EVENTID | ||
288 | */ | ||
289 | enum wmi_scan_type { | ||
290 | WMI_LONG_SCAN = 0, | ||
291 | WMI_SHORT_SCAN = 1, | ||
292 | }; | ||
293 | |||
294 | struct wmi_start_scan_cmd { | ||
295 | u8 reserved[8]; | ||
296 | __le32 home_dwell_time; /* Max duration in the home channel(ms) */ | ||
297 | __le32 force_scan_interval; /* Time interval between scans (ms)*/ | ||
298 | u8 scan_type; /* wmi_scan_type */ | ||
299 | u8 num_channels; /* how many channels follow */ | ||
300 | struct { | ||
301 | u8 channel; | ||
302 | u8 reserved; | ||
303 | } channel_list[0]; /* channels ID's */ | ||
304 | /* 0 - 58320 MHz */ | ||
305 | /* 1 - 60480 MHz */ | ||
306 | /* 2 - 62640 MHz */ | ||
307 | } __packed; | ||
308 | |||
309 | /* | ||
310 | * WMI_SET_PROBED_SSID_CMDID | ||
311 | */ | ||
312 | #define MAX_PROBED_SSID_INDEX (15) | ||
313 | |||
314 | enum wmi_ssid_flag { | ||
315 | WMI_SSID_FLAG_DISABLE = 0, /* disables entry */ | ||
316 | WMI_SSID_FLAG_SPECIFIC = 1, /* probes specified ssid */ | ||
317 | WMI_SSID_FLAG_ANY = 2, /* probes for any ssid */ | ||
318 | }; | ||
319 | |||
320 | struct wmi_probed_ssid_cmd { | ||
321 | u8 entry_index; /* 0 to MAX_PROBED_SSID_INDEX */ | ||
322 | u8 flag; /* enum wmi_ssid_flag */ | ||
323 | u8 ssid_len; | ||
324 | u8 ssid[WMI_MAX_SSID_LEN]; | ||
325 | } __packed; | ||
326 | |||
327 | /* | ||
328 | * WMI_SET_APPIE_CMDID | ||
329 | * Add Application specified IE to a management frame | ||
330 | */ | ||
331 | struct wmi_set_appie_cmd { | ||
332 | u8 mgmt_frm_type; /* enum wmi_mgmt_frame_type */ | ||
333 | u8 reserved; | ||
334 | __le16 ie_len; /* Length of the IE to be added to MGMT frame */ | ||
335 | u8 ie_info[0]; | ||
336 | } __packed; | ||
337 | |||
338 | #define WMI_MAX_IE_LEN (1024) | ||
339 | |||
340 | struct wmi_pxmt_range_cfg_cmd { | ||
341 | u8 dst_mac[WMI_MAC_LEN]; | ||
342 | __le16 range; | ||
343 | } __packed; | ||
344 | |||
345 | struct wmi_pxmt_snr2_range_cfg_cmd { | ||
346 | s8 snr2range_arr[WMI_PROX_RANGE_NUM-1]; | ||
347 | } __packed; | ||
348 | |||
349 | /* | ||
350 | * WMI_RF_MGMT_CMDID | ||
351 | */ | ||
352 | enum wmi_rf_mgmt_type { | ||
353 | WMI_RF_MGMT_W_DISABLE = 0, | ||
354 | WMI_RF_MGMT_W_ENABLE = 1, | ||
355 | WMI_RF_MGMT_GET_STATUS = 2, | ||
356 | }; | ||
357 | |||
358 | struct wmi_rf_mgmt_cmd { | ||
359 | __le32 rf_mgmt_type; | ||
360 | } __packed; | ||
361 | |||
362 | /* | ||
363 | * WMI_SET_SSID_CMDID | ||
364 | */ | ||
365 | struct wmi_set_ssid_cmd { | ||
366 | __le32 ssid_len; | ||
367 | u8 ssid[WMI_MAX_SSID_LEN]; | ||
368 | } __packed; | ||
369 | |||
370 | /* | ||
371 | * WMI_SET_PCP_CHANNEL_CMDID | ||
372 | */ | ||
373 | struct wmi_set_pcp_channel_cmd { | ||
374 | u8 channel; | ||
375 | u8 reserved[3]; | ||
376 | } __packed; | ||
377 | |||
378 | /* | ||
379 | * WMI_BCON_CTRL_CMDID | ||
380 | */ | ||
381 | struct wmi_bcon_ctrl_cmd { | ||
382 | __le16 bcon_interval; | ||
383 | __le16 frag_num; | ||
384 | __le64 ss_mask; | ||
385 | u8 network_type; | ||
386 | u8 reserved; | ||
387 | u8 disable_sec_offload; | ||
388 | u8 disable_sec; | ||
389 | } __packed; | ||
390 | |||
391 | /* | ||
392 | * WMI_SW_TX_REQ_CMDID | ||
393 | */ | ||
394 | struct wmi_sw_tx_req_cmd { | ||
395 | u8 dst_mac[WMI_MAC_LEN]; | ||
396 | __le16 len; | ||
397 | u8 payload[0]; | ||
398 | } __packed; | ||
399 | |||
400 | /* | ||
401 | * WMI_VRING_CFG_CMDID | ||
402 | */ | ||
403 | |||
404 | struct wmi_sw_ring_cfg { | ||
405 | __le64 ring_mem_base; | ||
406 | __le16 ring_size; | ||
407 | __le16 max_mpdu_size; | ||
408 | } __packed; | ||
409 | |||
410 | struct wmi_vring_cfg_schd { | ||
411 | __le16 priority; | ||
412 | __le16 timeslot_us; | ||
413 | } __packed; | ||
414 | |||
415 | enum wmi_vring_cfg_encap_trans_type { | ||
416 | WMI_VRING_ENC_TYPE_802_3 = 0, | ||
417 | WMI_VRING_ENC_TYPE_NATIVE_WIFI = 1, | ||
418 | }; | ||
419 | |||
420 | enum wmi_vring_cfg_ds_cfg { | ||
421 | WMI_VRING_DS_PBSS = 0, | ||
422 | WMI_VRING_DS_STATION = 1, | ||
423 | WMI_VRING_DS_AP = 2, | ||
424 | WMI_VRING_DS_ADDR4 = 3, | ||
425 | }; | ||
426 | |||
427 | enum wmi_vring_cfg_nwifi_ds_trans_type { | ||
428 | WMI_NWIFI_TX_TRANS_MODE_NO = 0, | ||
429 | WMI_NWIFI_TX_TRANS_MODE_AP2PBSS = 1, | ||
430 | WMI_NWIFI_TX_TRANS_MODE_STA2PBSS = 2, | ||
431 | }; | ||
432 | |||
433 | enum wmi_vring_cfg_schd_params_priority { | ||
434 | WMI_SCH_PRIO_REGULAR = 0, | ||
435 | WMI_SCH_PRIO_HIGH = 1, | ||
436 | }; | ||
437 | |||
438 | struct wmi_vring_cfg { | ||
439 | struct wmi_sw_ring_cfg tx_sw_ring; | ||
440 | u8 ringid; /* 0-23 vrings */ | ||
441 | |||
442 | #define CIDXTID_CID_POS (0) | ||
443 | #define CIDXTID_CID_LEN (4) | ||
444 | #define CIDXTID_CID_MSK (0xF) | ||
445 | #define CIDXTID_TID_POS (4) | ||
446 | #define CIDXTID_TID_LEN (4) | ||
447 | #define CIDXTID_TID_MSK (0xF0) | ||
448 | u8 cidxtid; | ||
449 | |||
450 | u8 encap_trans_type; | ||
451 | u8 ds_cfg; /* 802.3 DS cfg */ | ||
452 | u8 nwifi_ds_trans_type; | ||
453 | |||
454 | #define VRING_CFG_MAC_CTRL_LIFETIME_EN_POS (0) | ||
455 | #define VRING_CFG_MAC_CTRL_LIFETIME_EN_LEN (1) | ||
456 | #define VRING_CFG_MAC_CTRL_LIFETIME_EN_MSK (0x1) | ||
457 | #define VRING_CFG_MAC_CTRL_AGGR_EN_POS (1) | ||
458 | #define VRING_CFG_MAC_CTRL_AGGR_EN_LEN (1) | ||
459 | #define VRING_CFG_MAC_CTRL_AGGR_EN_MSK (0x2) | ||
460 | u8 mac_ctrl; | ||
461 | |||
462 | #define VRING_CFG_TO_RESOLUTION_VALUE_POS (0) | ||
463 | #define VRING_CFG_TO_RESOLUTION_VALUE_LEN (6) | ||
464 | #define VRING_CFG_TO_RESOLUTION_VALUE_MSK (0x3F) | ||
465 | u8 to_resolution; | ||
466 | u8 agg_max_wsize; | ||
467 | struct wmi_vring_cfg_schd schd_params; | ||
468 | } __packed; | ||
469 | |||
470 | enum wmi_vring_cfg_cmd_action { | ||
471 | WMI_VRING_CMD_ADD = 0, | ||
472 | WMI_VRING_CMD_MODIFY = 1, | ||
473 | WMI_VRING_CMD_DELETE = 2, | ||
474 | }; | ||
475 | |||
476 | struct wmi_vring_cfg_cmd { | ||
477 | __le32 action; | ||
478 | struct wmi_vring_cfg vring_cfg; | ||
479 | } __packed; | ||
480 | |||
481 | /* | ||
482 | * WMI_VRING_BA_EN_CMDID | ||
483 | */ | ||
484 | struct wmi_vring_ba_en_cmd { | ||
485 | u8 ringid; | ||
486 | u8 agg_max_wsize; | ||
487 | __le16 ba_timeout; | ||
488 | } __packed; | ||
489 | |||
490 | /* | ||
491 | * WMI_VRING_BA_DIS_CMDID | ||
492 | */ | ||
493 | struct wmi_vring_ba_dis_cmd { | ||
494 | u8 ringid; | ||
495 | u8 reserved; | ||
496 | __le16 reason; | ||
497 | } __packed; | ||
498 | |||
499 | /* | ||
500 | * WMI_NOTIFY_REQ_CMDID | ||
501 | */ | ||
502 | struct wmi_notify_req_cmd { | ||
503 | u8 cid; | ||
504 | u8 reserved[3]; | ||
505 | __le32 interval_usec; | ||
506 | } __packed; | ||
507 | |||
508 | /* | ||
509 | * WMI_CFG_RX_CHAIN_CMDID | ||
510 | */ | ||
511 | enum wmi_sniffer_cfg_mode { | ||
512 | WMI_SNIFFER_OFF = 0, | ||
513 | WMI_SNIFFER_ON = 1, | ||
514 | }; | ||
515 | |||
516 | enum wmi_sniffer_cfg_phy_info_mode { | ||
517 | WMI_SNIFFER_PHY_INFO_DISABLED = 0, | ||
518 | WMI_SNIFFER_PHY_INFO_ENABLED = 1, | ||
519 | }; | ||
520 | |||
521 | enum wmi_sniffer_cfg_phy_support { | ||
522 | WMI_SNIFFER_CP = 0, | ||
523 | WMI_SNIFFER_DP = 1, | ||
524 | WMI_SNIFFER_BOTH_PHYS = 2, | ||
525 | }; | ||
526 | |||
527 | struct wmi_sniffer_cfg { | ||
528 | __le32 mode; /* enum wmi_sniffer_cfg_mode */ | ||
529 | __le32 phy_info_mode; /* enum wmi_sniffer_cfg_phy_info_mode */ | ||
530 | __le32 phy_support; /* enum wmi_sniffer_cfg_phy_support */ | ||
531 | u8 channel; | ||
532 | u8 reserved[3]; | ||
533 | } __packed; | ||
534 | |||
535 | enum wmi_cfg_rx_chain_cmd_action { | ||
536 | WMI_RX_CHAIN_ADD = 0, | ||
537 | WMI_RX_CHAIN_DEL = 1, | ||
538 | }; | ||
539 | |||
540 | enum wmi_cfg_rx_chain_cmd_decap_trans_type { | ||
541 | WMI_DECAP_TYPE_802_3 = 0, | ||
542 | WMI_DECAP_TYPE_NATIVE_WIFI = 1, | ||
543 | }; | ||
544 | |||
545 | enum wmi_cfg_rx_chain_cmd_nwifi_ds_trans_type { | ||
546 | WMI_NWIFI_RX_TRANS_MODE_NO = 0, | ||
547 | WMI_NWIFI_RX_TRANS_MODE_PBSS2AP = 1, | ||
548 | WMI_NWIFI_RX_TRANS_MODE_PBSS2STA = 2, | ||
549 | }; | ||
550 | |||
551 | struct wmi_cfg_rx_chain_cmd { | ||
552 | __le32 action; | ||
553 | struct wmi_sw_ring_cfg rx_sw_ring; | ||
554 | u8 mid; | ||
555 | u8 decap_trans_type; | ||
556 | |||
557 | #define L2_802_3_OFFLOAD_CTRL_VLAN_TAG_INSERTION_POS (0) | ||
558 | #define L2_802_3_OFFLOAD_CTRL_VLAN_TAG_INSERTION_LEN (1) | ||
559 | #define L2_802_3_OFFLOAD_CTRL_VLAN_TAG_INSERTION_MSK (0x1) | ||
560 | u8 l2_802_3_offload_ctrl; | ||
561 | |||
562 | #define L2_NWIFI_OFFLOAD_CTRL_REMOVE_QOS_POS (0) | ||
563 | #define L2_NWIFI_OFFLOAD_CTRL_REMOVE_QOS_LEN (1) | ||
564 | #define L2_NWIFI_OFFLOAD_CTRL_REMOVE_QOS_MSK (0x1) | ||
565 | #define L2_NWIFI_OFFLOAD_CTRL_REMOVE_PN_POS (1) | ||
566 | #define L2_NWIFI_OFFLOAD_CTRL_REMOVE_PN_LEN (1) | ||
567 | #define L2_NWIFI_OFFLOAD_CTRL_REMOVE_PN_MSK (0x2) | ||
568 | u8 l2_nwifi_offload_ctrl; | ||
569 | |||
570 | u8 vlan_id; | ||
571 | u8 nwifi_ds_trans_type; | ||
572 | |||
573 | #define L3_L4_CTRL_IPV4_CHECKSUM_EN_POS (0) | ||
574 | #define L3_L4_CTRL_IPV4_CHECKSUM_EN_LEN (1) | ||
575 | #define L3_L4_CTRL_IPV4_CHECKSUM_EN_MSK (0x1) | ||
576 | #define L3_L4_CTRL_TCPIP_CHECKSUM_EN_POS (1) | ||
577 | #define L3_L4_CTRL_TCPIP_CHECKSUM_EN_LEN (1) | ||
578 | #define L3_L4_CTRL_TCPIP_CHECKSUM_EN_MSK (0x2) | ||
579 | u8 l3_l4_ctrl; | ||
580 | |||
581 | #define RING_CTRL_OVERRIDE_PREFETCH_THRSH_POS (0) | ||
582 | #define RING_CTRL_OVERRIDE_PREFETCH_THRSH_LEN (1) | ||
583 | #define RING_CTRL_OVERRIDE_PREFETCH_THRSH_MSK (0x1) | ||
584 | #define RING_CTRL_OVERRIDE_WB_THRSH_POS (1) | ||
585 | #define RING_CTRL_OVERRIDE_WB_THRSH_LEN (1) | ||
586 | #define RING_CTRL_OVERRIDE_WB_THRSH_MSK (0x2) | ||
587 | #define RING_CTRL_OVERRIDE_ITR_THRSH_POS (2) | ||
588 | #define RING_CTRL_OVERRIDE_ITR_THRSH_LEN (1) | ||
589 | #define RING_CTRL_OVERRIDE_ITR_THRSH_MSK (0x4) | ||
590 | #define RING_CTRL_OVERRIDE_HOST_THRSH_POS (3) | ||
591 | #define RING_CTRL_OVERRIDE_HOST_THRSH_LEN (1) | ||
592 | #define RING_CTRL_OVERRIDE_HOST_THRSH_MSK (0x8) | ||
593 | u8 ring_ctrl; | ||
594 | |||
595 | __le16 prefetch_thrsh; | ||
596 | __le16 wb_thrsh; | ||
597 | __le32 itr_value; | ||
598 | __le16 host_thrsh; | ||
599 | u8 reserved[2]; | ||
600 | struct wmi_sniffer_cfg sniffer_cfg; | ||
601 | } __packed; | ||
602 | |||
603 | /* | ||
604 | * WMI_RCP_ADDBA_RESP_CMDID | ||
605 | */ | ||
606 | struct wmi_rcp_addba_resp_cmd { | ||
607 | |||
608 | #define CIDXTID_CID_POS (0) | ||
609 | #define CIDXTID_CID_LEN (4) | ||
610 | #define CIDXTID_CID_MSK (0xF) | ||
611 | #define CIDXTID_TID_POS (4) | ||
612 | #define CIDXTID_TID_LEN (4) | ||
613 | #define CIDXTID_TID_MSK (0xF0) | ||
614 | u8 cidxtid; | ||
615 | |||
616 | u8 dialog_token; | ||
617 | __le16 status_code; | ||
618 | __le16 ba_param_set; /* ieee80211_ba_parameterset field to send */ | ||
619 | __le16 ba_timeout; | ||
620 | } __packed; | ||
621 | |||
622 | /* | ||
623 | * WMI_RCP_DELBA_CMDID | ||
624 | */ | ||
625 | struct wmi_rcp_delba_cmd { | ||
626 | |||
627 | #define CIDXTID_CID_POS (0) | ||
628 | #define CIDXTID_CID_LEN (4) | ||
629 | #define CIDXTID_CID_MSK (0xF) | ||
630 | #define CIDXTID_TID_POS (4) | ||
631 | #define CIDXTID_TID_LEN (4) | ||
632 | #define CIDXTID_TID_MSK (0xF0) | ||
633 | u8 cidxtid; | ||
634 | |||
635 | u8 reserved; | ||
636 | __le16 reason; | ||
637 | } __packed; | ||
638 | |||
639 | /* | ||
640 | * WMI_RCP_ADDBA_REQ_CMDID | ||
641 | */ | ||
642 | struct wmi_rcp_addba_req_cmd { | ||
643 | |||
644 | #define CIDXTID_CID_POS (0) | ||
645 | #define CIDXTID_CID_LEN (4) | ||
646 | #define CIDXTID_CID_MSK (0xF) | ||
647 | #define CIDXTID_TID_POS (4) | ||
648 | #define CIDXTID_TID_LEN (4) | ||
649 | #define CIDXTID_TID_MSK (0xF0) | ||
650 | u8 cidxtid; | ||
651 | |||
652 | u8 dialog_token; | ||
653 | /* ieee80211_ba_parameterset field as it received */ | ||
654 | __le16 ba_param_set; | ||
655 | __le16 ba_timeout; | ||
656 | /* ieee80211_ba_seqstrl field as it received */ | ||
657 | __le16 ba_seq_ctrl; | ||
658 | } __packed; | ||
659 | |||
660 | /* | ||
661 | * WMI_SET_MAC_ADDRESS_CMDID | ||
662 | */ | ||
663 | struct wmi_set_mac_address_cmd { | ||
664 | u8 mac[WMI_MAC_LEN]; | ||
665 | u8 reserved[2]; | ||
666 | } __packed; | ||
667 | |||
668 | |||
669 | /* | ||
670 | * WMI_EAPOL_TX_CMDID | ||
671 | */ | ||
672 | struct wmi_eapol_tx_cmd { | ||
673 | u8 dst_mac[WMI_MAC_LEN]; | ||
674 | __le16 eapol_len; | ||
675 | u8 eapol[0]; | ||
676 | } __packed; | ||
677 | |||
678 | /* | ||
679 | * WMI_ECHO_CMDID | ||
680 | * | ||
681 | * Check FW is alive | ||
682 | * | ||
683 | * WMI_DEEP_ECHO_CMDID | ||
684 | * | ||
685 | * Check FW and ucode are alive | ||
686 | * | ||
687 | * Returned event: WMI_ECHO_RSP_EVENTID | ||
688 | * same event for both commands | ||
689 | */ | ||
690 | struct wmi_echo_cmd { | ||
691 | __le32 value; | ||
692 | } __packed; | ||
693 | |||
694 | /* | ||
695 | * WMI Events | ||
696 | */ | ||
697 | |||
698 | /* | ||
699 | * List of Events (target to host) | ||
700 | */ | ||
701 | enum wmi_event_id { | ||
702 | WMI_IMM_RSP_EVENTID = 0x0000, | ||
703 | WMI_READY_EVENTID = 0x1001, | ||
704 | WMI_CONNECT_EVENTID = 0x1002, | ||
705 | WMI_DISCONNECT_EVENTID = 0x1003, | ||
706 | WMI_SCAN_COMPLETE_EVENTID = 0x100a, | ||
707 | WMI_REPORT_STATISTICS_EVENTID = 0x100b, | ||
708 | WMI_RD_MEM_RSP_EVENTID = 0x1800, | ||
709 | WMI_FW_READY_EVENTID = 0x1801, | ||
710 | WMI_EXIT_FAST_MEM_ACC_MODE_EVENTID = 0x0200, | ||
711 | WMI_ECHO_RSP_EVENTID = 0x1803, | ||
712 | WMI_CONFIG_MAC_DONE_EVENTID = 0x1805, | ||
713 | WMI_CONFIG_PHY_DEBUG_DONE_EVENTID = 0x1806, | ||
714 | WMI_ADD_STATION_DONE_EVENTID = 0x1807, | ||
715 | WMI_ADD_DEBUG_TX_PCKT_DONE_EVENTID = 0x1808, | ||
716 | WMI_PHY_GET_STATISTICS_EVENTID = 0x1809, | ||
717 | WMI_FS_TUNE_DONE_EVENTID = 0x180a, | ||
718 | WMI_CORR_MEASURE_DONE_EVENTID = 0x180b, | ||
719 | WMI_TEMP_SENSE_DONE_EVENTID = 0x180e, | ||
720 | WMI_DC_CALIB_DONE_EVENTID = 0x180f, | ||
721 | WMI_IQ_TX_CALIB_DONE_EVENTID = 0x1811, | ||
722 | WMI_IQ_RX_CALIB_DONE_EVENTID = 0x1812, | ||
723 | WMI_SET_WORK_MODE_DONE_EVENTID = 0x1815, | ||
724 | WMI_LO_LEAKAGE_CALIB_DONE_EVENTID = 0x1816, | ||
725 | WMI_MARLON_R_ACTIVATE_DONE_EVENTID = 0x1817, | ||
726 | WMI_MARLON_R_READ_DONE_EVENTID = 0x1818, | ||
727 | WMI_MARLON_R_WRITE_DONE_EVENTID = 0x1819, | ||
728 | WMI_MARLON_R_TXRX_SEL_DONE_EVENTID = 0x181a, | ||
729 | WMI_SILENT_RSSI_CALIB_DONE_EVENTID = 0x181d, | ||
730 | |||
731 | WMI_CFG_RX_CHAIN_DONE_EVENTID = 0x1820, | ||
732 | WMI_VRING_CFG_DONE_EVENTID = 0x1821, | ||
733 | WMI_RX_ON_DONE_EVENTID = 0x1822, | ||
734 | WMI_BA_STATUS_EVENTID = 0x1823, | ||
735 | WMI_RCP_ADDBA_REQ_EVENTID = 0x1824, | ||
736 | WMI_ADDBA_RESP_SENT_EVENTID = 0x1825, | ||
737 | WMI_DELBA_EVENTID = 0x1826, | ||
738 | WMI_GET_SSID_EVENTID = 0x1828, | ||
739 | WMI_GET_PCP_CHANNEL_EVENTID = 0x182a, | ||
740 | WMI_SW_TX_COMPLETE_EVENTID = 0x182b, | ||
741 | WMI_RX_OFF_DONE_EVENTID = 0x182c, | ||
742 | |||
743 | WMI_READ_MAC_RXQ_EVENTID = 0x1830, | ||
744 | WMI_READ_MAC_TXQ_EVENTID = 0x1831, | ||
745 | WMI_WRITE_MAC_RXQ_EVENTID = 0x1832, | ||
746 | WMI_WRITE_MAC_TXQ_EVENTID = 0x1833, | ||
747 | WMI_WRITE_MAC_XQ_FIELD_EVENTID = 0x1834, | ||
748 | |||
749 | WMI_BEAFORMING_MGMT_DONE_EVENTID = 0x1836, | ||
750 | WMI_BF_TXSS_MGMT_DONE_EVENTID = 0x1837, | ||
751 | WMI_BF_RXSS_MGMT_DONE_EVENTID = 0x1839, | ||
752 | WMI_RS_MGMT_DONE_EVENTID = 0x1852, | ||
753 | WMI_RF_MGMT_STATUS_EVENTID = 0x1853, | ||
754 | WMI_BF_SM_MGMT_DONE_EVENTID = 0x1838, | ||
755 | WMI_RX_MGMT_PACKET_EVENTID = 0x1840, | ||
756 | |||
757 | /* Performance monitoring events */ | ||
758 | WMI_DATA_PORT_OPEN_EVENTID = 0x1860, | ||
759 | WMI_WBE_LINKDOWN_EVENTID = 0x1861, | ||
760 | |||
761 | WMI_BF_CTRL_DONE_EVENTID = 0x1862, | ||
762 | WMI_NOTIFY_REQ_DONE_EVENTID = 0x1863, | ||
763 | WMI_GET_STATUS_DONE_EVENTID = 0x1864, | ||
764 | |||
765 | WMI_UNIT_TEST_EVENTID = 0x1900, | ||
766 | WMI_FLASH_READ_DONE_EVENTID = 0x1902, | ||
767 | WMI_FLASH_WRITE_DONE_EVENTID = 0x1903, | ||
768 | |||
769 | WMI_SET_CHANNEL_EVENTID = 0x9000, | ||
770 | WMI_ASSOC_REQ_EVENTID = 0x9001, | ||
771 | WMI_EAPOL_RX_EVENTID = 0x9002, | ||
772 | WMI_MAC_ADDR_RESP_EVENTID = 0x9003, | ||
773 | WMI_FW_VER_EVENTID = 0x9004, | ||
774 | }; | ||
775 | |||
776 | /* | ||
777 | * Events data structures | ||
778 | */ | ||
779 | |||
780 | /* | ||
781 | * WMI_RF_MGMT_STATUS_EVENTID | ||
782 | */ | ||
783 | enum wmi_rf_status { | ||
784 | WMI_RF_ENABLED = 0, | ||
785 | WMI_RF_DISABLED_HW = 1, | ||
786 | WMI_RF_DISABLED_SW = 2, | ||
787 | WMI_RF_DISABLED_HW_SW = 3, | ||
788 | }; | ||
789 | |||
790 | struct wmi_rf_mgmt_status_event { | ||
791 | __le32 rf_status; | ||
792 | } __packed; | ||
793 | |||
794 | /* | ||
795 | * WMI_GET_STATUS_DONE_EVENTID | ||
796 | */ | ||
797 | struct wmi_get_status_done_event { | ||
798 | __le32 is_associated; | ||
799 | u8 cid; | ||
800 | u8 reserved0[3]; | ||
801 | u8 bssid[WMI_MAC_LEN]; | ||
802 | u8 channel; | ||
803 | u8 reserved1; | ||
804 | u8 network_type; | ||
805 | u8 reserved2[3]; | ||
806 | __le32 ssid_len; | ||
807 | u8 ssid[WMI_MAX_SSID_LEN]; | ||
808 | __le32 rf_status; | ||
809 | __le32 is_secured; | ||
810 | } __packed; | ||
811 | |||
812 | /* | ||
813 | * WMI_FW_VER_EVENTID | ||
814 | */ | ||
815 | struct wmi_fw_ver_event { | ||
816 | u8 major; | ||
817 | u8 minor; | ||
818 | __le16 subminor; | ||
819 | __le16 build; | ||
820 | } __packed; | ||
821 | |||
822 | /* | ||
823 | * WMI_MAC_ADDR_RESP_EVENTID | ||
824 | */ | ||
825 | struct wmi_mac_addr_resp_event { | ||
826 | u8 mac[WMI_MAC_LEN]; | ||
827 | u8 auth_mode; | ||
828 | u8 crypt_mode; | ||
829 | __le32 offload_mode; | ||
830 | } __packed; | ||
831 | |||
832 | /* | ||
833 | * WMI_EAPOL_RX_EVENTID | ||
834 | */ | ||
835 | struct wmi_eapol_rx_event { | ||
836 | u8 src_mac[WMI_MAC_LEN]; | ||
837 | __le16 eapol_len; | ||
838 | u8 eapol[0]; | ||
839 | } __packed; | ||
840 | |||
841 | /* | ||
842 | * WMI_READY_EVENTID | ||
843 | */ | ||
844 | enum wmi_phy_capability { | ||
845 | WMI_11A_CAPABILITY = 1, | ||
846 | WMI_11G_CAPABILITY = 2, | ||
847 | WMI_11AG_CAPABILITY = 3, | ||
848 | WMI_11NA_CAPABILITY = 4, | ||
849 | WMI_11NG_CAPABILITY = 5, | ||
850 | WMI_11NAG_CAPABILITY = 6, | ||
851 | WMI_11AD_CAPABILITY = 7, | ||
852 | WMI_11N_CAPABILITY_OFFSET = WMI_11NA_CAPABILITY - WMI_11A_CAPABILITY, | ||
853 | }; | ||
854 | |||
855 | struct wmi_ready_event { | ||
856 | __le32 sw_version; | ||
857 | __le32 abi_version; | ||
858 | u8 mac[WMI_MAC_LEN]; | ||
859 | u8 phy_capability; /* enum wmi_phy_capability */ | ||
860 | u8 reserved; | ||
861 | } __packed; | ||
862 | |||
863 | /* | ||
864 | * WMI_NOTIFY_REQ_DONE_EVENTID | ||
865 | */ | ||
866 | struct wmi_notify_req_done_event { | ||
867 | __le32 status; | ||
868 | __le64 tsf; | ||
869 | __le32 snr_val; | ||
870 | __le32 tx_tpt; | ||
871 | __le32 tx_goodput; | ||
872 | __le32 rx_goodput; | ||
873 | __le16 bf_mcs; | ||
874 | __le16 my_rx_sector; | ||
875 | __le16 my_tx_sector; | ||
876 | __le16 other_rx_sector; | ||
877 | __le16 other_tx_sector; | ||
878 | __le16 range; | ||
879 | } __packed; | ||
880 | |||
881 | /* | ||
882 | * WMI_CONNECT_EVENTID | ||
883 | */ | ||
884 | struct wmi_connect_event { | ||
885 | u8 channel; | ||
886 | u8 reserved0; | ||
887 | u8 bssid[WMI_MAC_LEN]; | ||
888 | __le16 listen_interval; | ||
889 | __le16 beacon_interval; | ||
890 | u8 network_type; | ||
891 | u8 reserved1[3]; | ||
892 | u8 beacon_ie_len; | ||
893 | u8 assoc_req_len; | ||
894 | u8 assoc_resp_len; | ||
895 | u8 cid; | ||
896 | u8 reserved2[3]; | ||
897 | u8 assoc_info[0]; | ||
898 | } __packed; | ||
899 | |||
900 | /* | ||
901 | * WMI_DISCONNECT_EVENTID | ||
902 | */ | ||
903 | enum wmi_disconnect_reason { | ||
904 | WMI_DIS_REASON_NO_NETWORK_AVAIL = 1, | ||
905 | WMI_DIS_REASON_LOST_LINK = 2, /* bmiss */ | ||
906 | WMI_DIS_REASON_DISCONNECT_CMD = 3, | ||
907 | WMI_DIS_REASON_BSS_DISCONNECTED = 4, | ||
908 | WMI_DIS_REASON_AUTH_FAILED = 5, | ||
909 | WMI_DIS_REASON_ASSOC_FAILED = 6, | ||
910 | WMI_DIS_REASON_NO_RESOURCES_AVAIL = 7, | ||
911 | WMI_DIS_REASON_CSERV_DISCONNECT = 8, | ||
912 | WMI_DIS_REASON_INVALID_PROFILE = 10, | ||
913 | WMI_DIS_REASON_DOT11H_CHANNEL_SWITCH = 11, | ||
914 | WMI_DIS_REASON_PROFILE_MISMATCH = 12, | ||
915 | WMI_DIS_REASON_CONNECTION_EVICTED = 13, | ||
916 | WMI_DIS_REASON_IBSS_MERGE = 14, | ||
917 | }; | ||
918 | |||
919 | struct wmi_disconnect_event { | ||
920 | __le16 protocol_reason_status; /* reason code, see 802.11 spec. */ | ||
921 | u8 bssid[WMI_MAC_LEN]; /* set if known */ | ||
922 | u8 disconnect_reason; /* see wmi_disconnect_reason_e */ | ||
923 | u8 assoc_resp_len; | ||
924 | u8 assoc_info[0]; | ||
925 | } __packed; | ||
926 | |||
927 | /* | ||
928 | * WMI_SCAN_COMPLETE_EVENTID | ||
929 | */ | ||
930 | struct wmi_scan_complete_event { | ||
931 | __le32 status; | ||
932 | } __packed; | ||
933 | |||
934 | /* | ||
935 | * WMI_BA_STATUS_EVENTID | ||
936 | */ | ||
937 | enum wmi_vring_ba_status { | ||
938 | WMI_BA_AGREED = 0, | ||
939 | WMI_BA_NON_AGREED = 1, | ||
940 | }; | ||
941 | |||
942 | struct wmi_vring_ba_status_event { | ||
943 | __le16 status; | ||
944 | u8 reserved[2]; | ||
945 | u8 ringid; | ||
946 | u8 agg_wsize; | ||
947 | __le16 ba_timeout; | ||
948 | } __packed; | ||
949 | |||
950 | /* | ||
951 | * WMI_DELBA_EVENTID | ||
952 | */ | ||
953 | struct wmi_delba_event { | ||
954 | |||
955 | #define CIDXTID_CID_POS (0) | ||
956 | #define CIDXTID_CID_LEN (4) | ||
957 | #define CIDXTID_CID_MSK (0xF) | ||
958 | #define CIDXTID_TID_POS (4) | ||
959 | #define CIDXTID_TID_LEN (4) | ||
960 | #define CIDXTID_TID_MSK (0xF0) | ||
961 | u8 cidxtid; | ||
962 | |||
963 | u8 from_initiator; | ||
964 | __le16 reason; | ||
965 | } __packed; | ||
966 | |||
967 | /* | ||
968 | * WMI_VRING_CFG_DONE_EVENTID | ||
969 | */ | ||
970 | enum wmi_vring_cfg_done_event_status { | ||
971 | WMI_VRING_CFG_SUCCESS = 0, | ||
972 | WMI_VRING_CFG_FAILURE = 1, | ||
973 | }; | ||
974 | |||
975 | struct wmi_vring_cfg_done_event { | ||
976 | u8 ringid; | ||
977 | u8 status; | ||
978 | u8 reserved[2]; | ||
979 | __le32 tx_vring_tail_ptr; | ||
980 | } __packed; | ||
981 | |||
982 | /* | ||
983 | * WMI_ADDBA_RESP_SENT_EVENTID | ||
984 | */ | ||
985 | enum wmi_rcp_addba_resp_sent_event_status { | ||
986 | WMI_ADDBA_SUCCESS = 0, | ||
987 | WMI_ADDBA_FAIL = 1, | ||
988 | }; | ||
989 | |||
990 | struct wmi_rcp_addba_resp_sent_event { | ||
991 | |||
992 | #define CIDXTID_CID_POS (0) | ||
993 | #define CIDXTID_CID_LEN (4) | ||
994 | #define CIDXTID_CID_MSK (0xF) | ||
995 | #define CIDXTID_TID_POS (4) | ||
996 | #define CIDXTID_TID_LEN (4) | ||
997 | #define CIDXTID_TID_MSK (0xF0) | ||
998 | u8 cidxtid; | ||
999 | |||
1000 | u8 reserved; | ||
1001 | __le16 status; | ||
1002 | } __packed; | ||
1003 | |||
1004 | /* | ||
1005 | * WMI_RCP_ADDBA_REQ_EVENTID | ||
1006 | */ | ||
1007 | struct wmi_rcp_addba_req_event { | ||
1008 | |||
1009 | #define CIDXTID_CID_POS (0) | ||
1010 | #define CIDXTID_CID_LEN (4) | ||
1011 | #define CIDXTID_CID_MSK (0xF) | ||
1012 | #define CIDXTID_TID_POS (4) | ||
1013 | #define CIDXTID_TID_LEN (4) | ||
1014 | #define CIDXTID_TID_MSK (0xF0) | ||
1015 | u8 cidxtid; | ||
1016 | |||
1017 | u8 dialog_token; | ||
1018 | __le16 ba_param_set; /* ieee80211_ba_parameterset as it received */ | ||
1019 | __le16 ba_timeout; | ||
1020 | __le16 ba_seq_ctrl; /* ieee80211_ba_seqstrl field as it received */ | ||
1021 | } __packed; | ||
1022 | |||
1023 | /* | ||
1024 | * WMI_CFG_RX_CHAIN_DONE_EVENTID | ||
1025 | */ | ||
1026 | enum wmi_cfg_rx_chain_done_event_status { | ||
1027 | WMI_CFG_RX_CHAIN_SUCCESS = 1, | ||
1028 | }; | ||
1029 | |||
1030 | struct wmi_cfg_rx_chain_done_event { | ||
1031 | __le32 rx_ring_tail_ptr; /* Rx V-Ring Tail pointer */ | ||
1032 | __le32 status; | ||
1033 | } __packed; | ||
1034 | |||
1035 | /* | ||
1036 | * WMI_WBE_LINKDOWN_EVENTID | ||
1037 | */ | ||
1038 | enum wmi_wbe_link_down_event_reason { | ||
1039 | WMI_WBE_REASON_USER_REQUEST = 0, | ||
1040 | WMI_WBE_REASON_RX_DISASSOC = 1, | ||
1041 | WMI_WBE_REASON_BAD_PHY_LINK = 2, | ||
1042 | }; | ||
1043 | |||
1044 | struct wmi_wbe_link_down_event { | ||
1045 | u8 cid; | ||
1046 | u8 reserved[3]; | ||
1047 | __le32 reason; | ||
1048 | } __packed; | ||
1049 | |||
1050 | /* | ||
1051 | * WMI_DATA_PORT_OPEN_EVENTID | ||
1052 | */ | ||
1053 | struct wmi_data_port_open_event { | ||
1054 | u8 cid; | ||
1055 | u8 reserved[3]; | ||
1056 | } __packed; | ||
1057 | |||
1058 | /* | ||
1059 | * WMI_GET_PCP_CHANNEL_EVENTID | ||
1060 | */ | ||
1061 | struct wmi_get_pcp_channel_event { | ||
1062 | u8 channel; | ||
1063 | u8 reserved[3]; | ||
1064 | } __packed; | ||
1065 | |||
1066 | /* | ||
1067 | * WMI_SW_TX_COMPLETE_EVENTID | ||
1068 | */ | ||
1069 | enum wmi_sw_tx_status { | ||
1070 | WMI_TX_SW_STATUS_SUCCESS = 0, | ||
1071 | WMI_TX_SW_STATUS_FAILED_NO_RESOURCES = 1, | ||
1072 | WMI_TX_SW_STATUS_FAILED_TX = 2, | ||
1073 | }; | ||
1074 | |||
1075 | struct wmi_sw_tx_complete_event { | ||
1076 | u8 status; /* enum wmi_sw_tx_status */ | ||
1077 | u8 reserved[3]; | ||
1078 | } __packed; | ||
1079 | |||
1080 | /* | ||
1081 | * WMI_GET_SSID_EVENTID | ||
1082 | */ | ||
1083 | struct wmi_get_ssid_event { | ||
1084 | __le32 ssid_len; | ||
1085 | u8 ssid[WMI_MAX_SSID_LEN]; | ||
1086 | } __packed; | ||
1087 | |||
1088 | /* | ||
1089 | * WMI_RX_MGMT_PACKET_EVENTID | ||
1090 | */ | ||
1091 | struct wmi_rx_mgmt_info { | ||
1092 | u8 mcs; | ||
1093 | s8 snr; | ||
1094 | __le16 range; | ||
1095 | __le16 stype; | ||
1096 | __le16 status; | ||
1097 | __le32 len; | ||
1098 | u8 qid; | ||
1099 | u8 mid; | ||
1100 | u8 cid; | ||
1101 | u8 channel; /* From Radio MNGR */ | ||
1102 | } __packed; | ||
1103 | |||
1104 | struct wmi_rx_mgmt_packet_event { | ||
1105 | struct wmi_rx_mgmt_info info; | ||
1106 | u8 payload[0]; | ||
1107 | } __packed; | ||
1108 | |||
1109 | /* | ||
1110 | * WMI_ECHO_RSP_EVENTID | ||
1111 | */ | ||
1112 | struct wmi_echo_event { | ||
1113 | __le32 echoed_value; | ||
1114 | } __packed; | ||
1115 | |||
1116 | #endif /* __WILOCITY_WMI_H__ */ | ||
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index b298e5d68be2..10e288d470e7 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h | |||
@@ -7,6 +7,7 @@ | |||
7 | #include <linux/hw_random.h> | 7 | #include <linux/hw_random.h> |
8 | #include <linux/bcma/bcma.h> | 8 | #include <linux/bcma/bcma.h> |
9 | #include <linux/ssb/ssb.h> | 9 | #include <linux/ssb/ssb.h> |
10 | #include <linux/completion.h> | ||
10 | #include <net/mac80211.h> | 11 | #include <net/mac80211.h> |
11 | 12 | ||
12 | #include "debugfs.h" | 13 | #include "debugfs.h" |
@@ -722,6 +723,10 @@ enum b43_firmware_file_type { | |||
722 | struct b43_request_fw_context { | 723 | struct b43_request_fw_context { |
723 | /* The device we are requesting the fw for. */ | 724 | /* The device we are requesting the fw for. */ |
724 | struct b43_wldev *dev; | 725 | struct b43_wldev *dev; |
726 | /* a completion event structure needed if this call is asynchronous */ | ||
727 | struct completion fw_load_complete; | ||
728 | /* a pointer to the firmware object */ | ||
729 | const struct firmware *blob; | ||
725 | /* The type of firmware to request. */ | 730 | /* The type of firmware to request. */ |
726 | enum b43_firmware_file_type req_type; | 731 | enum b43_firmware_file_type req_type; |
727 | /* Error messages for each firmware type. */ | 732 | /* Error messages for each firmware type. */ |
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 16ab280359bd..806e34c19281 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c | |||
@@ -2088,11 +2088,18 @@ static void b43_print_fw_helptext(struct b43_wl *wl, bool error) | |||
2088 | b43warn(wl, text); | 2088 | b43warn(wl, text); |
2089 | } | 2089 | } |
2090 | 2090 | ||
2091 | static void b43_fw_cb(const struct firmware *firmware, void *context) | ||
2092 | { | ||
2093 | struct b43_request_fw_context *ctx = context; | ||
2094 | |||
2095 | ctx->blob = firmware; | ||
2096 | complete(&ctx->fw_load_complete); | ||
2097 | } | ||
2098 | |||
2091 | int b43_do_request_fw(struct b43_request_fw_context *ctx, | 2099 | int b43_do_request_fw(struct b43_request_fw_context *ctx, |
2092 | const char *name, | 2100 | const char *name, |
2093 | struct b43_firmware_file *fw) | 2101 | struct b43_firmware_file *fw, bool async) |
2094 | { | 2102 | { |
2095 | const struct firmware *blob; | ||
2096 | struct b43_fw_header *hdr; | 2103 | struct b43_fw_header *hdr; |
2097 | u32 size; | 2104 | u32 size; |
2098 | int err; | 2105 | int err; |
@@ -2131,11 +2138,31 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx, | |||
2131 | B43_WARN_ON(1); | 2138 | B43_WARN_ON(1); |
2132 | return -ENOSYS; | 2139 | return -ENOSYS; |
2133 | } | 2140 | } |
2134 | err = request_firmware(&blob, ctx->fwname, ctx->dev->dev->dev); | 2141 | if (async) { |
2142 | /* do this part asynchronously */ | ||
2143 | init_completion(&ctx->fw_load_complete); | ||
2144 | err = request_firmware_nowait(THIS_MODULE, 1, ctx->fwname, | ||
2145 | ctx->dev->dev->dev, GFP_KERNEL, | ||
2146 | ctx, b43_fw_cb); | ||
2147 | if (err < 0) { | ||
2148 | pr_err("Unable to load firmware\n"); | ||
2149 | return err; | ||
2150 | } | ||
2151 | /* stall here until fw ready */ | ||
2152 | wait_for_completion(&ctx->fw_load_complete); | ||
2153 | if (ctx->blob) | ||
2154 | goto fw_ready; | ||
2155 | /* On some ARM systems, the async request will fail, but the next sync | ||
2156 | * request works. For this reason, we dall through here | ||
2157 | */ | ||
2158 | } | ||
2159 | err = request_firmware(&ctx->blob, ctx->fwname, | ||
2160 | ctx->dev->dev->dev); | ||
2135 | if (err == -ENOENT) { | 2161 | if (err == -ENOENT) { |
2136 | snprintf(ctx->errors[ctx->req_type], | 2162 | snprintf(ctx->errors[ctx->req_type], |
2137 | sizeof(ctx->errors[ctx->req_type]), | 2163 | sizeof(ctx->errors[ctx->req_type]), |
2138 | "Firmware file \"%s\" not found\n", ctx->fwname); | 2164 | "Firmware file \"%s\" not found\n", |
2165 | ctx->fwname); | ||
2139 | return err; | 2166 | return err; |
2140 | } else if (err) { | 2167 | } else if (err) { |
2141 | snprintf(ctx->errors[ctx->req_type], | 2168 | snprintf(ctx->errors[ctx->req_type], |
@@ -2144,14 +2171,15 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx, | |||
2144 | ctx->fwname, err); | 2171 | ctx->fwname, err); |
2145 | return err; | 2172 | return err; |
2146 | } | 2173 | } |
2147 | if (blob->size < sizeof(struct b43_fw_header)) | 2174 | fw_ready: |
2175 | if (ctx->blob->size < sizeof(struct b43_fw_header)) | ||
2148 | goto err_format; | 2176 | goto err_format; |
2149 | hdr = (struct b43_fw_header *)(blob->data); | 2177 | hdr = (struct b43_fw_header *)(ctx->blob->data); |
2150 | switch (hdr->type) { | 2178 | switch (hdr->type) { |
2151 | case B43_FW_TYPE_UCODE: | 2179 | case B43_FW_TYPE_UCODE: |
2152 | case B43_FW_TYPE_PCM: | 2180 | case B43_FW_TYPE_PCM: |
2153 | size = be32_to_cpu(hdr->size); | 2181 | size = be32_to_cpu(hdr->size); |
2154 | if (size != blob->size - sizeof(struct b43_fw_header)) | 2182 | if (size != ctx->blob->size - sizeof(struct b43_fw_header)) |
2155 | goto err_format; | 2183 | goto err_format; |
2156 | /* fallthrough */ | 2184 | /* fallthrough */ |
2157 | case B43_FW_TYPE_IV: | 2185 | case B43_FW_TYPE_IV: |
@@ -2162,7 +2190,7 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx, | |||
2162 | goto err_format; | 2190 | goto err_format; |
2163 | } | 2191 | } |
2164 | 2192 | ||
2165 | fw->data = blob; | 2193 | fw->data = ctx->blob; |
2166 | fw->filename = name; | 2194 | fw->filename = name; |
2167 | fw->type = ctx->req_type; | 2195 | fw->type = ctx->req_type; |
2168 | 2196 | ||
@@ -2172,7 +2200,7 @@ err_format: | |||
2172 | snprintf(ctx->errors[ctx->req_type], | 2200 | snprintf(ctx->errors[ctx->req_type], |
2173 | sizeof(ctx->errors[ctx->req_type]), | 2201 | sizeof(ctx->errors[ctx->req_type]), |
2174 | "Firmware file \"%s\" format error.\n", ctx->fwname); | 2202 | "Firmware file \"%s\" format error.\n", ctx->fwname); |
2175 | release_firmware(blob); | 2203 | release_firmware(ctx->blob); |
2176 | 2204 | ||
2177 | return -EPROTO; | 2205 | return -EPROTO; |
2178 | } | 2206 | } |
@@ -2223,7 +2251,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx) | |||
2223 | goto err_no_ucode; | 2251 | goto err_no_ucode; |
2224 | } | 2252 | } |
2225 | } | 2253 | } |
2226 | err = b43_do_request_fw(ctx, filename, &fw->ucode); | 2254 | err = b43_do_request_fw(ctx, filename, &fw->ucode, true); |
2227 | if (err) | 2255 | if (err) |
2228 | goto err_load; | 2256 | goto err_load; |
2229 | 2257 | ||
@@ -2235,7 +2263,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx) | |||
2235 | else | 2263 | else |
2236 | goto err_no_pcm; | 2264 | goto err_no_pcm; |
2237 | fw->pcm_request_failed = false; | 2265 | fw->pcm_request_failed = false; |
2238 | err = b43_do_request_fw(ctx, filename, &fw->pcm); | 2266 | err = b43_do_request_fw(ctx, filename, &fw->pcm, false); |
2239 | if (err == -ENOENT) { | 2267 | if (err == -ENOENT) { |
2240 | /* We did not find a PCM file? Not fatal, but | 2268 | /* We did not find a PCM file? Not fatal, but |
2241 | * core rev <= 10 must do without hwcrypto then. */ | 2269 | * core rev <= 10 must do without hwcrypto then. */ |
@@ -2296,7 +2324,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx) | |||
2296 | default: | 2324 | default: |
2297 | goto err_no_initvals; | 2325 | goto err_no_initvals; |
2298 | } | 2326 | } |
2299 | err = b43_do_request_fw(ctx, filename, &fw->initvals); | 2327 | err = b43_do_request_fw(ctx, filename, &fw->initvals, false); |
2300 | if (err) | 2328 | if (err) |
2301 | goto err_load; | 2329 | goto err_load; |
2302 | 2330 | ||
@@ -2355,7 +2383,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx) | |||
2355 | default: | 2383 | default: |
2356 | goto err_no_initvals; | 2384 | goto err_no_initvals; |
2357 | } | 2385 | } |
2358 | err = b43_do_request_fw(ctx, filename, &fw->initvals_band); | 2386 | err = b43_do_request_fw(ctx, filename, &fw->initvals_band, false); |
2359 | if (err) | 2387 | if (err) |
2360 | goto err_load; | 2388 | goto err_load; |
2361 | 2389 | ||
diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h index 8c684cd33529..abac25ee958d 100644 --- a/drivers/net/wireless/b43/main.h +++ b/drivers/net/wireless/b43/main.h | |||
@@ -137,9 +137,8 @@ void b43_mac_phy_clock_set(struct b43_wldev *dev, bool on); | |||
137 | 137 | ||
138 | 138 | ||
139 | struct b43_request_fw_context; | 139 | struct b43_request_fw_context; |
140 | int b43_do_request_fw(struct b43_request_fw_context *ctx, | 140 | int b43_do_request_fw(struct b43_request_fw_context *ctx, const char *name, |
141 | const char *name, | 141 | struct b43_firmware_file *fw, bool async); |
142 | struct b43_firmware_file *fw); | ||
143 | void b43_do_release_fw(struct b43_firmware_file *fw); | 142 | void b43_do_release_fw(struct b43_firmware_file *fw); |
144 | 143 | ||
145 | #endif /* B43_MAIN_H_ */ | 144 | #endif /* B43_MAIN_H_ */ |
diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c index d604b4036a76..3726cd6fcd75 100644 --- a/drivers/net/wireless/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/iwlegacy/3945-mac.c | |||
@@ -3273,7 +3273,7 @@ il3945_store_measurement(struct device *d, struct device_attribute *attr, | |||
3273 | 3273 | ||
3274 | if (count) { | 3274 | if (count) { |
3275 | char *p = buffer; | 3275 | char *p = buffer; |
3276 | strncpy(buffer, buf, min(sizeof(buffer), count)); | 3276 | strlcpy(buffer, buf, sizeof(buffer)); |
3277 | channel = simple_strtoul(p, NULL, 0); | 3277 | channel = simple_strtoul(p, NULL, 0); |
3278 | if (channel) | 3278 | if (channel) |
3279 | params.channel = channel; | 3279 | params.channel = channel; |
diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c index da21328ca8ed..a790599fe2c2 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/iwlwifi/dvm/tx.c | |||
@@ -1151,13 +1151,6 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, | |||
1151 | next_reclaimed = ssn; | 1151 | next_reclaimed = ssn; |
1152 | } | 1152 | } |
1153 | 1153 | ||
1154 | if (tid != IWL_TID_NON_QOS) { | ||
1155 | priv->tid_data[sta_id][tid].next_reclaimed = | ||
1156 | next_reclaimed; | ||
1157 | IWL_DEBUG_TX_REPLY(priv, "Next reclaimed packet:%d\n", | ||
1158 | next_reclaimed); | ||
1159 | } | ||
1160 | |||
1161 | iwl_trans_reclaim(priv->trans, txq_id, ssn, &skbs); | 1154 | iwl_trans_reclaim(priv->trans, txq_id, ssn, &skbs); |
1162 | 1155 | ||
1163 | iwlagn_check_ratid_empty(priv, sta_id, tid); | 1156 | iwlagn_check_ratid_empty(priv, sta_id, tid); |
@@ -1208,11 +1201,28 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, | |||
1208 | if (!is_agg) | 1201 | if (!is_agg) |
1209 | iwlagn_non_agg_tx_status(priv, ctx, hdr->addr1); | 1202 | iwlagn_non_agg_tx_status(priv, ctx, hdr->addr1); |
1210 | 1203 | ||
1204 | /* | ||
1205 | * W/A for FW bug - the seq_ctl isn't updated when the | ||
1206 | * queues are flushed. Fetch it from the packet itself | ||
1207 | */ | ||
1208 | if (!is_agg && status == TX_STATUS_FAIL_FIFO_FLUSHED) { | ||
1209 | next_reclaimed = le16_to_cpu(hdr->seq_ctrl); | ||
1210 | next_reclaimed = | ||
1211 | SEQ_TO_SN(next_reclaimed + 0x10); | ||
1212 | } | ||
1213 | |||
1211 | is_offchannel_skb = | 1214 | is_offchannel_skb = |
1212 | (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN); | 1215 | (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN); |
1213 | freed++; | 1216 | freed++; |
1214 | } | 1217 | } |
1215 | 1218 | ||
1219 | if (tid != IWL_TID_NON_QOS) { | ||
1220 | priv->tid_data[sta_id][tid].next_reclaimed = | ||
1221 | next_reclaimed; | ||
1222 | IWL_DEBUG_TX_REPLY(priv, "Next reclaimed packet:%d\n", | ||
1223 | next_reclaimed); | ||
1224 | } | ||
1225 | |||
1216 | WARN_ON(!is_agg && freed != 1); | 1226 | WARN_ON(!is_agg && freed != 1); |
1217 | 1227 | ||
1218 | /* | 1228 | /* |
diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index dad4c4aad91f..8389cd38338b 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c | |||
@@ -1166,6 +1166,7 @@ static irqreturn_t iwl_pcie_isr(int irq, void *data) | |||
1166 | else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) && | 1166 | else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) && |
1167 | !trans_pcie->inta) | 1167 | !trans_pcie->inta) |
1168 | iwl_enable_interrupts(trans); | 1168 | iwl_enable_interrupts(trans); |
1169 | return IRQ_HANDLED; | ||
1169 | 1170 | ||
1170 | none: | 1171 | none: |
1171 | /* re-enable interrupts here since we don't have anything to service. */ | 1172 | /* re-enable interrupts here since we don't have anything to service. */ |
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index a875499f8945..efe525be27dd 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c | |||
@@ -1709,7 +1709,7 @@ static int mwifiex_set_ibss_params(struct mwifiex_private *priv, | |||
1709 | NL80211_CHAN_NO_HT) | 1709 | NL80211_CHAN_NO_HT) |
1710 | config_bands |= BAND_GN; | 1710 | config_bands |= BAND_GN; |
1711 | } else { | 1711 | } else { |
1712 | if (cfg80211_get_chandef_type(¶ms->chandef) != | 1712 | if (cfg80211_get_chandef_type(¶ms->chandef) == |
1713 | NL80211_CHAN_NO_HT) | 1713 | NL80211_CHAN_NO_HT) |
1714 | config_bands = BAND_A; | 1714 | config_bands = BAND_A; |
1715 | else | 1715 | else |
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index cb682561c438..60e88b58039d 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c | |||
@@ -56,7 +56,6 @@ int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist, | |||
56 | */ | 56 | */ |
57 | int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter) | 57 | int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter) |
58 | { | 58 | { |
59 | bool cancel_flag = false; | ||
60 | int status; | 59 | int status; |
61 | struct cmd_ctrl_node *cmd_queued; | 60 | struct cmd_ctrl_node *cmd_queued; |
62 | 61 | ||
@@ -70,14 +69,11 @@ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter) | |||
70 | atomic_inc(&adapter->cmd_pending); | 69 | atomic_inc(&adapter->cmd_pending); |
71 | 70 | ||
72 | /* Wait for completion */ | 71 | /* Wait for completion */ |
73 | wait_event_interruptible(adapter->cmd_wait_q.wait, | 72 | status = wait_event_interruptible(adapter->cmd_wait_q.wait, |
74 | *(cmd_queued->condition)); | 73 | *(cmd_queued->condition)); |
75 | if (!*(cmd_queued->condition)) | 74 | if (status) { |
76 | cancel_flag = true; | 75 | dev_err(adapter->dev, "cmd_wait_q terminated: %d\n", status); |
77 | 76 | return status; | |
78 | if (cancel_flag) { | ||
79 | mwifiex_cancel_pending_ioctl(adapter); | ||
80 | dev_dbg(adapter->dev, "cmd cancel\n"); | ||
81 | } | 77 | } |
82 | 78 | ||
83 | status = adapter->cmd_wait_q.status; | 79 | status = adapter->cmd_wait_q.status; |
@@ -496,8 +492,11 @@ int mwifiex_enable_hs(struct mwifiex_adapter *adapter) | |||
496 | return false; | 492 | return false; |
497 | } | 493 | } |
498 | 494 | ||
499 | wait_event_interruptible(adapter->hs_activate_wait_q, | 495 | if (wait_event_interruptible(adapter->hs_activate_wait_q, |
500 | adapter->hs_activate_wait_q_woken); | 496 | adapter->hs_activate_wait_q_woken)) { |
497 | dev_err(adapter->dev, "hs_activate_wait_q terminated\n"); | ||
498 | return false; | ||
499 | } | ||
501 | 500 | ||
502 | return true; | 501 | return true; |
503 | } | 502 | } |
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index f221b95b90b3..83564d36e801 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c | |||
@@ -4250,9 +4250,11 @@ static int mwl8k_cmd_update_stadb_add(struct ieee80211_hw *hw, | |||
4250 | p->amsdu_enabled = 0; | 4250 | p->amsdu_enabled = 0; |
4251 | 4251 | ||
4252 | rc = mwl8k_post_cmd(hw, &cmd->header); | 4252 | rc = mwl8k_post_cmd(hw, &cmd->header); |
4253 | if (!rc) | ||
4254 | rc = p->station_id; | ||
4253 | kfree(cmd); | 4255 | kfree(cmd); |
4254 | 4256 | ||
4255 | return rc ? rc : p->station_id; | 4257 | return rc; |
4256 | } | 4258 | } |
4257 | 4259 | ||
4258 | static int mwl8k_cmd_update_stadb_del(struct ieee80211_hw *hw, | 4260 | static int mwl8k_cmd_update_stadb_del(struct ieee80211_hw *hw, |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c index 1d5d3604e3e0..246e5352f2e1 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c | |||
@@ -692,7 +692,7 @@ u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw) | |||
692 | if (!(is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) { | 692 | if (!(is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) { |
693 | rtl92c_phy_sw_chnl_callback(hw); | 693 | rtl92c_phy_sw_chnl_callback(hw); |
694 | RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD, | 694 | RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD, |
695 | "sw_chnl_inprogress false schdule workitem\n"); | 695 | "sw_chnl_inprogress false schedule workitem\n"); |
696 | rtlphy->sw_chnl_inprogress = false; | 696 | rtlphy->sw_chnl_inprogress = false; |
697 | } else { | 697 | } else { |
698 | RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD, | 698 | RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD, |
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c b/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c index 39cc7938eedf..3d8536bb0d2b 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c | |||
@@ -1106,7 +1106,7 @@ u8 rtl8723ae_phy_sw_chnl(struct ieee80211_hw *hw) | |||
1106 | if (!(is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) { | 1106 | if (!(is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) { |
1107 | rtl8723ae_phy_sw_chnl_callback(hw); | 1107 | rtl8723ae_phy_sw_chnl_callback(hw); |
1108 | RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD, | 1108 | RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD, |
1109 | "sw_chnl_inprogress false schdule workitem\n"); | 1109 | "sw_chnl_inprogress false schedule workitem\n"); |
1110 | rtlphy->sw_chnl_inprogress = false; | 1110 | rtlphy->sw_chnl_inprogress = false; |
1111 | } else { | 1111 | } else { |
1112 | RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD, | 1112 | RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD, |
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 26ffd3e3fb74..2c113de94323 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h | |||
@@ -44,7 +44,6 @@ extern bool pciehp_poll_mode; | |||
44 | extern int pciehp_poll_time; | 44 | extern int pciehp_poll_time; |
45 | extern bool pciehp_debug; | 45 | extern bool pciehp_debug; |
46 | extern bool pciehp_force; | 46 | extern bool pciehp_force; |
47 | extern struct workqueue_struct *pciehp_wq; | ||
48 | 47 | ||
49 | #define dbg(format, arg...) \ | 48 | #define dbg(format, arg...) \ |
50 | do { \ | 49 | do { \ |
@@ -78,6 +77,7 @@ struct slot { | |||
78 | struct hotplug_slot *hotplug_slot; | 77 | struct hotplug_slot *hotplug_slot; |
79 | struct delayed_work work; /* work for button event */ | 78 | struct delayed_work work; /* work for button event */ |
80 | struct mutex lock; | 79 | struct mutex lock; |
80 | struct workqueue_struct *wq; | ||
81 | }; | 81 | }; |
82 | 82 | ||
83 | struct event_info { | 83 | struct event_info { |
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index 916bf4f53aba..939bd1d4b5b1 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c | |||
@@ -42,7 +42,6 @@ bool pciehp_debug; | |||
42 | bool pciehp_poll_mode; | 42 | bool pciehp_poll_mode; |
43 | int pciehp_poll_time; | 43 | int pciehp_poll_time; |
44 | bool pciehp_force; | 44 | bool pciehp_force; |
45 | struct workqueue_struct *pciehp_wq; | ||
46 | 45 | ||
47 | #define DRIVER_VERSION "0.4" | 46 | #define DRIVER_VERSION "0.4" |
48 | #define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>" | 47 | #define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>" |
@@ -340,18 +339,13 @@ static int __init pcied_init(void) | |||
340 | { | 339 | { |
341 | int retval = 0; | 340 | int retval = 0; |
342 | 341 | ||
343 | pciehp_wq = alloc_workqueue("pciehp", 0, 0); | ||
344 | if (!pciehp_wq) | ||
345 | return -ENOMEM; | ||
346 | |||
347 | pciehp_firmware_init(); | 342 | pciehp_firmware_init(); |
348 | retval = pcie_port_service_register(&hpdriver_portdrv); | 343 | retval = pcie_port_service_register(&hpdriver_portdrv); |
349 | dbg("pcie_port_service_register = %d\n", retval); | 344 | dbg("pcie_port_service_register = %d\n", retval); |
350 | info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); | 345 | info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); |
351 | if (retval) { | 346 | if (retval) |
352 | destroy_workqueue(pciehp_wq); | ||
353 | dbg("Failure to register service\n"); | 347 | dbg("Failure to register service\n"); |
354 | } | 348 | |
355 | return retval; | 349 | return retval; |
356 | } | 350 | } |
357 | 351 | ||
@@ -359,7 +353,6 @@ static void __exit pcied_cleanup(void) | |||
359 | { | 353 | { |
360 | dbg("unload_pciehpd()\n"); | 354 | dbg("unload_pciehpd()\n"); |
361 | pcie_port_service_unregister(&hpdriver_portdrv); | 355 | pcie_port_service_unregister(&hpdriver_portdrv); |
362 | destroy_workqueue(pciehp_wq); | ||
363 | info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n"); | 356 | info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n"); |
364 | } | 357 | } |
365 | 358 | ||
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index 27f44295a657..38f018679175 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c | |||
@@ -49,7 +49,7 @@ static int queue_interrupt_event(struct slot *p_slot, u32 event_type) | |||
49 | info->p_slot = p_slot; | 49 | info->p_slot = p_slot; |
50 | INIT_WORK(&info->work, interrupt_event_handler); | 50 | INIT_WORK(&info->work, interrupt_event_handler); |
51 | 51 | ||
52 | queue_work(pciehp_wq, &info->work); | 52 | queue_work(p_slot->wq, &info->work); |
53 | 53 | ||
54 | return 0; | 54 | return 0; |
55 | } | 55 | } |
@@ -344,7 +344,7 @@ void pciehp_queue_pushbutton_work(struct work_struct *work) | |||
344 | kfree(info); | 344 | kfree(info); |
345 | goto out; | 345 | goto out; |
346 | } | 346 | } |
347 | queue_work(pciehp_wq, &info->work); | 347 | queue_work(p_slot->wq, &info->work); |
348 | out: | 348 | out: |
349 | mutex_unlock(&p_slot->lock); | 349 | mutex_unlock(&p_slot->lock); |
350 | } | 350 | } |
@@ -377,7 +377,7 @@ static void handle_button_press_event(struct slot *p_slot) | |||
377 | if (ATTN_LED(ctrl)) | 377 | if (ATTN_LED(ctrl)) |
378 | pciehp_set_attention_status(p_slot, 0); | 378 | pciehp_set_attention_status(p_slot, 0); |
379 | 379 | ||
380 | queue_delayed_work(pciehp_wq, &p_slot->work, 5*HZ); | 380 | queue_delayed_work(p_slot->wq, &p_slot->work, 5*HZ); |
381 | break; | 381 | break; |
382 | case BLINKINGOFF_STATE: | 382 | case BLINKINGOFF_STATE: |
383 | case BLINKINGON_STATE: | 383 | case BLINKINGON_STATE: |
@@ -439,7 +439,7 @@ static void handle_surprise_event(struct slot *p_slot) | |||
439 | else | 439 | else |
440 | p_slot->state = POWERON_STATE; | 440 | p_slot->state = POWERON_STATE; |
441 | 441 | ||
442 | queue_work(pciehp_wq, &info->work); | 442 | queue_work(p_slot->wq, &info->work); |
443 | } | 443 | } |
444 | 444 | ||
445 | static void interrupt_event_handler(struct work_struct *work) | 445 | static void interrupt_event_handler(struct work_struct *work) |
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 13b2eaf7ba43..5127f3f41821 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c | |||
@@ -773,23 +773,32 @@ static void pcie_shutdown_notification(struct controller *ctrl) | |||
773 | static int pcie_init_slot(struct controller *ctrl) | 773 | static int pcie_init_slot(struct controller *ctrl) |
774 | { | 774 | { |
775 | struct slot *slot; | 775 | struct slot *slot; |
776 | char name[32]; | ||
776 | 777 | ||
777 | slot = kzalloc(sizeof(*slot), GFP_KERNEL); | 778 | slot = kzalloc(sizeof(*slot), GFP_KERNEL); |
778 | if (!slot) | 779 | if (!slot) |
779 | return -ENOMEM; | 780 | return -ENOMEM; |
780 | 781 | ||
782 | snprintf(name, sizeof(name), "pciehp-%u", PSN(ctrl)); | ||
783 | slot->wq = alloc_workqueue(name, 0, 0); | ||
784 | if (!slot->wq) | ||
785 | goto abort; | ||
786 | |||
781 | slot->ctrl = ctrl; | 787 | slot->ctrl = ctrl; |
782 | mutex_init(&slot->lock); | 788 | mutex_init(&slot->lock); |
783 | INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work); | 789 | INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work); |
784 | ctrl->slot = slot; | 790 | ctrl->slot = slot; |
785 | return 0; | 791 | return 0; |
792 | abort: | ||
793 | kfree(slot); | ||
794 | return -ENOMEM; | ||
786 | } | 795 | } |
787 | 796 | ||
788 | static void pcie_cleanup_slot(struct controller *ctrl) | 797 | static void pcie_cleanup_slot(struct controller *ctrl) |
789 | { | 798 | { |
790 | struct slot *slot = ctrl->slot; | 799 | struct slot *slot = ctrl->slot; |
791 | cancel_delayed_work(&slot->work); | 800 | cancel_delayed_work(&slot->work); |
792 | flush_workqueue(pciehp_wq); | 801 | destroy_workqueue(slot->wq); |
793 | kfree(slot); | 802 | kfree(slot); |
794 | } | 803 | } |
795 | 804 | ||
diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h index ca64932e658b..b849f995075a 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h | |||
@@ -46,8 +46,6 @@ | |||
46 | extern bool shpchp_poll_mode; | 46 | extern bool shpchp_poll_mode; |
47 | extern int shpchp_poll_time; | 47 | extern int shpchp_poll_time; |
48 | extern bool shpchp_debug; | 48 | extern bool shpchp_debug; |
49 | extern struct workqueue_struct *shpchp_wq; | ||
50 | extern struct workqueue_struct *shpchp_ordered_wq; | ||
51 | 49 | ||
52 | #define dbg(format, arg...) \ | 50 | #define dbg(format, arg...) \ |
53 | do { \ | 51 | do { \ |
@@ -91,6 +89,7 @@ struct slot { | |||
91 | struct list_head slot_list; | 89 | struct list_head slot_list; |
92 | struct delayed_work work; /* work for button event */ | 90 | struct delayed_work work; /* work for button event */ |
93 | struct mutex lock; | 91 | struct mutex lock; |
92 | struct workqueue_struct *wq; | ||
94 | u8 hp_slot; | 93 | u8 hp_slot; |
95 | }; | 94 | }; |
96 | 95 | ||
diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index b6de307248e4..3100c52c837c 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c | |||
@@ -39,8 +39,6 @@ | |||
39 | bool shpchp_debug; | 39 | bool shpchp_debug; |
40 | bool shpchp_poll_mode; | 40 | bool shpchp_poll_mode; |
41 | int shpchp_poll_time; | 41 | int shpchp_poll_time; |
42 | struct workqueue_struct *shpchp_wq; | ||
43 | struct workqueue_struct *shpchp_ordered_wq; | ||
44 | 42 | ||
45 | #define DRIVER_VERSION "0.4" | 43 | #define DRIVER_VERSION "0.4" |
46 | #define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>" | 44 | #define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>" |
@@ -129,6 +127,14 @@ static int init_slots(struct controller *ctrl) | |||
129 | slot->device = ctrl->slot_device_offset + i; | 127 | slot->device = ctrl->slot_device_offset + i; |
130 | slot->hpc_ops = ctrl->hpc_ops; | 128 | slot->hpc_ops = ctrl->hpc_ops; |
131 | slot->number = ctrl->first_slot + (ctrl->slot_num_inc * i); | 129 | slot->number = ctrl->first_slot + (ctrl->slot_num_inc * i); |
130 | |||
131 | snprintf(name, sizeof(name), "shpchp-%d", slot->number); | ||
132 | slot->wq = alloc_workqueue(name, 0, 0); | ||
133 | if (!slot->wq) { | ||
134 | retval = -ENOMEM; | ||
135 | goto error_info; | ||
136 | } | ||
137 | |||
132 | mutex_init(&slot->lock); | 138 | mutex_init(&slot->lock); |
133 | INIT_DELAYED_WORK(&slot->work, shpchp_queue_pushbutton_work); | 139 | INIT_DELAYED_WORK(&slot->work, shpchp_queue_pushbutton_work); |
134 | 140 | ||
@@ -148,7 +154,7 @@ static int init_slots(struct controller *ctrl) | |||
148 | if (retval) { | 154 | if (retval) { |
149 | ctrl_err(ctrl, "pci_hp_register failed with error %d\n", | 155 | ctrl_err(ctrl, "pci_hp_register failed with error %d\n", |
150 | retval); | 156 | retval); |
151 | goto error_info; | 157 | goto error_slotwq; |
152 | } | 158 | } |
153 | 159 | ||
154 | get_power_status(hotplug_slot, &info->power_status); | 160 | get_power_status(hotplug_slot, &info->power_status); |
@@ -160,6 +166,8 @@ static int init_slots(struct controller *ctrl) | |||
160 | } | 166 | } |
161 | 167 | ||
162 | return 0; | 168 | return 0; |
169 | error_slotwq: | ||
170 | destroy_workqueue(slot->wq); | ||
163 | error_info: | 171 | error_info: |
164 | kfree(info); | 172 | kfree(info); |
165 | error_hpslot: | 173 | error_hpslot: |
@@ -180,8 +188,7 @@ void cleanup_slots(struct controller *ctrl) | |||
180 | slot = list_entry(tmp, struct slot, slot_list); | 188 | slot = list_entry(tmp, struct slot, slot_list); |
181 | list_del(&slot->slot_list); | 189 | list_del(&slot->slot_list); |
182 | cancel_delayed_work(&slot->work); | 190 | cancel_delayed_work(&slot->work); |
183 | flush_workqueue(shpchp_wq); | 191 | destroy_workqueue(slot->wq); |
184 | flush_workqueue(shpchp_ordered_wq); | ||
185 | pci_hp_deregister(slot->hotplug_slot); | 192 | pci_hp_deregister(slot->hotplug_slot); |
186 | } | 193 | } |
187 | } | 194 | } |
@@ -364,25 +371,12 @@ static struct pci_driver shpc_driver = { | |||
364 | 371 | ||
365 | static int __init shpcd_init(void) | 372 | static int __init shpcd_init(void) |
366 | { | 373 | { |
367 | int retval = 0; | 374 | int retval; |
368 | |||
369 | shpchp_wq = alloc_ordered_workqueue("shpchp", 0); | ||
370 | if (!shpchp_wq) | ||
371 | return -ENOMEM; | ||
372 | |||
373 | shpchp_ordered_wq = alloc_ordered_workqueue("shpchp_ordered", 0); | ||
374 | if (!shpchp_ordered_wq) { | ||
375 | destroy_workqueue(shpchp_wq); | ||
376 | return -ENOMEM; | ||
377 | } | ||
378 | 375 | ||
379 | retval = pci_register_driver(&shpc_driver); | 376 | retval = pci_register_driver(&shpc_driver); |
380 | dbg("%s: pci_register_driver = %d\n", __func__, retval); | 377 | dbg("%s: pci_register_driver = %d\n", __func__, retval); |
381 | info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); | 378 | info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); |
382 | if (retval) { | 379 | |
383 | destroy_workqueue(shpchp_ordered_wq); | ||
384 | destroy_workqueue(shpchp_wq); | ||
385 | } | ||
386 | return retval; | 380 | return retval; |
387 | } | 381 | } |
388 | 382 | ||
@@ -390,8 +384,6 @@ static void __exit shpcd_cleanup(void) | |||
390 | { | 384 | { |
391 | dbg("unload_shpchpd()\n"); | 385 | dbg("unload_shpchpd()\n"); |
392 | pci_unregister_driver(&shpc_driver); | 386 | pci_unregister_driver(&shpc_driver); |
393 | destroy_workqueue(shpchp_ordered_wq); | ||
394 | destroy_workqueue(shpchp_wq); | ||
395 | info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n"); | 387 | info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n"); |
396 | } | 388 | } |
397 | 389 | ||
diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c index f9b5a52e4115..58499277903a 100644 --- a/drivers/pci/hotplug/shpchp_ctrl.c +++ b/drivers/pci/hotplug/shpchp_ctrl.c | |||
@@ -51,7 +51,7 @@ static int queue_interrupt_event(struct slot *p_slot, u32 event_type) | |||
51 | info->p_slot = p_slot; | 51 | info->p_slot = p_slot; |
52 | INIT_WORK(&info->work, interrupt_event_handler); | 52 | INIT_WORK(&info->work, interrupt_event_handler); |
53 | 53 | ||
54 | queue_work(shpchp_wq, &info->work); | 54 | queue_work(p_slot->wq, &info->work); |
55 | 55 | ||
56 | return 0; | 56 | return 0; |
57 | } | 57 | } |
@@ -453,7 +453,7 @@ void shpchp_queue_pushbutton_work(struct work_struct *work) | |||
453 | kfree(info); | 453 | kfree(info); |
454 | goto out; | 454 | goto out; |
455 | } | 455 | } |
456 | queue_work(shpchp_ordered_wq, &info->work); | 456 | queue_work(p_slot->wq, &info->work); |
457 | out: | 457 | out: |
458 | mutex_unlock(&p_slot->lock); | 458 | mutex_unlock(&p_slot->lock); |
459 | } | 459 | } |
@@ -501,7 +501,7 @@ static void handle_button_press_event(struct slot *p_slot) | |||
501 | p_slot->hpc_ops->green_led_blink(p_slot); | 501 | p_slot->hpc_ops->green_led_blink(p_slot); |
502 | p_slot->hpc_ops->set_attention_status(p_slot, 0); | 502 | p_slot->hpc_ops->set_attention_status(p_slot, 0); |
503 | 503 | ||
504 | queue_delayed_work(shpchp_wq, &p_slot->work, 5*HZ); | 504 | queue_delayed_work(p_slot->wq, &p_slot->work, 5*HZ); |
505 | break; | 505 | break; |
506 | case BLINKINGOFF_STATE: | 506 | case BLINKINGOFF_STATE: |
507 | case BLINKINGON_STATE: | 507 | case BLINKINGON_STATE: |
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index bafd2bbcaf65..c18e5bf444fa 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c | |||
@@ -739,7 +739,7 @@ EXPORT_SYMBOL_GPL(pci_num_vf); | |||
739 | /** | 739 | /** |
740 | * pci_sriov_set_totalvfs -- reduce the TotalVFs available | 740 | * pci_sriov_set_totalvfs -- reduce the TotalVFs available |
741 | * @dev: the PCI PF device | 741 | * @dev: the PCI PF device |
742 | * numvfs: number that should be used for TotalVFs supported | 742 | * @numvfs: number that should be used for TotalVFs supported |
743 | * | 743 | * |
744 | * Should be called from PF driver's probe routine with | 744 | * Should be called from PF driver's probe routine with |
745 | * device's mutex held. | 745 | * device's mutex held. |
diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig index 6c8bc5809787..fde4a32a0295 100644 --- a/drivers/pci/pcie/Kconfig +++ b/drivers/pci/pcie/Kconfig | |||
@@ -82,4 +82,4 @@ endchoice | |||
82 | 82 | ||
83 | config PCIE_PME | 83 | config PCIE_PME |
84 | def_bool y | 84 | def_bool y |
85 | depends on PCIEPORTBUS && PM_RUNTIME && EXPERIMENTAL && ACPI | 85 | depends on PCIEPORTBUS && PM_RUNTIME && ACPI |
diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c index 421bbc5fee32..564d97f94b6c 100644 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ b/drivers/pci/pcie/aer/aerdrv_core.c | |||
@@ -630,6 +630,7 @@ static void aer_recover_work_func(struct work_struct *work) | |||
630 | continue; | 630 | continue; |
631 | } | 631 | } |
632 | do_recovery(pdev, entry.severity); | 632 | do_recovery(pdev, entry.severity); |
633 | pci_dev_put(pdev); | ||
633 | } | 634 | } |
634 | } | 635 | } |
635 | #endif | 636 | #endif |
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index b52630b8eada..8474b6a4fc9b 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c | |||
@@ -771,6 +771,9 @@ void pcie_clear_aspm(struct pci_bus *bus) | |||
771 | { | 771 | { |
772 | struct pci_dev *child; | 772 | struct pci_dev *child; |
773 | 773 | ||
774 | if (aspm_force) | ||
775 | return; | ||
776 | |||
774 | /* | 777 | /* |
775 | * Clear any ASPM setup that the firmware has carried out on this bus | 778 | * Clear any ASPM setup that the firmware has carried out on this bus |
776 | */ | 779 | */ |
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 06f4eb7ab87e..afed7018a2b5 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c | |||
@@ -125,8 +125,11 @@ static const struct key_entry acer_wmi_keymap[] = { | |||
125 | {KE_IGNORE, 0x63, {KEY_BRIGHTNESSDOWN} }, | 125 | {KE_IGNORE, 0x63, {KEY_BRIGHTNESSDOWN} }, |
126 | {KE_KEY, 0x64, {KEY_SWITCHVIDEOMODE} }, /* Display Switch */ | 126 | {KE_KEY, 0x64, {KEY_SWITCHVIDEOMODE} }, /* Display Switch */ |
127 | {KE_IGNORE, 0x81, {KEY_SLEEP} }, | 127 | {KE_IGNORE, 0x81, {KEY_SLEEP} }, |
128 | {KE_KEY, 0x82, {KEY_TOUCHPAD_TOGGLE} }, /* Touch Pad On/Off */ | 128 | {KE_KEY, 0x82, {KEY_TOUCHPAD_TOGGLE} }, /* Touch Pad Toggle */ |
129 | {KE_KEY, KEY_TOUCHPAD_ON, {KEY_TOUCHPAD_ON} }, | ||
130 | {KE_KEY, KEY_TOUCHPAD_OFF, {KEY_TOUCHPAD_OFF} }, | ||
129 | {KE_IGNORE, 0x83, {KEY_TOUCHPAD_TOGGLE} }, | 131 | {KE_IGNORE, 0x83, {KEY_TOUCHPAD_TOGGLE} }, |
132 | {KE_KEY, 0x85, {KEY_TOUCHPAD_TOGGLE} }, | ||
130 | {KE_END, 0} | 133 | {KE_END, 0} |
131 | }; | 134 | }; |
132 | 135 | ||
@@ -147,6 +150,7 @@ struct event_return_value { | |||
147 | #define ACER_WMID3_GDS_THREEG (1<<6) /* 3G */ | 150 | #define ACER_WMID3_GDS_THREEG (1<<6) /* 3G */ |
148 | #define ACER_WMID3_GDS_WIMAX (1<<7) /* WiMAX */ | 151 | #define ACER_WMID3_GDS_WIMAX (1<<7) /* WiMAX */ |
149 | #define ACER_WMID3_GDS_BLUETOOTH (1<<11) /* BT */ | 152 | #define ACER_WMID3_GDS_BLUETOOTH (1<<11) /* BT */ |
153 | #define ACER_WMID3_GDS_TOUCHPAD (1<<1) /* Touchpad */ | ||
150 | 154 | ||
151 | struct lm_input_params { | 155 | struct lm_input_params { |
152 | u8 function_num; /* Function Number */ | 156 | u8 function_num; /* Function Number */ |
@@ -875,7 +879,7 @@ WMI_execute_u32(u32 method_id, u32 in, u32 *out) | |||
875 | struct acpi_buffer input = { (acpi_size) sizeof(u32), (void *)(&in) }; | 879 | struct acpi_buffer input = { (acpi_size) sizeof(u32), (void *)(&in) }; |
876 | struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL }; | 880 | struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL }; |
877 | union acpi_object *obj; | 881 | union acpi_object *obj; |
878 | u32 tmp; | 882 | u32 tmp = 0; |
879 | acpi_status status; | 883 | acpi_status status; |
880 | 884 | ||
881 | status = wmi_evaluate_method(WMID_GUID1, 1, method_id, &input, &result); | 885 | status = wmi_evaluate_method(WMID_GUID1, 1, method_id, &input, &result); |
@@ -884,14 +888,14 @@ WMI_execute_u32(u32 method_id, u32 in, u32 *out) | |||
884 | return status; | 888 | return status; |
885 | 889 | ||
886 | obj = (union acpi_object *) result.pointer; | 890 | obj = (union acpi_object *) result.pointer; |
887 | if (obj && obj->type == ACPI_TYPE_BUFFER && | 891 | if (obj) { |
888 | (obj->buffer.length == sizeof(u32) || | 892 | if (obj->type == ACPI_TYPE_BUFFER && |
889 | obj->buffer.length == sizeof(u64))) { | 893 | (obj->buffer.length == sizeof(u32) || |
890 | tmp = *((u32 *) obj->buffer.pointer); | 894 | obj->buffer.length == sizeof(u64))) { |
891 | } else if (obj->type == ACPI_TYPE_INTEGER) { | 895 | tmp = *((u32 *) obj->buffer.pointer); |
892 | tmp = (u32) obj->integer.value; | 896 | } else if (obj->type == ACPI_TYPE_INTEGER) { |
893 | } else { | 897 | tmp = (u32) obj->integer.value; |
894 | tmp = 0; | 898 | } |
895 | } | 899 | } |
896 | 900 | ||
897 | if (out) | 901 | if (out) |
@@ -1193,12 +1197,14 @@ static acpi_status WMID_set_capabilities(void) | |||
1193 | return status; | 1197 | return status; |
1194 | 1198 | ||
1195 | obj = (union acpi_object *) out.pointer; | 1199 | obj = (union acpi_object *) out.pointer; |
1196 | if (obj && obj->type == ACPI_TYPE_BUFFER && | 1200 | if (obj) { |
1197 | (obj->buffer.length == sizeof(u32) || | 1201 | if (obj->type == ACPI_TYPE_BUFFER && |
1198 | obj->buffer.length == sizeof(u64))) { | 1202 | (obj->buffer.length == sizeof(u32) || |
1199 | devices = *((u32 *) obj->buffer.pointer); | 1203 | obj->buffer.length == sizeof(u64))) { |
1200 | } else if (obj->type == ACPI_TYPE_INTEGER) { | 1204 | devices = *((u32 *) obj->buffer.pointer); |
1201 | devices = (u32) obj->integer.value; | 1205 | } else if (obj->type == ACPI_TYPE_INTEGER) { |
1206 | devices = (u32) obj->integer.value; | ||
1207 | } | ||
1202 | } else { | 1208 | } else { |
1203 | kfree(out.pointer); | 1209 | kfree(out.pointer); |
1204 | return AE_ERROR; | 1210 | return AE_ERROR; |
@@ -1676,6 +1682,7 @@ static void acer_wmi_notify(u32 value, void *context) | |||
1676 | acpi_status status; | 1682 | acpi_status status; |
1677 | u16 device_state; | 1683 | u16 device_state; |
1678 | const struct key_entry *key; | 1684 | const struct key_entry *key; |
1685 | u32 scancode; | ||
1679 | 1686 | ||
1680 | status = wmi_get_event_data(value, &response); | 1687 | status = wmi_get_event_data(value, &response); |
1681 | if (status != AE_OK) { | 1688 | if (status != AE_OK) { |
@@ -1712,6 +1719,7 @@ static void acer_wmi_notify(u32 value, void *context) | |||
1712 | pr_warn("Unknown key number - 0x%x\n", | 1719 | pr_warn("Unknown key number - 0x%x\n", |
1713 | return_value.key_num); | 1720 | return_value.key_num); |
1714 | } else { | 1721 | } else { |
1722 | scancode = return_value.key_num; | ||
1715 | switch (key->keycode) { | 1723 | switch (key->keycode) { |
1716 | case KEY_WLAN: | 1724 | case KEY_WLAN: |
1717 | case KEY_BLUETOOTH: | 1725 | case KEY_BLUETOOTH: |
@@ -1725,9 +1733,11 @@ static void acer_wmi_notify(u32 value, void *context) | |||
1725 | rfkill_set_sw_state(bluetooth_rfkill, | 1733 | rfkill_set_sw_state(bluetooth_rfkill, |
1726 | !(device_state & ACER_WMID3_GDS_BLUETOOTH)); | 1734 | !(device_state & ACER_WMID3_GDS_BLUETOOTH)); |
1727 | break; | 1735 | break; |
1736 | case KEY_TOUCHPAD_TOGGLE: | ||
1737 | scancode = (device_state & ACER_WMID3_GDS_TOUCHPAD) ? | ||
1738 | KEY_TOUCHPAD_ON : KEY_TOUCHPAD_OFF; | ||
1728 | } | 1739 | } |
1729 | sparse_keymap_report_entry(acer_wmi_input_dev, key, | 1740 | sparse_keymap_report_event(acer_wmi_input_dev, scancode, 1, true); |
1730 | 1, true); | ||
1731 | } | 1741 | } |
1732 | break; | 1742 | break; |
1733 | case WMID_ACCEL_EVENT: | 1743 | case WMID_ACCEL_EVENT: |
@@ -1946,12 +1956,14 @@ static u32 get_wmid_devices(void) | |||
1946 | return 0; | 1956 | return 0; |
1947 | 1957 | ||
1948 | obj = (union acpi_object *) out.pointer; | 1958 | obj = (union acpi_object *) out.pointer; |
1949 | if (obj && obj->type == ACPI_TYPE_BUFFER && | 1959 | if (obj) { |
1950 | (obj->buffer.length == sizeof(u32) || | 1960 | if (obj->type == ACPI_TYPE_BUFFER && |
1951 | obj->buffer.length == sizeof(u64))) { | 1961 | (obj->buffer.length == sizeof(u32) || |
1952 | devices = *((u32 *) obj->buffer.pointer); | 1962 | obj->buffer.length == sizeof(u64))) { |
1953 | } else if (obj->type == ACPI_TYPE_INTEGER) { | 1963 | devices = *((u32 *) obj->buffer.pointer); |
1954 | devices = (u32) obj->integer.value; | 1964 | } else if (obj->type == ACPI_TYPE_INTEGER) { |
1965 | devices = (u32) obj->integer.value; | ||
1966 | } | ||
1955 | } | 1967 | } |
1956 | 1968 | ||
1957 | kfree(out.pointer); | 1969 | kfree(out.pointer); |
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index ec1d3bc2dbe2..fcde4e528819 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c | |||
@@ -860,8 +860,10 @@ static ssize_t show_infos(struct device *dev, | |||
860 | /* | 860 | /* |
861 | * The HWRS method return informations about the hardware. | 861 | * The HWRS method return informations about the hardware. |
862 | * 0x80 bit is for WLAN, 0x100 for Bluetooth. | 862 | * 0x80 bit is for WLAN, 0x100 for Bluetooth. |
863 | * 0x40 for WWAN, 0x10 for WIMAX. | ||
863 | * The significance of others is yet to be found. | 864 | * The significance of others is yet to be found. |
864 | * If we don't find the method, we assume the device are present. | 865 | * We don't currently use this for device detection, and it |
866 | * takes several seconds to run on some systems. | ||
865 | */ | 867 | */ |
866 | rv = acpi_evaluate_integer(asus->handle, "HWRS", NULL, &temp); | 868 | rv = acpi_evaluate_integer(asus->handle, "HWRS", NULL, &temp); |
867 | if (!ACPI_FAILURE(rv)) | 869 | if (!ACPI_FAILURE(rv)) |
@@ -1682,7 +1684,7 @@ static int asus_laptop_get_info(struct asus_laptop *asus) | |||
1682 | { | 1684 | { |
1683 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 1685 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
1684 | union acpi_object *model = NULL; | 1686 | union acpi_object *model = NULL; |
1685 | unsigned long long bsts_result, hwrs_result; | 1687 | unsigned long long bsts_result; |
1686 | char *string = NULL; | 1688 | char *string = NULL; |
1687 | acpi_status status; | 1689 | acpi_status status; |
1688 | 1690 | ||
@@ -1741,20 +1743,9 @@ static int asus_laptop_get_info(struct asus_laptop *asus) | |||
1741 | return -ENOMEM; | 1743 | return -ENOMEM; |
1742 | } | 1744 | } |
1743 | 1745 | ||
1744 | if (*string) | 1746 | if (string) |
1745 | pr_notice(" %s model detected\n", string); | 1747 | pr_notice(" %s model detected\n", string); |
1746 | 1748 | ||
1747 | /* | ||
1748 | * The HWRS method return informations about the hardware. | ||
1749 | * 0x80 bit is for WLAN, 0x100 for Bluetooth, | ||
1750 | * 0x40 for WWAN, 0x10 for WIMAX. | ||
1751 | * The significance of others is yet to be found. | ||
1752 | */ | ||
1753 | status = | ||
1754 | acpi_evaluate_integer(asus->handle, "HWRS", NULL, &hwrs_result); | ||
1755 | if (!ACPI_FAILURE(status)) | ||
1756 | pr_notice(" HWRS returned %x", (int)hwrs_result); | ||
1757 | |||
1758 | if (!acpi_check_handle(asus->handle, METHOD_WL_STATUS, NULL)) | 1749 | if (!acpi_check_handle(asus->handle, METHOD_WL_STATUS, NULL)) |
1759 | asus->have_rsts = true; | 1750 | asus->have_rsts = true; |
1760 | 1751 | ||
diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index dd90d15f5210..71623a2ff3e8 100644 --- a/drivers/platform/x86/samsung-laptop.c +++ b/drivers/platform/x86/samsung-laptop.c | |||
@@ -1523,6 +1523,16 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = { | |||
1523 | }, | 1523 | }, |
1524 | .driver_data = &samsung_broken_acpi_video, | 1524 | .driver_data = &samsung_broken_acpi_video, |
1525 | }, | 1525 | }, |
1526 | { | ||
1527 | .callback = samsung_dmi_matched, | ||
1528 | .ident = "N250P", | ||
1529 | .matches = { | ||
1530 | DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), | ||
1531 | DMI_MATCH(DMI_PRODUCT_NAME, "N250P"), | ||
1532 | DMI_MATCH(DMI_BOARD_NAME, "N250P"), | ||
1533 | }, | ||
1534 | .driver_data = &samsung_broken_acpi_video, | ||
1535 | }, | ||
1526 | { }, | 1536 | { }, |
1527 | }; | 1537 | }; |
1528 | MODULE_DEVICE_TABLE(dmi, samsung_dmi_table); | 1538 | MODULE_DEVICE_TABLE(dmi, samsung_dmi_table); |
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index daaddec68def..b8ad71f7863f 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c | |||
@@ -786,28 +786,29 @@ static int sony_nc_int_call(acpi_handle handle, char *name, int *value, | |||
786 | static int sony_nc_buffer_call(acpi_handle handle, char *name, u64 *value, | 786 | static int sony_nc_buffer_call(acpi_handle handle, char *name, u64 *value, |
787 | void *buffer, size_t buflen) | 787 | void *buffer, size_t buflen) |
788 | { | 788 | { |
789 | int ret = 0; | ||
789 | size_t len = len; | 790 | size_t len = len; |
790 | union acpi_object *object = __call_snc_method(handle, name, value); | 791 | union acpi_object *object = __call_snc_method(handle, name, value); |
791 | 792 | ||
792 | if (!object) | 793 | if (!object) |
793 | return -EINVAL; | 794 | return -EINVAL; |
794 | 795 | ||
795 | if (object->type == ACPI_TYPE_BUFFER) | 796 | if (object->type == ACPI_TYPE_BUFFER) { |
796 | len = MIN(buflen, object->buffer.length); | 797 | len = MIN(buflen, object->buffer.length); |
798 | memcpy(buffer, object->buffer.pointer, len); | ||
797 | 799 | ||
798 | else if (object->type == ACPI_TYPE_INTEGER) | 800 | } else if (object->type == ACPI_TYPE_INTEGER) { |
799 | len = MIN(buflen, sizeof(object->integer.value)); | 801 | len = MIN(buflen, sizeof(object->integer.value)); |
802 | memcpy(buffer, &object->integer.value, len); | ||
800 | 803 | ||
801 | else { | 804 | } else { |
802 | pr_warn("Invalid acpi_object: expected 0x%x got 0x%x\n", | 805 | pr_warn("Invalid acpi_object: expected 0x%x got 0x%x\n", |
803 | ACPI_TYPE_BUFFER, object->type); | 806 | ACPI_TYPE_BUFFER, object->type); |
804 | kfree(object); | 807 | ret = -EINVAL; |
805 | return -EINVAL; | ||
806 | } | 808 | } |
807 | 809 | ||
808 | memcpy(buffer, object->buffer.pointer, len); | ||
809 | kfree(object); | 810 | kfree(object); |
810 | return 0; | 811 | return ret; |
811 | } | 812 | } |
812 | 813 | ||
813 | struct sony_nc_handles { | 814 | struct sony_nc_handles { |
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 0f65b246cc0c..278584302f2d 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c | |||
@@ -1885,9 +1885,15 @@ int regulator_can_change_voltage(struct regulator *regulator) | |||
1885 | struct regulator_dev *rdev = regulator->rdev; | 1885 | struct regulator_dev *rdev = regulator->rdev; |
1886 | 1886 | ||
1887 | if (rdev->constraints && | 1887 | if (rdev->constraints && |
1888 | rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE && | 1888 | (rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) { |
1889 | (rdev->desc->n_voltages - rdev->desc->linear_min_sel) > 1) | 1889 | if (rdev->desc->n_voltages - rdev->desc->linear_min_sel > 1) |
1890 | return 1; | 1890 | return 1; |
1891 | |||
1892 | if (rdev->desc->continuous_voltage_range && | ||
1893 | rdev->constraints->min_uV && rdev->constraints->max_uV && | ||
1894 | rdev->constraints->min_uV != rdev->constraints->max_uV) | ||
1895 | return 1; | ||
1896 | } | ||
1891 | 1897 | ||
1892 | return 0; | 1898 | return 0; |
1893 | } | 1899 | } |
@@ -3315,7 +3321,8 @@ static void rdev_init_debugfs(struct regulator_dev *rdev) | |||
3315 | * @config: runtime configuration for regulator | 3321 | * @config: runtime configuration for regulator |
3316 | * | 3322 | * |
3317 | * Called by regulator drivers to register a regulator. | 3323 | * Called by regulator drivers to register a regulator. |
3318 | * Returns 0 on success. | 3324 | * Returns a valid pointer to struct regulator_dev on success |
3325 | * or an ERR_PTR() on error. | ||
3319 | */ | 3326 | */ |
3320 | struct regulator_dev * | 3327 | struct regulator_dev * |
3321 | regulator_register(const struct regulator_desc *regulator_desc, | 3328 | regulator_register(const struct regulator_desc *regulator_desc, |
diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c index df0eafb0dc7e..02be7fcae32f 100644 --- a/drivers/regulator/max8997.c +++ b/drivers/regulator/max8997.c | |||
@@ -71,26 +71,26 @@ struct voltage_map_desc { | |||
71 | int step; | 71 | int step; |
72 | }; | 72 | }; |
73 | 73 | ||
74 | /* Voltage maps in mV */ | 74 | /* Voltage maps in uV */ |
75 | static const struct voltage_map_desc ldo_voltage_map_desc = { | 75 | static const struct voltage_map_desc ldo_voltage_map_desc = { |
76 | .min = 800, .max = 3950, .step = 50, | 76 | .min = 800000, .max = 3950000, .step = 50000, |
77 | }; /* LDO1 ~ 18, 21 all */ | 77 | }; /* LDO1 ~ 18, 21 all */ |
78 | 78 | ||
79 | static const struct voltage_map_desc buck1245_voltage_map_desc = { | 79 | static const struct voltage_map_desc buck1245_voltage_map_desc = { |
80 | .min = 650, .max = 2225, .step = 25, | 80 | .min = 650000, .max = 2225000, .step = 25000, |
81 | }; /* Buck1, 2, 4, 5 */ | 81 | }; /* Buck1, 2, 4, 5 */ |
82 | 82 | ||
83 | static const struct voltage_map_desc buck37_voltage_map_desc = { | 83 | static const struct voltage_map_desc buck37_voltage_map_desc = { |
84 | .min = 750, .max = 3900, .step = 50, | 84 | .min = 750000, .max = 3900000, .step = 50000, |
85 | }; /* Buck3, 7 */ | 85 | }; /* Buck3, 7 */ |
86 | 86 | ||
87 | /* current map in mA */ | 87 | /* current map in uA */ |
88 | static const struct voltage_map_desc charger_current_map_desc = { | 88 | static const struct voltage_map_desc charger_current_map_desc = { |
89 | .min = 200, .max = 950, .step = 50, | 89 | .min = 200000, .max = 950000, .step = 50000, |
90 | }; | 90 | }; |
91 | 91 | ||
92 | static const struct voltage_map_desc topoff_current_map_desc = { | 92 | static const struct voltage_map_desc topoff_current_map_desc = { |
93 | .min = 50, .max = 200, .step = 10, | 93 | .min = 50000, .max = 200000, .step = 10000, |
94 | }; | 94 | }; |
95 | 95 | ||
96 | static const struct voltage_map_desc *reg_voltage_map[] = { | 96 | static const struct voltage_map_desc *reg_voltage_map[] = { |
@@ -194,7 +194,7 @@ static int max8997_list_voltage(struct regulator_dev *rdev, | |||
194 | if (val > desc->max) | 194 | if (val > desc->max) |
195 | return -EINVAL; | 195 | return -EINVAL; |
196 | 196 | ||
197 | return val * 1000; | 197 | return val; |
198 | } | 198 | } |
199 | 199 | ||
200 | static int max8997_get_enable_register(struct regulator_dev *rdev, | 200 | static int max8997_get_enable_register(struct regulator_dev *rdev, |
@@ -485,7 +485,6 @@ static int max8997_set_voltage_ldobuck(struct regulator_dev *rdev, | |||
485 | { | 485 | { |
486 | struct max8997_data *max8997 = rdev_get_drvdata(rdev); | 486 | struct max8997_data *max8997 = rdev_get_drvdata(rdev); |
487 | struct i2c_client *i2c = max8997->iodev->i2c; | 487 | struct i2c_client *i2c = max8997->iodev->i2c; |
488 | int min_vol = min_uV / 1000, max_vol = max_uV / 1000; | ||
489 | const struct voltage_map_desc *desc; | 488 | const struct voltage_map_desc *desc; |
490 | int rid = rdev_get_id(rdev); | 489 | int rid = rdev_get_id(rdev); |
491 | int i, reg, shift, mask, ret; | 490 | int i, reg, shift, mask, ret; |
@@ -509,7 +508,7 @@ static int max8997_set_voltage_ldobuck(struct regulator_dev *rdev, | |||
509 | 508 | ||
510 | desc = reg_voltage_map[rid]; | 509 | desc = reg_voltage_map[rid]; |
511 | 510 | ||
512 | i = max8997_get_voltage_proper_val(desc, min_vol, max_vol); | 511 | i = max8997_get_voltage_proper_val(desc, min_uV, max_uV); |
513 | if (i < 0) | 512 | if (i < 0) |
514 | return i; | 513 | return i; |
515 | 514 | ||
@@ -557,7 +556,7 @@ static int max8997_set_voltage_ldobuck_time_sel(struct regulator_dev *rdev, | |||
557 | case MAX8997_BUCK4: | 556 | case MAX8997_BUCK4: |
558 | case MAX8997_BUCK5: | 557 | case MAX8997_BUCK5: |
559 | return DIV_ROUND_UP(desc->step * (new_selector - old_selector), | 558 | return DIV_ROUND_UP(desc->step * (new_selector - old_selector), |
560 | max8997->ramp_delay); | 559 | max8997->ramp_delay * 1000); |
561 | } | 560 | } |
562 | 561 | ||
563 | return 0; | 562 | return 0; |
@@ -656,7 +655,6 @@ static int max8997_set_voltage_buck(struct regulator_dev *rdev, | |||
656 | const struct voltage_map_desc *desc; | 655 | const struct voltage_map_desc *desc; |
657 | int new_val, new_idx, damage, tmp_val, tmp_idx, tmp_dmg; | 656 | int new_val, new_idx, damage, tmp_val, tmp_idx, tmp_dmg; |
658 | bool gpio_dvs_mode = false; | 657 | bool gpio_dvs_mode = false; |
659 | int min_vol = min_uV / 1000, max_vol = max_uV / 1000; | ||
660 | 658 | ||
661 | if (rid < MAX8997_BUCK1 || rid > MAX8997_BUCK7) | 659 | if (rid < MAX8997_BUCK1 || rid > MAX8997_BUCK7) |
662 | return -EINVAL; | 660 | return -EINVAL; |
@@ -681,7 +679,7 @@ static int max8997_set_voltage_buck(struct regulator_dev *rdev, | |||
681 | selector); | 679 | selector); |
682 | 680 | ||
683 | desc = reg_voltage_map[rid]; | 681 | desc = reg_voltage_map[rid]; |
684 | new_val = max8997_get_voltage_proper_val(desc, min_vol, max_vol); | 682 | new_val = max8997_get_voltage_proper_val(desc, min_uV, max_uV); |
685 | if (new_val < 0) | 683 | if (new_val < 0) |
686 | return new_val; | 684 | return new_val; |
687 | 685 | ||
@@ -1123,8 +1121,8 @@ static int max8997_pmic_probe(struct platform_device *pdev) | |||
1123 | max8997->buck1_vol[i] = ret = | 1121 | max8997->buck1_vol[i] = ret = |
1124 | max8997_get_voltage_proper_val( | 1122 | max8997_get_voltage_proper_val( |
1125 | &buck1245_voltage_map_desc, | 1123 | &buck1245_voltage_map_desc, |
1126 | pdata->buck1_voltage[i] / 1000, | 1124 | pdata->buck1_voltage[i], |
1127 | pdata->buck1_voltage[i] / 1000 + | 1125 | pdata->buck1_voltage[i] + |
1128 | buck1245_voltage_map_desc.step); | 1126 | buck1245_voltage_map_desc.step); |
1129 | if (ret < 0) | 1127 | if (ret < 0) |
1130 | goto err_out; | 1128 | goto err_out; |
@@ -1132,8 +1130,8 @@ static int max8997_pmic_probe(struct platform_device *pdev) | |||
1132 | max8997->buck2_vol[i] = ret = | 1130 | max8997->buck2_vol[i] = ret = |
1133 | max8997_get_voltage_proper_val( | 1131 | max8997_get_voltage_proper_val( |
1134 | &buck1245_voltage_map_desc, | 1132 | &buck1245_voltage_map_desc, |
1135 | pdata->buck2_voltage[i] / 1000, | 1133 | pdata->buck2_voltage[i], |
1136 | pdata->buck2_voltage[i] / 1000 + | 1134 | pdata->buck2_voltage[i] + |
1137 | buck1245_voltage_map_desc.step); | 1135 | buck1245_voltage_map_desc.step); |
1138 | if (ret < 0) | 1136 | if (ret < 0) |
1139 | goto err_out; | 1137 | goto err_out; |
@@ -1141,8 +1139,8 @@ static int max8997_pmic_probe(struct platform_device *pdev) | |||
1141 | max8997->buck5_vol[i] = ret = | 1139 | max8997->buck5_vol[i] = ret = |
1142 | max8997_get_voltage_proper_val( | 1140 | max8997_get_voltage_proper_val( |
1143 | &buck1245_voltage_map_desc, | 1141 | &buck1245_voltage_map_desc, |
1144 | pdata->buck5_voltage[i] / 1000, | 1142 | pdata->buck5_voltage[i], |
1145 | pdata->buck5_voltage[i] / 1000 + | 1143 | pdata->buck5_voltage[i] + |
1146 | buck1245_voltage_map_desc.step); | 1144 | buck1245_voltage_map_desc.step); |
1147 | if (ret < 0) | 1145 | if (ret < 0) |
1148 | goto err_out; | 1146 | goto err_out; |
diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c index b821d08eb64a..1f0df4046b86 100644 --- a/drivers/regulator/max8998.c +++ b/drivers/regulator/max8998.c | |||
@@ -51,39 +51,39 @@ struct voltage_map_desc { | |||
51 | int step; | 51 | int step; |
52 | }; | 52 | }; |
53 | 53 | ||
54 | /* Voltage maps */ | 54 | /* Voltage maps in uV*/ |
55 | static const struct voltage_map_desc ldo23_voltage_map_desc = { | 55 | static const struct voltage_map_desc ldo23_voltage_map_desc = { |
56 | .min = 800, .step = 50, .max = 1300, | 56 | .min = 800000, .step = 50000, .max = 1300000, |
57 | }; | 57 | }; |
58 | static const struct voltage_map_desc ldo456711_voltage_map_desc = { | 58 | static const struct voltage_map_desc ldo456711_voltage_map_desc = { |
59 | .min = 1600, .step = 100, .max = 3600, | 59 | .min = 1600000, .step = 100000, .max = 3600000, |
60 | }; | 60 | }; |
61 | static const struct voltage_map_desc ldo8_voltage_map_desc = { | 61 | static const struct voltage_map_desc ldo8_voltage_map_desc = { |
62 | .min = 3000, .step = 100, .max = 3600, | 62 | .min = 3000000, .step = 100000, .max = 3600000, |
63 | }; | 63 | }; |
64 | static const struct voltage_map_desc ldo9_voltage_map_desc = { | 64 | static const struct voltage_map_desc ldo9_voltage_map_desc = { |
65 | .min = 2800, .step = 100, .max = 3100, | 65 | .min = 2800000, .step = 100000, .max = 3100000, |
66 | }; | 66 | }; |
67 | static const struct voltage_map_desc ldo10_voltage_map_desc = { | 67 | static const struct voltage_map_desc ldo10_voltage_map_desc = { |
68 | .min = 950, .step = 50, .max = 1300, | 68 | .min = 95000, .step = 50000, .max = 1300000, |
69 | }; | 69 | }; |
70 | static const struct voltage_map_desc ldo1213_voltage_map_desc = { | 70 | static const struct voltage_map_desc ldo1213_voltage_map_desc = { |
71 | .min = 800, .step = 100, .max = 3300, | 71 | .min = 800000, .step = 100000, .max = 3300000, |
72 | }; | 72 | }; |
73 | static const struct voltage_map_desc ldo1415_voltage_map_desc = { | 73 | static const struct voltage_map_desc ldo1415_voltage_map_desc = { |
74 | .min = 1200, .step = 100, .max = 3300, | 74 | .min = 1200000, .step = 100000, .max = 3300000, |
75 | }; | 75 | }; |
76 | static const struct voltage_map_desc ldo1617_voltage_map_desc = { | 76 | static const struct voltage_map_desc ldo1617_voltage_map_desc = { |
77 | .min = 1600, .step = 100, .max = 3600, | 77 | .min = 1600000, .step = 100000, .max = 3600000, |
78 | }; | 78 | }; |
79 | static const struct voltage_map_desc buck12_voltage_map_desc = { | 79 | static const struct voltage_map_desc buck12_voltage_map_desc = { |
80 | .min = 750, .step = 25, .max = 1525, | 80 | .min = 750000, .step = 25000, .max = 1525000, |
81 | }; | 81 | }; |
82 | static const struct voltage_map_desc buck3_voltage_map_desc = { | 82 | static const struct voltage_map_desc buck3_voltage_map_desc = { |
83 | .min = 1600, .step = 100, .max = 3600, | 83 | .min = 1600000, .step = 100000, .max = 3600000, |
84 | }; | 84 | }; |
85 | static const struct voltage_map_desc buck4_voltage_map_desc = { | 85 | static const struct voltage_map_desc buck4_voltage_map_desc = { |
86 | .min = 800, .step = 100, .max = 2300, | 86 | .min = 800000, .step = 100000, .max = 2300000, |
87 | }; | 87 | }; |
88 | 88 | ||
89 | static const struct voltage_map_desc *ldo_voltage_map[] = { | 89 | static const struct voltage_map_desc *ldo_voltage_map[] = { |
@@ -445,9 +445,9 @@ static int max8998_set_voltage_buck_time_sel(struct regulator_dev *rdev, | |||
445 | if (max8998->iodev->type == TYPE_MAX8998 && !(val & MAX8998_ENRAMP)) | 445 | if (max8998->iodev->type == TYPE_MAX8998 && !(val & MAX8998_ENRAMP)) |
446 | return 0; | 446 | return 0; |
447 | 447 | ||
448 | difference = (new_selector - old_selector) * desc->step; | 448 | difference = (new_selector - old_selector) * desc->step / 1000; |
449 | if (difference > 0) | 449 | if (difference > 0) |
450 | return difference / ((val & 0x0f) + 1); | 450 | return DIV_ROUND_UP(difference, (val & 0x0f) + 1); |
451 | 451 | ||
452 | return 0; | 452 | return 0; |
453 | } | 453 | } |
@@ -702,7 +702,7 @@ static int max8998_pmic_probe(struct platform_device *pdev) | |||
702 | i = 0; | 702 | i = 0; |
703 | while (buck12_voltage_map_desc.min + | 703 | while (buck12_voltage_map_desc.min + |
704 | buck12_voltage_map_desc.step*i | 704 | buck12_voltage_map_desc.step*i |
705 | < (pdata->buck1_voltage1 / 1000)) | 705 | < pdata->buck1_voltage1) |
706 | i++; | 706 | i++; |
707 | max8998->buck1_vol[0] = i; | 707 | max8998->buck1_vol[0] = i; |
708 | ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE1, i); | 708 | ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE1, i); |
@@ -713,7 +713,7 @@ static int max8998_pmic_probe(struct platform_device *pdev) | |||
713 | i = 0; | 713 | i = 0; |
714 | while (buck12_voltage_map_desc.min + | 714 | while (buck12_voltage_map_desc.min + |
715 | buck12_voltage_map_desc.step*i | 715 | buck12_voltage_map_desc.step*i |
716 | < (pdata->buck1_voltage2 / 1000)) | 716 | < pdata->buck1_voltage2) |
717 | i++; | 717 | i++; |
718 | 718 | ||
719 | max8998->buck1_vol[1] = i; | 719 | max8998->buck1_vol[1] = i; |
@@ -725,7 +725,7 @@ static int max8998_pmic_probe(struct platform_device *pdev) | |||
725 | i = 0; | 725 | i = 0; |
726 | while (buck12_voltage_map_desc.min + | 726 | while (buck12_voltage_map_desc.min + |
727 | buck12_voltage_map_desc.step*i | 727 | buck12_voltage_map_desc.step*i |
728 | < (pdata->buck1_voltage3 / 1000)) | 728 | < pdata->buck1_voltage3) |
729 | i++; | 729 | i++; |
730 | 730 | ||
731 | max8998->buck1_vol[2] = i; | 731 | max8998->buck1_vol[2] = i; |
@@ -737,7 +737,7 @@ static int max8998_pmic_probe(struct platform_device *pdev) | |||
737 | i = 0; | 737 | i = 0; |
738 | while (buck12_voltage_map_desc.min + | 738 | while (buck12_voltage_map_desc.min + |
739 | buck12_voltage_map_desc.step*i | 739 | buck12_voltage_map_desc.step*i |
740 | < (pdata->buck1_voltage4 / 1000)) | 740 | < pdata->buck1_voltage4) |
741 | i++; | 741 | i++; |
742 | 742 | ||
743 | max8998->buck1_vol[3] = i; | 743 | max8998->buck1_vol[3] = i; |
@@ -763,7 +763,7 @@ static int max8998_pmic_probe(struct platform_device *pdev) | |||
763 | i = 0; | 763 | i = 0; |
764 | while (buck12_voltage_map_desc.min + | 764 | while (buck12_voltage_map_desc.min + |
765 | buck12_voltage_map_desc.step*i | 765 | buck12_voltage_map_desc.step*i |
766 | < (pdata->buck2_voltage1 / 1000)) | 766 | < pdata->buck2_voltage1) |
767 | i++; | 767 | i++; |
768 | max8998->buck2_vol[0] = i; | 768 | max8998->buck2_vol[0] = i; |
769 | ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE1, i); | 769 | ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE1, i); |
@@ -774,7 +774,7 @@ static int max8998_pmic_probe(struct platform_device *pdev) | |||
774 | i = 0; | 774 | i = 0; |
775 | while (buck12_voltage_map_desc.min + | 775 | while (buck12_voltage_map_desc.min + |
776 | buck12_voltage_map_desc.step*i | 776 | buck12_voltage_map_desc.step*i |
777 | < (pdata->buck2_voltage2 / 1000)) | 777 | < pdata->buck2_voltage2) |
778 | i++; | 778 | i++; |
779 | max8998->buck2_vol[1] = i; | 779 | max8998->buck2_vol[1] = i; |
780 | ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE2, i); | 780 | ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE2, i); |
@@ -792,8 +792,8 @@ static int max8998_pmic_probe(struct platform_device *pdev) | |||
792 | int count = (desc->max - desc->min) / desc->step + 1; | 792 | int count = (desc->max - desc->min) / desc->step + 1; |
793 | 793 | ||
794 | regulators[index].n_voltages = count; | 794 | regulators[index].n_voltages = count; |
795 | regulators[index].min_uV = desc->min * 1000; | 795 | regulators[index].min_uV = desc->min; |
796 | regulators[index].uV_step = desc->step * 1000; | 796 | regulators[index].uV_step = desc->step; |
797 | } | 797 | } |
798 | 798 | ||
799 | config.dev = max8998->dev; | 799 | config.dev = max8998->dev; |
diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c index 9f991f2c525a..33b65c9ad5d5 100644 --- a/drivers/regulator/s5m8767.c +++ b/drivers/regulator/s5m8767.c | |||
@@ -214,7 +214,7 @@ static int s5m8767_reg_is_enabled(struct regulator_dev *rdev) | |||
214 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); | 214 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); |
215 | int ret, reg; | 215 | int ret, reg; |
216 | int mask = 0xc0, enable_ctrl; | 216 | int mask = 0xc0, enable_ctrl; |
217 | u8 val; | 217 | unsigned int val; |
218 | 218 | ||
219 | ret = s5m8767_get_register(rdev, ®, &enable_ctrl); | 219 | ret = s5m8767_get_register(rdev, ®, &enable_ctrl); |
220 | if (ret == -EINVAL) | 220 | if (ret == -EINVAL) |
@@ -306,7 +306,7 @@ static int s5m8767_get_voltage_sel(struct regulator_dev *rdev) | |||
306 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); | 306 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); |
307 | int reg, mask, ret; | 307 | int reg, mask, ret; |
308 | int reg_id = rdev_get_id(rdev); | 308 | int reg_id = rdev_get_id(rdev); |
309 | u8 val; | 309 | unsigned int val; |
310 | 310 | ||
311 | ret = s5m8767_get_voltage_register(rdev, ®); | 311 | ret = s5m8767_get_voltage_register(rdev, ®); |
312 | if (ret) | 312 | if (ret) |
diff --git a/drivers/rtc/rtc-da9055.c b/drivers/rtc/rtc-da9055.c index 96bafc5c3bf8..8f0dcfedb83c 100644 --- a/drivers/rtc/rtc-da9055.c +++ b/drivers/rtc/rtc-da9055.c | |||
@@ -227,7 +227,7 @@ static const struct rtc_class_ops da9055_rtc_ops = { | |||
227 | .alarm_irq_enable = da9055_rtc_alarm_irq_enable, | 227 | .alarm_irq_enable = da9055_rtc_alarm_irq_enable, |
228 | }; | 228 | }; |
229 | 229 | ||
230 | static int __init da9055_rtc_device_init(struct da9055 *da9055, | 230 | static int da9055_rtc_device_init(struct da9055 *da9055, |
231 | struct da9055_pdata *pdata) | 231 | struct da9055_pdata *pdata) |
232 | { | 232 | { |
233 | int ret; | 233 | int ret; |
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 9bd5da36f99e..704488d0f819 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c | |||
@@ -248,7 +248,7 @@ static void dasd_ext_handler(struct ext_code ext_code, | |||
248 | default: | 248 | default: |
249 | return; | 249 | return; |
250 | } | 250 | } |
251 | kstat_cpu(smp_processor_id()).irqs[EXTINT_DSD]++; | 251 | inc_irq_stat(IRQEXT_DSD); |
252 | if (!ip) { /* no intparm: unsolicited interrupt */ | 252 | if (!ip) { /* no intparm: unsolicited interrupt */ |
253 | DBF_EVENT(DBF_NOTICE, "%s", "caught unsolicited " | 253 | DBF_EVENT(DBF_NOTICE, "%s", "caught unsolicited " |
254 | "interrupt"); | 254 | "interrupt"); |
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 806fe912d6e7..e37bc1620d14 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c | |||
@@ -4274,7 +4274,7 @@ static struct ccw_driver dasd_eckd_driver = { | |||
4274 | .thaw = dasd_generic_restore_device, | 4274 | .thaw = dasd_generic_restore_device, |
4275 | .restore = dasd_generic_restore_device, | 4275 | .restore = dasd_generic_restore_device, |
4276 | .uc_handler = dasd_generic_uc_handler, | 4276 | .uc_handler = dasd_generic_uc_handler, |
4277 | .int_class = IOINT_DAS, | 4277 | .int_class = IRQIO_DAS, |
4278 | }; | 4278 | }; |
4279 | 4279 | ||
4280 | /* | 4280 | /* |
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index eb748507c7fa..414698584344 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c | |||
@@ -78,7 +78,7 @@ static struct ccw_driver dasd_fba_driver = { | |||
78 | .freeze = dasd_generic_pm_freeze, | 78 | .freeze = dasd_generic_pm_freeze, |
79 | .thaw = dasd_generic_restore_device, | 79 | .thaw = dasd_generic_restore_device, |
80 | .restore = dasd_generic_restore_device, | 80 | .restore = dasd_generic_restore_device, |
81 | .int_class = IOINT_DAS, | 81 | .int_class = IRQIO_DAS, |
82 | }; | 82 | }; |
83 | 83 | ||
84 | static void | 84 | static void |
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 40084501c31b..33b7141a182f 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c | |||
@@ -44,6 +44,7 @@ | |||
44 | #define RAW3215_NR_CCWS 3 | 44 | #define RAW3215_NR_CCWS 3 |
45 | #define RAW3215_TIMEOUT HZ/10 /* time for delayed output */ | 45 | #define RAW3215_TIMEOUT HZ/10 /* time for delayed output */ |
46 | 46 | ||
47 | #define RAW3215_FIXED 1 /* 3215 console device is not be freed */ | ||
47 | #define RAW3215_WORKING 4 /* set if a request is being worked on */ | 48 | #define RAW3215_WORKING 4 /* set if a request is being worked on */ |
48 | #define RAW3215_THROTTLED 8 /* set if reading is disabled */ | 49 | #define RAW3215_THROTTLED 8 /* set if reading is disabled */ |
49 | #define RAW3215_STOPPED 16 /* set if writing is disabled */ | 50 | #define RAW3215_STOPPED 16 /* set if writing is disabled */ |
@@ -630,7 +631,8 @@ static void raw3215_shutdown(struct raw3215_info *raw) | |||
630 | DECLARE_WAITQUEUE(wait, current); | 631 | DECLARE_WAITQUEUE(wait, current); |
631 | unsigned long flags; | 632 | unsigned long flags; |
632 | 633 | ||
633 | if (!(raw->port.flags & ASYNC_INITIALIZED)) | 634 | if (!(raw->port.flags & ASYNC_INITIALIZED) || |
635 | (raw->flags & RAW3215_FIXED)) | ||
634 | return; | 636 | return; |
635 | /* Wait for outstanding requests, then free irq */ | 637 | /* Wait for outstanding requests, then free irq */ |
636 | spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); | 638 | spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); |
@@ -805,7 +807,7 @@ static struct ccw_driver raw3215_ccw_driver = { | |||
805 | .freeze = &raw3215_pm_stop, | 807 | .freeze = &raw3215_pm_stop, |
806 | .thaw = &raw3215_pm_start, | 808 | .thaw = &raw3215_pm_start, |
807 | .restore = &raw3215_pm_start, | 809 | .restore = &raw3215_pm_start, |
808 | .int_class = IOINT_C15, | 810 | .int_class = IRQIO_C15, |
809 | }; | 811 | }; |
810 | 812 | ||
811 | #ifdef CONFIG_TN3215_CONSOLE | 813 | #ifdef CONFIG_TN3215_CONSOLE |
@@ -927,6 +929,8 @@ static int __init con3215_init(void) | |||
927 | dev_set_drvdata(&cdev->dev, raw); | 929 | dev_set_drvdata(&cdev->dev, raw); |
928 | cdev->handler = raw3215_irq; | 930 | cdev->handler = raw3215_irq; |
929 | 931 | ||
932 | raw->flags |= RAW3215_FIXED; | ||
933 | |||
930 | /* Request the console irq */ | 934 | /* Request the console irq */ |
931 | if (raw3215_startup(raw) != 0) { | 935 | if (raw3215_startup(raw) != 0) { |
932 | raw3215_free_info(raw); | 936 | raw3215_free_info(raw); |
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index f3b8bb84faf2..9a6c140c5f07 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c | |||
@@ -1396,7 +1396,7 @@ static struct ccw_driver raw3270_ccw_driver = { | |||
1396 | .freeze = &raw3270_pm_stop, | 1396 | .freeze = &raw3270_pm_stop, |
1397 | .thaw = &raw3270_pm_start, | 1397 | .thaw = &raw3270_pm_start, |
1398 | .restore = &raw3270_pm_start, | 1398 | .restore = &raw3270_pm_start, |
1399 | .int_class = IOINT_C70, | 1399 | .int_class = IRQIO_C70, |
1400 | }; | 1400 | }; |
1401 | 1401 | ||
1402 | static int | 1402 | static int |
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index 4fa21f7e2308..12c16a65dd25 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c | |||
@@ -400,7 +400,7 @@ static void sclp_interrupt_handler(struct ext_code ext_code, | |||
400 | u32 finished_sccb; | 400 | u32 finished_sccb; |
401 | u32 evbuf_pending; | 401 | u32 evbuf_pending; |
402 | 402 | ||
403 | kstat_cpu(smp_processor_id()).irqs[EXTINT_SCP]++; | 403 | inc_irq_stat(IRQEXT_SCP); |
404 | spin_lock(&sclp_lock); | 404 | spin_lock(&sclp_lock); |
405 | finished_sccb = param32 & 0xfffffff8; | 405 | finished_sccb = param32 & 0xfffffff8; |
406 | evbuf_pending = param32 & 0x3; | 406 | evbuf_pending = param32 & 0x3; |
@@ -813,7 +813,7 @@ static void sclp_check_handler(struct ext_code ext_code, | |||
813 | { | 813 | { |
814 | u32 finished_sccb; | 814 | u32 finished_sccb; |
815 | 815 | ||
816 | kstat_cpu(smp_processor_id()).irqs[EXTINT_SCP]++; | 816 | inc_irq_stat(IRQEXT_SCP); |
817 | finished_sccb = param32 & 0xfffffff8; | 817 | finished_sccb = param32 & 0xfffffff8; |
818 | /* Is this the interrupt we are waiting for? */ | 818 | /* Is this the interrupt we are waiting for? */ |
819 | if (finished_sccb == 0) | 819 | if (finished_sccb == 0) |
diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c index 6ae929c024ae..9aa79702b370 100644 --- a/drivers/s390/char/tape_34xx.c +++ b/drivers/s390/char/tape_34xx.c | |||
@@ -1193,7 +1193,7 @@ static struct ccw_driver tape_34xx_driver = { | |||
1193 | .set_online = tape_34xx_online, | 1193 | .set_online = tape_34xx_online, |
1194 | .set_offline = tape_generic_offline, | 1194 | .set_offline = tape_generic_offline, |
1195 | .freeze = tape_generic_pm_suspend, | 1195 | .freeze = tape_generic_pm_suspend, |
1196 | .int_class = IOINT_TAP, | 1196 | .int_class = IRQIO_TAP, |
1197 | }; | 1197 | }; |
1198 | 1198 | ||
1199 | static int | 1199 | static int |
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index 1b0eb49f739c..327cb19ad0b0 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c | |||
@@ -1656,7 +1656,7 @@ static struct ccw_driver tape_3590_driver = { | |||
1656 | .set_offline = tape_generic_offline, | 1656 | .set_offline = tape_generic_offline, |
1657 | .set_online = tape_3590_online, | 1657 | .set_online = tape_3590_online, |
1658 | .freeze = tape_generic_pm_suspend, | 1658 | .freeze = tape_generic_pm_suspend, |
1659 | .int_class = IOINT_TAP, | 1659 | .int_class = IRQIO_TAP, |
1660 | }; | 1660 | }; |
1661 | 1661 | ||
1662 | /* | 1662 | /* |
diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c index 73bef0bd394c..483f72ba030d 100644 --- a/drivers/s390/char/vmur.c +++ b/drivers/s390/char/vmur.c | |||
@@ -74,7 +74,7 @@ static struct ccw_driver ur_driver = { | |||
74 | .set_online = ur_set_online, | 74 | .set_online = ur_set_online, |
75 | .set_offline = ur_set_offline, | 75 | .set_offline = ur_set_offline, |
76 | .freeze = ur_pm_suspend, | 76 | .freeze = ur_pm_suspend, |
77 | .int_class = IOINT_VMR, | 77 | .int_class = IRQIO_VMR, |
78 | }; | 78 | }; |
79 | 79 | ||
80 | static DEFINE_MUTEX(vmur_mutex); | 80 | static DEFINE_MUTEX(vmur_mutex); |
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 68e80e2734a4..10729bbceced 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c | |||
@@ -283,7 +283,7 @@ struct chsc_sei_nt2_area { | |||
283 | u8 ccdf[PAGE_SIZE - 24 - 56]; /* content-code dependent field */ | 283 | u8 ccdf[PAGE_SIZE - 24 - 56]; /* content-code dependent field */ |
284 | } __packed; | 284 | } __packed; |
285 | 285 | ||
286 | #define CHSC_SEI_NT0 0ULL | 286 | #define CHSC_SEI_NT0 (1ULL << 63) |
287 | #define CHSC_SEI_NT2 (1ULL << 61) | 287 | #define CHSC_SEI_NT2 (1ULL << 61) |
288 | 288 | ||
289 | struct chsc_sei { | 289 | struct chsc_sei { |
@@ -291,7 +291,8 @@ struct chsc_sei { | |||
291 | u32 reserved1; | 291 | u32 reserved1; |
292 | u64 ntsm; /* notification type mask */ | 292 | u64 ntsm; /* notification type mask */ |
293 | struct chsc_header response; | 293 | struct chsc_header response; |
294 | u32 reserved2; | 294 | u32 :24; |
295 | u8 nt; | ||
295 | union { | 296 | union { |
296 | struct chsc_sei_nt0_area nt0_area; | 297 | struct chsc_sei_nt0_area nt0_area; |
297 | struct chsc_sei_nt2_area nt2_area; | 298 | struct chsc_sei_nt2_area nt2_area; |
@@ -496,17 +497,17 @@ static int __chsc_process_crw(struct chsc_sei *sei, u64 ntsm) | |||
496 | css_schedule_eval_all(); | 497 | css_schedule_eval_all(); |
497 | } | 498 | } |
498 | 499 | ||
499 | switch (sei->ntsm) { | 500 | switch (sei->nt) { |
500 | case CHSC_SEI_NT0: | 501 | case 0: |
501 | chsc_process_sei_nt0(&sei->u.nt0_area); | 502 | chsc_process_sei_nt0(&sei->u.nt0_area); |
502 | return 1; | 503 | break; |
503 | case CHSC_SEI_NT2: | 504 | case 2: |
504 | chsc_process_sei_nt2(&sei->u.nt2_area); | 505 | chsc_process_sei_nt2(&sei->u.nt2_area); |
505 | return 1; | 506 | break; |
506 | default: | 507 | default: |
507 | CIO_CRW_EVENT(2, "chsc: unhandled nt (nt=%08Lx)\n", | 508 | CIO_CRW_EVENT(2, "chsc: unhandled nt=%d\n", |
508 | sei->ntsm); | 509 | sei->nt); |
509 | return 0; | 510 | break; |
510 | } | 511 | } |
511 | } else { | 512 | } else { |
512 | CIO_CRW_EVENT(2, "chsc: sei failed (rc=%04x)\n", | 513 | CIO_CRW_EVENT(2, "chsc: sei failed (rc=%04x)\n", |
@@ -537,15 +538,7 @@ static void chsc_process_crw(struct crw *crw0, struct crw *crw1, int overflow) | |||
537 | sei = sei_page; | 538 | sei = sei_page; |
538 | 539 | ||
539 | CIO_TRACE_EVENT(2, "prcss"); | 540 | CIO_TRACE_EVENT(2, "prcss"); |
540 | 541 | __chsc_process_crw(sei, CHSC_SEI_NT0 | CHSC_SEI_NT2); | |
541 | /* | ||
542 | * The ntsm does not allow to select NT0 and NT2 together. We need to | ||
543 | * first check for NT2, than additionally for NT0... | ||
544 | */ | ||
545 | #ifdef CONFIG_PCI | ||
546 | if (!__chsc_process_crw(sei, CHSC_SEI_NT2)) | ||
547 | #endif | ||
548 | __chsc_process_crw(sei, CHSC_SEI_NT0); | ||
549 | } | 542 | } |
550 | 543 | ||
551 | void chsc_chp_online(struct chp_id chpid) | 544 | void chsc_chp_online(struct chp_id chpid) |
diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c index 8f9a1a384496..facdf809113f 100644 --- a/drivers/s390/cio/chsc_sch.c +++ b/drivers/s390/cio/chsc_sch.c | |||
@@ -58,7 +58,7 @@ static void chsc_subchannel_irq(struct subchannel *sch) | |||
58 | 58 | ||
59 | CHSC_LOG(4, "irb"); | 59 | CHSC_LOG(4, "irb"); |
60 | CHSC_LOG_HEX(4, irb, sizeof(*irb)); | 60 | CHSC_LOG_HEX(4, irb, sizeof(*irb)); |
61 | kstat_cpu(smp_processor_id()).irqs[IOINT_CSC]++; | 61 | inc_irq_stat(IRQIO_CSC); |
62 | 62 | ||
63 | /* Copy irb to provided request and set done. */ | 63 | /* Copy irb to provided request and set done. */ |
64 | if (!request) { | 64 | if (!request) { |
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 8e927b9f285f..c8faf6230b0f 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c | |||
@@ -611,7 +611,7 @@ void __irq_entry do_IRQ(struct pt_regs *regs) | |||
611 | tpi_info = (struct tpi_info *)&S390_lowcore.subchannel_id; | 611 | tpi_info = (struct tpi_info *)&S390_lowcore.subchannel_id; |
612 | irb = (struct irb *)&S390_lowcore.irb; | 612 | irb = (struct irb *)&S390_lowcore.irb; |
613 | do { | 613 | do { |
614 | kstat_cpu(smp_processor_id()).irqs[IO_INTERRUPT]++; | 614 | kstat_incr_irqs_this_cpu(IO_INTERRUPT, NULL); |
615 | if (tpi_info->adapter_IO) { | 615 | if (tpi_info->adapter_IO) { |
616 | do_adapter_IO(tpi_info->isc); | 616 | do_adapter_IO(tpi_info->isc); |
617 | continue; | 617 | continue; |
@@ -619,7 +619,7 @@ void __irq_entry do_IRQ(struct pt_regs *regs) | |||
619 | sch = (struct subchannel *)(unsigned long)tpi_info->intparm; | 619 | sch = (struct subchannel *)(unsigned long)tpi_info->intparm; |
620 | if (!sch) { | 620 | if (!sch) { |
621 | /* Clear pending interrupt condition. */ | 621 | /* Clear pending interrupt condition. */ |
622 | kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; | 622 | inc_irq_stat(IRQIO_CIO); |
623 | tsch(tpi_info->schid, irb); | 623 | tsch(tpi_info->schid, irb); |
624 | continue; | 624 | continue; |
625 | } | 625 | } |
@@ -633,9 +633,9 @@ void __irq_entry do_IRQ(struct pt_regs *regs) | |||
633 | if (sch->driver && sch->driver->irq) | 633 | if (sch->driver && sch->driver->irq) |
634 | sch->driver->irq(sch); | 634 | sch->driver->irq(sch); |
635 | else | 635 | else |
636 | kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; | 636 | inc_irq_stat(IRQIO_CIO); |
637 | } else | 637 | } else |
638 | kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; | 638 | inc_irq_stat(IRQIO_CIO); |
639 | spin_unlock(sch->lock); | 639 | spin_unlock(sch->lock); |
640 | /* | 640 | /* |
641 | * Are more interrupts pending? | 641 | * Are more interrupts pending? |
@@ -678,7 +678,7 @@ static void cio_tsch(struct subchannel *sch) | |||
678 | if (sch->driver && sch->driver->irq) | 678 | if (sch->driver && sch->driver->irq) |
679 | sch->driver->irq(sch); | 679 | sch->driver->irq(sch); |
680 | else | 680 | else |
681 | kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; | 681 | inc_irq_stat(IRQIO_CIO); |
682 | if (!irq_context) { | 682 | if (!irq_context) { |
683 | irq_exit(); | 683 | irq_exit(); |
684 | _local_bh_enable(); | 684 | _local_bh_enable(); |
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 6995cff44636..7cd5c6812ac7 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c | |||
@@ -758,7 +758,7 @@ static int io_subchannel_initialize_dev(struct subchannel *sch, | |||
758 | struct ccw_device *cdev) | 758 | struct ccw_device *cdev) |
759 | { | 759 | { |
760 | cdev->private->cdev = cdev; | 760 | cdev->private->cdev = cdev; |
761 | cdev->private->int_class = IOINT_CIO; | 761 | cdev->private->int_class = IRQIO_CIO; |
762 | atomic_set(&cdev->private->onoff, 0); | 762 | atomic_set(&cdev->private->onoff, 0); |
763 | cdev->dev.parent = &sch->dev; | 763 | cdev->dev.parent = &sch->dev; |
764 | cdev->dev.release = ccw_device_release; | 764 | cdev->dev.release = ccw_device_release; |
@@ -1023,7 +1023,7 @@ static void io_subchannel_irq(struct subchannel *sch) | |||
1023 | if (cdev) | 1023 | if (cdev) |
1024 | dev_fsm_event(cdev, DEV_EVENT_INTERRUPT); | 1024 | dev_fsm_event(cdev, DEV_EVENT_INTERRUPT); |
1025 | else | 1025 | else |
1026 | kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; | 1026 | inc_irq_stat(IRQIO_CIO); |
1027 | } | 1027 | } |
1028 | 1028 | ||
1029 | void io_subchannel_init_config(struct subchannel *sch) | 1029 | void io_subchannel_init_config(struct subchannel *sch) |
@@ -1634,7 +1634,7 @@ ccw_device_probe_console(void) | |||
1634 | memset(&console_private, 0, sizeof(struct ccw_device_private)); | 1634 | memset(&console_private, 0, sizeof(struct ccw_device_private)); |
1635 | console_cdev.private = &console_private; | 1635 | console_cdev.private = &console_private; |
1636 | console_private.cdev = &console_cdev; | 1636 | console_private.cdev = &console_cdev; |
1637 | console_private.int_class = IOINT_CIO; | 1637 | console_private.int_class = IRQIO_CIO; |
1638 | ret = ccw_device_console_enable(&console_cdev, sch); | 1638 | ret = ccw_device_console_enable(&console_cdev, sch); |
1639 | if (ret) { | 1639 | if (ret) { |
1640 | cio_release_console(); | 1640 | cio_release_console(); |
@@ -1715,13 +1715,13 @@ ccw_device_probe (struct device *dev) | |||
1715 | if (cdrv->int_class != 0) | 1715 | if (cdrv->int_class != 0) |
1716 | cdev->private->int_class = cdrv->int_class; | 1716 | cdev->private->int_class = cdrv->int_class; |
1717 | else | 1717 | else |
1718 | cdev->private->int_class = IOINT_CIO; | 1718 | cdev->private->int_class = IRQIO_CIO; |
1719 | 1719 | ||
1720 | ret = cdrv->probe ? cdrv->probe(cdev) : -ENODEV; | 1720 | ret = cdrv->probe ? cdrv->probe(cdev) : -ENODEV; |
1721 | 1721 | ||
1722 | if (ret) { | 1722 | if (ret) { |
1723 | cdev->drv = NULL; | 1723 | cdev->drv = NULL; |
1724 | cdev->private->int_class = IOINT_CIO; | 1724 | cdev->private->int_class = IRQIO_CIO; |
1725 | return ret; | 1725 | return ret; |
1726 | } | 1726 | } |
1727 | 1727 | ||
@@ -1755,7 +1755,7 @@ ccw_device_remove (struct device *dev) | |||
1755 | } | 1755 | } |
1756 | ccw_device_set_timeout(cdev, 0); | 1756 | ccw_device_set_timeout(cdev, 0); |
1757 | cdev->drv = NULL; | 1757 | cdev->drv = NULL; |
1758 | cdev->private->int_class = IOINT_CIO; | 1758 | cdev->private->int_class = IRQIO_CIO; |
1759 | return 0; | 1759 | return 0; |
1760 | } | 1760 | } |
1761 | 1761 | ||
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h index 2e575cff9845..7d4ecb65db00 100644 --- a/drivers/s390/cio/device.h +++ b/drivers/s390/cio/device.h | |||
@@ -61,11 +61,10 @@ dev_fsm_event(struct ccw_device *cdev, enum dev_event dev_event) | |||
61 | 61 | ||
62 | if (dev_event == DEV_EVENT_INTERRUPT) { | 62 | if (dev_event == DEV_EVENT_INTERRUPT) { |
63 | if (state == DEV_STATE_ONLINE) | 63 | if (state == DEV_STATE_ONLINE) |
64 | kstat_cpu(smp_processor_id()). | 64 | inc_irq_stat(cdev->private->int_class); |
65 | irqs[cdev->private->int_class]++; | ||
66 | else if (state != DEV_STATE_CMFCHANGE && | 65 | else if (state != DEV_STATE_CMFCHANGE && |
67 | state != DEV_STATE_CMFUPDATE) | 66 | state != DEV_STATE_CMFUPDATE) |
68 | kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++; | 67 | inc_irq_stat(IRQIO_CIO); |
69 | } | 68 | } |
70 | dev_jumptable[state][dev_event](cdev, dev_event); | 69 | dev_jumptable[state][dev_event](cdev, dev_event); |
71 | } | 70 | } |
diff --git a/drivers/s390/cio/eadm_sch.c b/drivers/s390/cio/eadm_sch.c index 6c9673400464..d9eddcba7e88 100644 --- a/drivers/s390/cio/eadm_sch.c +++ b/drivers/s390/cio/eadm_sch.c | |||
@@ -139,7 +139,7 @@ static void eadm_subchannel_irq(struct subchannel *sch) | |||
139 | EADM_LOG(6, "irq"); | 139 | EADM_LOG(6, "irq"); |
140 | EADM_LOG_HEX(6, irb, sizeof(*irb)); | 140 | EADM_LOG_HEX(6, irb, sizeof(*irb)); |
141 | 141 | ||
142 | kstat_cpu(smp_processor_id()).irqs[IOINT_ADM]++; | 142 | inc_irq_stat(IRQIO_ADM); |
143 | 143 | ||
144 | if ((scsw->stctl & (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)) | 144 | if ((scsw->stctl & (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)) |
145 | && scsw->eswf == 1 && irb->esw.eadm.erw.r) | 145 | && scsw->eswf == 1 && irb->esw.eadm.erw.r) |
diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c index bdb394b066fc..bde5255200dc 100644 --- a/drivers/s390/cio/qdio_thinint.c +++ b/drivers/s390/cio/qdio_thinint.c | |||
@@ -182,7 +182,7 @@ static void tiqdio_thinint_handler(void *alsi, void *data) | |||
182 | struct qdio_q *q; | 182 | struct qdio_q *q; |
183 | 183 | ||
184 | last_ai_time = S390_lowcore.int_clock; | 184 | last_ai_time = S390_lowcore.int_clock; |
185 | kstat_cpu(smp_processor_id()).irqs[IOINT_QAI]++; | 185 | inc_irq_stat(IRQIO_QAI); |
186 | 186 | ||
187 | /* protect tiq_list entries, only changed in activate or shutdown */ | 187 | /* protect tiq_list entries, only changed in activate or shutdown */ |
188 | rcu_read_lock(); | 188 | rcu_read_lock(); |
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 7b865a7300e6..b8b340ac5332 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c | |||
@@ -1272,7 +1272,7 @@ out: | |||
1272 | 1272 | ||
1273 | static void ap_interrupt_handler(void *unused1, void *unused2) | 1273 | static void ap_interrupt_handler(void *unused1, void *unused2) |
1274 | { | 1274 | { |
1275 | kstat_cpu(smp_processor_id()).irqs[IOINT_APB]++; | 1275 | inc_irq_stat(IRQIO_APB); |
1276 | tasklet_schedule(&ap_tasklet); | 1276 | tasklet_schedule(&ap_tasklet); |
1277 | } | 1277 | } |
1278 | 1278 | ||
diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c index 7dabef624da3..8491111aec12 100644 --- a/drivers/s390/kvm/kvm_virtio.c +++ b/drivers/s390/kvm/kvm_virtio.c | |||
@@ -392,7 +392,7 @@ static void kvm_extint_handler(struct ext_code ext_code, | |||
392 | 392 | ||
393 | if ((ext_code.subcode & 0xff00) != VIRTIO_SUBCODE_64) | 393 | if ((ext_code.subcode & 0xff00) != VIRTIO_SUBCODE_64) |
394 | return; | 394 | return; |
395 | kstat_cpu(smp_processor_id()).irqs[EXTINT_VRT]++; | 395 | inc_irq_stat(IRQEXT_VRT); |
396 | 396 | ||
397 | /* The LSB might be overloaded, we have to mask it */ | 397 | /* The LSB might be overloaded, we have to mask it */ |
398 | vq = (struct virtqueue *)(param64 & ~1UL); | 398 | vq = (struct virtqueue *)(param64 & ~1UL); |
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index 5c70a6599578..83bc9c5fa0c1 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c | |||
@@ -282,7 +282,7 @@ static struct ccw_driver claw_ccw_driver = { | |||
282 | .ids = claw_ids, | 282 | .ids = claw_ids, |
283 | .probe = ccwgroup_probe_ccwdev, | 283 | .probe = ccwgroup_probe_ccwdev, |
284 | .remove = ccwgroup_remove_ccwdev, | 284 | .remove = ccwgroup_remove_ccwdev, |
285 | .int_class = IOINT_CLW, | 285 | .int_class = IRQIO_CLW, |
286 | }; | 286 | }; |
287 | 287 | ||
288 | static ssize_t claw_driver_group_store(struct device_driver *ddrv, | 288 | static ssize_t claw_driver_group_store(struct device_driver *ddrv, |
diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c index 817b68925ddd..676f12049a36 100644 --- a/drivers/s390/net/ctcm_main.c +++ b/drivers/s390/net/ctcm_main.c | |||
@@ -1755,7 +1755,7 @@ static struct ccw_driver ctcm_ccw_driver = { | |||
1755 | .ids = ctcm_ids, | 1755 | .ids = ctcm_ids, |
1756 | .probe = ccwgroup_probe_ccwdev, | 1756 | .probe = ccwgroup_probe_ccwdev, |
1757 | .remove = ccwgroup_remove_ccwdev, | 1757 | .remove = ccwgroup_remove_ccwdev, |
1758 | .int_class = IOINT_CTC, | 1758 | .int_class = IRQIO_CTC, |
1759 | }; | 1759 | }; |
1760 | 1760 | ||
1761 | static struct ccwgroup_driver ctcm_group_driver = { | 1761 | static struct ccwgroup_driver ctcm_group_driver = { |
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index 2ca0f1dd7a00..c645dc9e98af 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c | |||
@@ -2384,7 +2384,7 @@ static struct ccw_driver lcs_ccw_driver = { | |||
2384 | .ids = lcs_ids, | 2384 | .ids = lcs_ids, |
2385 | .probe = ccwgroup_probe_ccwdev, | 2385 | .probe = ccwgroup_probe_ccwdev, |
2386 | .remove = ccwgroup_remove_ccwdev, | 2386 | .remove = ccwgroup_remove_ccwdev, |
2387 | .int_class = IOINT_LCS, | 2387 | .int_class = IRQIO_LCS, |
2388 | }; | 2388 | }; |
2389 | 2389 | ||
2390 | /** | 2390 | /** |
diff --git a/drivers/sh/clk/cpg.c b/drivers/sh/clk/cpg.c index 5aedcdf4ac5c..1ebe67cd1833 100644 --- a/drivers/sh/clk/cpg.c +++ b/drivers/sh/clk/cpg.c | |||
@@ -126,6 +126,12 @@ static int sh_clk_div_set_rate(struct clk *clk, unsigned long rate) | |||
126 | 126 | ||
127 | static int sh_clk_div_enable(struct clk *clk) | 127 | static int sh_clk_div_enable(struct clk *clk) |
128 | { | 128 | { |
129 | if (clk->div_mask == SH_CLK_DIV6_MSK) { | ||
130 | int ret = sh_clk_div_set_rate(clk, clk->rate); | ||
131 | if (ret < 0) | ||
132 | return ret; | ||
133 | } | ||
134 | |||
129 | sh_clk_write(sh_clk_read(clk) & ~CPG_CKSTP_BIT, clk); | 135 | sh_clk_write(sh_clk_read(clk) & ~CPG_CKSTP_BIT, clk); |
130 | return 0; | 136 | return 0; |
131 | } | 137 | } |
diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig index 7de2a10213bd..36eec320569c 100644 --- a/drivers/staging/comedi/Kconfig +++ b/drivers/staging/comedi/Kconfig | |||
@@ -444,6 +444,7 @@ config COMEDI_ADQ12B | |||
444 | 444 | ||
445 | config COMEDI_NI_AT_A2150 | 445 | config COMEDI_NI_AT_A2150 |
446 | tristate "NI AT-A2150 ISA card support" | 446 | tristate "NI AT-A2150 ISA card support" |
447 | select COMEDI_FC | ||
447 | depends on VIRT_TO_BUS | 448 | depends on VIRT_TO_BUS |
448 | ---help--- | 449 | ---help--- |
449 | Enable support for National Instruments AT-A2150 cards | 450 | Enable support for National Instruments AT-A2150 cards |
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index b7bba1790a20..9b038e4a7e71 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c | |||
@@ -1549,6 +1549,9 @@ static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd, | |||
1549 | if (cmd == COMEDI_DEVCONFIG) { | 1549 | if (cmd == COMEDI_DEVCONFIG) { |
1550 | rc = do_devconfig_ioctl(dev, | 1550 | rc = do_devconfig_ioctl(dev, |
1551 | (struct comedi_devconfig __user *)arg); | 1551 | (struct comedi_devconfig __user *)arg); |
1552 | if (rc == 0) | ||
1553 | /* Evade comedi_auto_unconfig(). */ | ||
1554 | dev_file_info->hardware_device = NULL; | ||
1552 | goto done; | 1555 | goto done; |
1553 | } | 1556 | } |
1554 | 1557 | ||
diff --git a/drivers/staging/comedi/drivers/comedi_test.c b/drivers/staging/comedi/drivers/comedi_test.c index fb3d09323ba1..01de996239f1 100644 --- a/drivers/staging/comedi/drivers/comedi_test.c +++ b/drivers/staging/comedi/drivers/comedi_test.c | |||
@@ -345,7 +345,7 @@ static int waveform_ai_cancel(struct comedi_device *dev, | |||
345 | struct waveform_private *devpriv = dev->private; | 345 | struct waveform_private *devpriv = dev->private; |
346 | 346 | ||
347 | devpriv->timer_running = 0; | 347 | devpriv->timer_running = 0; |
348 | del_timer(&devpriv->timer); | 348 | del_timer_sync(&devpriv->timer); |
349 | return 0; | 349 | return 0; |
350 | } | 350 | } |
351 | 351 | ||
diff --git a/drivers/staging/comedi/drivers/ni_pcimio.c b/drivers/staging/comedi/drivers/ni_pcimio.c index aaac0b2cc9eb..fd1662b4175d 100644 --- a/drivers/staging/comedi/drivers/ni_pcimio.c +++ b/drivers/staging/comedi/drivers/ni_pcimio.c | |||
@@ -963,7 +963,7 @@ static const struct ni_board_struct ni_boards[] = { | |||
963 | .ao_range_table = &range_ni_M_625x_ao, | 963 | .ao_range_table = &range_ni_M_625x_ao, |
964 | .reg_type = ni_reg_625x, | 964 | .reg_type = ni_reg_625x, |
965 | .ao_unipolar = 0, | 965 | .ao_unipolar = 0, |
966 | .ao_speed = 357, | 966 | .ao_speed = 350, |
967 | .num_p0_dio_channels = 8, | 967 | .num_p0_dio_channels = 8, |
968 | .caldac = {caldac_none}, | 968 | .caldac = {caldac_none}, |
969 | .has_8255 = 0, | 969 | .has_8255 = 0, |
@@ -982,7 +982,7 @@ static const struct ni_board_struct ni_boards[] = { | |||
982 | .ao_range_table = &range_ni_M_625x_ao, | 982 | .ao_range_table = &range_ni_M_625x_ao, |
983 | .reg_type = ni_reg_625x, | 983 | .reg_type = ni_reg_625x, |
984 | .ao_unipolar = 0, | 984 | .ao_unipolar = 0, |
985 | .ao_speed = 357, | 985 | .ao_speed = 350, |
986 | .num_p0_dio_channels = 8, | 986 | .num_p0_dio_channels = 8, |
987 | .caldac = {caldac_none}, | 987 | .caldac = {caldac_none}, |
988 | .has_8255 = 0, | 988 | .has_8255 = 0, |
@@ -1001,7 +1001,7 @@ static const struct ni_board_struct ni_boards[] = { | |||
1001 | .ao_range_table = &range_ni_M_625x_ao, | 1001 | .ao_range_table = &range_ni_M_625x_ao, |
1002 | .reg_type = ni_reg_625x, | 1002 | .reg_type = ni_reg_625x, |
1003 | .ao_unipolar = 0, | 1003 | .ao_unipolar = 0, |
1004 | .ao_speed = 357, | 1004 | .ao_speed = 350, |
1005 | .num_p0_dio_channels = 8, | 1005 | .num_p0_dio_channels = 8, |
1006 | .caldac = {caldac_none}, | 1006 | .caldac = {caldac_none}, |
1007 | .has_8255 = 0, | 1007 | .has_8255 = 0, |
@@ -1037,7 +1037,7 @@ static const struct ni_board_struct ni_boards[] = { | |||
1037 | .ao_range_table = &range_ni_M_625x_ao, | 1037 | .ao_range_table = &range_ni_M_625x_ao, |
1038 | .reg_type = ni_reg_625x, | 1038 | .reg_type = ni_reg_625x, |
1039 | .ao_unipolar = 0, | 1039 | .ao_unipolar = 0, |
1040 | .ao_speed = 357, | 1040 | .ao_speed = 350, |
1041 | .num_p0_dio_channels = 32, | 1041 | .num_p0_dio_channels = 32, |
1042 | .caldac = {caldac_none}, | 1042 | .caldac = {caldac_none}, |
1043 | .has_8255 = 0, | 1043 | .has_8255 = 0, |
@@ -1056,7 +1056,7 @@ static const struct ni_board_struct ni_boards[] = { | |||
1056 | .ao_range_table = &range_ni_M_625x_ao, | 1056 | .ao_range_table = &range_ni_M_625x_ao, |
1057 | .reg_type = ni_reg_625x, | 1057 | .reg_type = ni_reg_625x, |
1058 | .ao_unipolar = 0, | 1058 | .ao_unipolar = 0, |
1059 | .ao_speed = 357, | 1059 | .ao_speed = 350, |
1060 | .num_p0_dio_channels = 32, | 1060 | .num_p0_dio_channels = 32, |
1061 | .caldac = {caldac_none}, | 1061 | .caldac = {caldac_none}, |
1062 | .has_8255 = 0, | 1062 | .has_8255 = 0, |
@@ -1092,7 +1092,7 @@ static const struct ni_board_struct ni_boards[] = { | |||
1092 | .ao_range_table = &range_ni_M_628x_ao, | 1092 | .ao_range_table = &range_ni_M_628x_ao, |
1093 | .reg_type = ni_reg_628x, | 1093 | .reg_type = ni_reg_628x, |
1094 | .ao_unipolar = 1, | 1094 | .ao_unipolar = 1, |
1095 | .ao_speed = 357, | 1095 | .ao_speed = 350, |
1096 | .num_p0_dio_channels = 8, | 1096 | .num_p0_dio_channels = 8, |
1097 | .caldac = {caldac_none}, | 1097 | .caldac = {caldac_none}, |
1098 | .has_8255 = 0, | 1098 | .has_8255 = 0, |
@@ -1111,7 +1111,7 @@ static const struct ni_board_struct ni_boards[] = { | |||
1111 | .ao_range_table = &range_ni_M_628x_ao, | 1111 | .ao_range_table = &range_ni_M_628x_ao, |
1112 | .reg_type = ni_reg_628x, | 1112 | .reg_type = ni_reg_628x, |
1113 | .ao_unipolar = 1, | 1113 | .ao_unipolar = 1, |
1114 | .ao_speed = 357, | 1114 | .ao_speed = 350, |
1115 | .num_p0_dio_channels = 8, | 1115 | .num_p0_dio_channels = 8, |
1116 | .caldac = {caldac_none}, | 1116 | .caldac = {caldac_none}, |
1117 | .has_8255 = 0, | 1117 | .has_8255 = 0, |
@@ -1147,7 +1147,7 @@ static const struct ni_board_struct ni_boards[] = { | |||
1147 | .ao_range_table = &range_ni_M_628x_ao, | 1147 | .ao_range_table = &range_ni_M_628x_ao, |
1148 | .reg_type = ni_reg_628x, | 1148 | .reg_type = ni_reg_628x, |
1149 | .ao_unipolar = 1, | 1149 | .ao_unipolar = 1, |
1150 | .ao_speed = 357, | 1150 | .ao_speed = 350, |
1151 | .num_p0_dio_channels = 32, | 1151 | .num_p0_dio_channels = 32, |
1152 | .caldac = {caldac_none}, | 1152 | .caldac = {caldac_none}, |
1153 | .has_8255 = 0, | 1153 | .has_8255 = 0, |
diff --git a/drivers/staging/fwserial/Kconfig b/drivers/staging/fwserial/Kconfig index 580406cb1808..b2f8331e4acf 100644 --- a/drivers/staging/fwserial/Kconfig +++ b/drivers/staging/fwserial/Kconfig | |||
@@ -3,7 +3,9 @@ config FIREWIRE_SERIAL | |||
3 | depends on FIREWIRE | 3 | depends on FIREWIRE |
4 | help | 4 | help |
5 | This enables TTY over IEEE 1394, providing high-speed serial | 5 | This enables TTY over IEEE 1394, providing high-speed serial |
6 | connectivity to cabled peers. | 6 | connectivity to cabled peers. This driver implements a |
7 | ad-hoc transport protocol and is currently limited to | ||
8 | Linux-to-Linux communication. | ||
7 | 9 | ||
8 | To compile this driver as a module, say M here: the module will | 10 | To compile this driver as a module, say M here: the module will |
9 | be called firewire-serial. | 11 | be called firewire-serial. |
diff --git a/drivers/staging/fwserial/TODO b/drivers/staging/fwserial/TODO index 726900548eae..8dae8fb25223 100644 --- a/drivers/staging/fwserial/TODO +++ b/drivers/staging/fwserial/TODO | |||
@@ -1,5 +1,5 @@ | |||
1 | TODOs | 1 | TODOs prior to this driver moving out of staging |
2 | ----- | 2 | ------------------------------------------------ |
3 | 1. Implement retries for RCODE_BUSY, RCODE_NO_ACK and RCODE_SEND_ERROR | 3 | 1. Implement retries for RCODE_BUSY, RCODE_NO_ACK and RCODE_SEND_ERROR |
4 | - I/O is handled asynchronously which presents some issues when error | 4 | - I/O is handled asynchronously which presents some issues when error |
5 | conditions occur. | 5 | conditions occur. |
@@ -11,17 +11,9 @@ TODOs | |||
11 | -- Issues with firewire stack -- | 11 | -- Issues with firewire stack -- |
12 | 1. This driver uses the same unregistered vendor id that the firewire core does | 12 | 1. This driver uses the same unregistered vendor id that the firewire core does |
13 | (0xd00d1e). Perhaps this could be exposed as a define in | 13 | (0xd00d1e). Perhaps this could be exposed as a define in |
14 | firewire-constants.h? | 14 | firewire.h? |
15 | 2. MAX_ASYNC_PAYLOAD needs to be publicly exposed by core/ohci | ||
16 | - otherwise how will this driver know the max size of address window to | ||
17 | open for one packet write? | ||
18 | 3. Maybe device_max_receive() and link_speed_to_max_payload() should be | 15 | 3. Maybe device_max_receive() and link_speed_to_max_payload() should be |
19 | taken up by the firewire core? | 16 | taken up by the firewire core? |
20 | 4. To avoid dropping rx data while still limiting the maximum buffering, | ||
21 | the size of the AR context must be known. How to expose this to drivers? | ||
22 | 5. Explore if bigger AR context will reduce RCODE_BUSY responses | ||
23 | (or auto-grow to certain max size -- but this would require major surgery | ||
24 | as the current AR is contiguously mapped) | ||
25 | 17 | ||
26 | -- Issues with TTY core -- | 18 | -- Issues with TTY core -- |
27 | 1. Hack for alternate device name scheme | 19 | 1. Hack for alternate device name scheme |
diff --git a/drivers/staging/fwserial/fwserial.c b/drivers/staging/fwserial/fwserial.c index 61ee29083b26..d03a7f57e8d4 100644 --- a/drivers/staging/fwserial/fwserial.c +++ b/drivers/staging/fwserial/fwserial.c | |||
@@ -179,7 +179,7 @@ static void dump_profile(struct seq_file *m, struct stats *stats) | |||
179 | /* Returns the max receive packet size for the given card */ | 179 | /* Returns the max receive packet size for the given card */ |
180 | static inline int device_max_receive(struct fw_device *fw_device) | 180 | static inline int device_max_receive(struct fw_device *fw_device) |
181 | { | 181 | { |
182 | return 1 << (clamp_t(int, fw_device->max_rec, 8U, 13U) + 1); | 182 | return 1 << (clamp_t(int, fw_device->max_rec, 8U, 11U) + 1); |
183 | } | 183 | } |
184 | 184 | ||
185 | static void fwtty_log_tx_error(struct fwtty_port *port, int rcode) | 185 | static void fwtty_log_tx_error(struct fwtty_port *port, int rcode) |
diff --git a/drivers/staging/fwserial/fwserial.h b/drivers/staging/fwserial/fwserial.h index 8b572edf9563..caa1c1ea82d5 100644 --- a/drivers/staging/fwserial/fwserial.h +++ b/drivers/staging/fwserial/fwserial.h | |||
@@ -374,10 +374,10 @@ static inline void fwtty_bind_console(struct fwtty_port *port, | |||
374 | */ | 374 | */ |
375 | static inline int link_speed_to_max_payload(unsigned speed) | 375 | static inline int link_speed_to_max_payload(unsigned speed) |
376 | { | 376 | { |
377 | static const int max_async[] = { 307, 614, 1229, 2458, 4916, 9832, }; | 377 | static const int max_async[] = { 307, 614, 1229, 2458, }; |
378 | BUILD_BUG_ON(ARRAY_SIZE(max_async) - 1 != SCODE_3200); | 378 | BUILD_BUG_ON(ARRAY_SIZE(max_async) - 1 != SCODE_800); |
379 | 379 | ||
380 | speed = clamp(speed, (unsigned) SCODE_100, (unsigned) SCODE_3200); | 380 | speed = clamp(speed, (unsigned) SCODE_100, (unsigned) SCODE_800); |
381 | if (limit_bw) | 381 | if (limit_bw) |
382 | return max_async[speed]; | 382 | return max_async[speed]; |
383 | else | 383 | else |
diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c index fb31b457a56a..c5ceb9d90ea8 100644 --- a/drivers/staging/iio/adc/mxs-lradc.c +++ b/drivers/staging/iio/adc/mxs-lradc.c | |||
@@ -239,7 +239,7 @@ static irqreturn_t mxs_lradc_trigger_handler(int irq, void *p) | |||
239 | struct mxs_lradc *lradc = iio_priv(iio); | 239 | struct mxs_lradc *lradc = iio_priv(iio); |
240 | const uint32_t chan_value = LRADC_CH_ACCUMULATE | | 240 | const uint32_t chan_value = LRADC_CH_ACCUMULATE | |
241 | ((LRADC_DELAY_TIMER_LOOP - 1) << LRADC_CH_NUM_SAMPLES_OFFSET); | 241 | ((LRADC_DELAY_TIMER_LOOP - 1) << LRADC_CH_NUM_SAMPLES_OFFSET); |
242 | int i, j = 0; | 242 | unsigned int i, j = 0; |
243 | 243 | ||
244 | for_each_set_bit(i, iio->active_scan_mask, iio->masklength) { | 244 | for_each_set_bit(i, iio->active_scan_mask, iio->masklength) { |
245 | lradc->buffer[j] = readl(lradc->base + LRADC_CH(j)); | 245 | lradc->buffer[j] = readl(lradc->base + LRADC_CH(j)); |
diff --git a/drivers/staging/iio/gyro/Kconfig b/drivers/staging/iio/gyro/Kconfig index ea295b25308c..87979a0d03a9 100644 --- a/drivers/staging/iio/gyro/Kconfig +++ b/drivers/staging/iio/gyro/Kconfig | |||
@@ -27,8 +27,8 @@ config ADIS16130 | |||
27 | config ADIS16260 | 27 | config ADIS16260 |
28 | tristate "Analog Devices ADIS16260 Digital Gyroscope Sensor SPI driver" | 28 | tristate "Analog Devices ADIS16260 Digital Gyroscope Sensor SPI driver" |
29 | depends on SPI | 29 | depends on SPI |
30 | select IIO_TRIGGER if IIO_BUFFER | 30 | select IIO_ADIS_LIB |
31 | select IIO_SW_RING if IIO_BUFFER | 31 | select IIO_ADIS_LIB_BUFFER if IIO_BUFFER |
32 | help | 32 | help |
33 | Say yes here to build support for Analog Devices ADIS16260 ADIS16265 | 33 | Say yes here to build support for Analog Devices ADIS16260 ADIS16265 |
34 | ADIS16250 ADIS16255 and ADIS16251 programmable digital gyroscope sensors. | 34 | ADIS16250 ADIS16255 and ADIS16251 programmable digital gyroscope sensors. |
diff --git a/drivers/staging/iio/gyro/adis16080_core.c b/drivers/staging/iio/gyro/adis16080_core.c index 3525a68d6a75..41d7350d030f 100644 --- a/drivers/staging/iio/gyro/adis16080_core.c +++ b/drivers/staging/iio/gyro/adis16080_core.c | |||
@@ -69,7 +69,7 @@ static int adis16080_spi_read(struct iio_dev *indio_dev, | |||
69 | ret = spi_read(st->us, st->buf, 2); | 69 | ret = spi_read(st->us, st->buf, 2); |
70 | 70 | ||
71 | if (ret == 0) | 71 | if (ret == 0) |
72 | *val = ((st->buf[0] & 0xF) << 8) | st->buf[1]; | 72 | *val = sign_extend32(((st->buf[0] & 0xF) << 8) | st->buf[1], 11); |
73 | mutex_unlock(&st->buf_lock); | 73 | mutex_unlock(&st->buf_lock); |
74 | 74 | ||
75 | return ret; | 75 | return ret; |
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c index ecf0f44bc70e..cec19f1cf56c 100644 --- a/drivers/staging/imx-drm/imx-drm-core.c +++ b/drivers/staging/imx-drm/imx-drm-core.c | |||
@@ -584,7 +584,6 @@ int imx_drm_add_encoder(struct drm_encoder *encoder, | |||
584 | 584 | ||
585 | ret = imx_drm_encoder_register(imx_drm_encoder); | 585 | ret = imx_drm_encoder_register(imx_drm_encoder); |
586 | if (ret) { | 586 | if (ret) { |
587 | kfree(imx_drm_encoder); | ||
588 | ret = -ENOMEM; | 587 | ret = -ENOMEM; |
589 | goto err_register; | 588 | goto err_register; |
590 | } | 589 | } |
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c index 677e665ca86d..f7059cddd7fd 100644 --- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c +++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c | |||
@@ -1104,7 +1104,9 @@ static int ipu_probe(struct platform_device *pdev) | |||
1104 | if (ret) | 1104 | if (ret) |
1105 | goto out_failed_irq; | 1105 | goto out_failed_irq; |
1106 | 1106 | ||
1107 | ipu_reset(ipu); | 1107 | ret = ipu_reset(ipu); |
1108 | if (ret) | ||
1109 | goto out_failed_reset; | ||
1108 | 1110 | ||
1109 | /* Set MCU_T to divide MCU access window into 2 */ | 1111 | /* Set MCU_T to divide MCU access window into 2 */ |
1110 | ipu_cm_write(ipu, 0x00400000L | (IPU_MCU_T_DEFAULT << 18), | 1112 | ipu_cm_write(ipu, 0x00400000L | (IPU_MCU_T_DEFAULT << 18), |
@@ -1129,6 +1131,7 @@ failed_add_clients: | |||
1129 | ipu_submodules_exit(ipu); | 1131 | ipu_submodules_exit(ipu); |
1130 | failed_submodules_init: | 1132 | failed_submodules_init: |
1131 | ipu_irq_exit(ipu); | 1133 | ipu_irq_exit(ipu); |
1134 | out_failed_reset: | ||
1132 | out_failed_irq: | 1135 | out_failed_irq: |
1133 | clk_disable_unprepare(ipu->clk); | 1136 | clk_disable_unprepare(ipu->clk); |
1134 | failed_clk_get: | 1137 | failed_clk_get: |
diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c index 1892006526b5..4b3a019409b5 100644 --- a/drivers/staging/imx-drm/ipuv3-crtc.c +++ b/drivers/staging/imx-drm/ipuv3-crtc.c | |||
@@ -452,7 +452,7 @@ static int ipu_get_resources(struct ipu_crtc *ipu_crtc, | |||
452 | int ret; | 452 | int ret; |
453 | 453 | ||
454 | ipu_crtc->ipu_ch = ipu_idmac_get(ipu, pdata->dma[0]); | 454 | ipu_crtc->ipu_ch = ipu_idmac_get(ipu, pdata->dma[0]); |
455 | if (IS_ERR_OR_NULL(ipu_crtc->ipu_ch)) { | 455 | if (IS_ERR(ipu_crtc->ipu_ch)) { |
456 | ret = PTR_ERR(ipu_crtc->ipu_ch); | 456 | ret = PTR_ERR(ipu_crtc->ipu_ch); |
457 | goto err_out; | 457 | goto err_out; |
458 | } | 458 | } |
@@ -472,7 +472,7 @@ static int ipu_get_resources(struct ipu_crtc *ipu_crtc, | |||
472 | if (pdata->dp >= 0) { | 472 | if (pdata->dp >= 0) { |
473 | ipu_crtc->dp = ipu_dp_get(ipu, pdata->dp); | 473 | ipu_crtc->dp = ipu_dp_get(ipu, pdata->dp); |
474 | if (IS_ERR(ipu_crtc->dp)) { | 474 | if (IS_ERR(ipu_crtc->dp)) { |
475 | ret = PTR_ERR(ipu_crtc->ipu_ch); | 475 | ret = PTR_ERR(ipu_crtc->dp); |
476 | goto err_out; | 476 | goto err_out; |
477 | } | 477 | } |
478 | } | 478 | } |
@@ -548,6 +548,8 @@ static int ipu_drm_probe(struct platform_device *pdev) | |||
548 | ipu_crtc->dev = &pdev->dev; | 548 | ipu_crtc->dev = &pdev->dev; |
549 | 549 | ||
550 | ret = ipu_crtc_init(ipu_crtc, pdata); | 550 | ret = ipu_crtc_init(ipu_crtc, pdata); |
551 | if (ret) | ||
552 | return ret; | ||
551 | 553 | ||
552 | platform_set_drvdata(pdev, ipu_crtc); | 554 | platform_set_drvdata(pdev, ipu_crtc); |
553 | 555 | ||
diff --git a/drivers/staging/omapdrm/Makefile b/drivers/staging/omapdrm/Makefile index 1ca0e0016de4..d85e058f2845 100644 --- a/drivers/staging/omapdrm/Makefile +++ b/drivers/staging/omapdrm/Makefile | |||
@@ -5,6 +5,7 @@ | |||
5 | 5 | ||
6 | ccflags-y := -Iinclude/drm -Werror | 6 | ccflags-y := -Iinclude/drm -Werror |
7 | omapdrm-y := omap_drv.o \ | 7 | omapdrm-y := omap_drv.o \ |
8 | omap_irq.o \ | ||
8 | omap_debugfs.o \ | 9 | omap_debugfs.o \ |
9 | omap_crtc.o \ | 10 | omap_crtc.o \ |
10 | omap_plane.o \ | 11 | omap_plane.o \ |
diff --git a/drivers/staging/omapdrm/TODO b/drivers/staging/omapdrm/TODO index 938c7888ca31..abeeb00aaa12 100644 --- a/drivers/staging/omapdrm/TODO +++ b/drivers/staging/omapdrm/TODO | |||
@@ -17,9 +17,6 @@ TODO | |||
17 | . Revisit GEM sync object infrastructure.. TTM has some framework for this | 17 | . Revisit GEM sync object infrastructure.. TTM has some framework for this |
18 | already. Possibly this could be refactored out and made more common? | 18 | already. Possibly this could be refactored out and made more common? |
19 | There should be some way to do this with less wheel-reinvention. | 19 | There should be some way to do this with less wheel-reinvention. |
20 | . Review DSS vs KMS mismatches. The omap_dss_device is sort of part encoder, | ||
21 | part connector. Which results in a bit of duct tape to fwd calls from | ||
22 | encoder to connector. Possibly this could be done a bit better. | ||
23 | . Solve PM sequencing on resume. DMM/TILER must be reloaded before any | 20 | . Solve PM sequencing on resume. DMM/TILER must be reloaded before any |
24 | access is made from any component in the system. Which means on suspend | 21 | access is made from any component in the system. Which means on suspend |
25 | CRTC's should be disabled, and on resume the LUT should be reprogrammed | 22 | CRTC's should be disabled, and on resume the LUT should be reprogrammed |
diff --git a/drivers/staging/omapdrm/omap_connector.c b/drivers/staging/omapdrm/omap_connector.c index 91edb3f96972..4cc9ee733c5f 100644 --- a/drivers/staging/omapdrm/omap_connector.c +++ b/drivers/staging/omapdrm/omap_connector.c | |||
@@ -31,9 +31,10 @@ | |||
31 | struct omap_connector { | 31 | struct omap_connector { |
32 | struct drm_connector base; | 32 | struct drm_connector base; |
33 | struct omap_dss_device *dssdev; | 33 | struct omap_dss_device *dssdev; |
34 | struct drm_encoder *encoder; | ||
34 | }; | 35 | }; |
35 | 36 | ||
36 | static inline void copy_timings_omap_to_drm(struct drm_display_mode *mode, | 37 | void copy_timings_omap_to_drm(struct drm_display_mode *mode, |
37 | struct omap_video_timings *timings) | 38 | struct omap_video_timings *timings) |
38 | { | 39 | { |
39 | mode->clock = timings->pixel_clock; | 40 | mode->clock = timings->pixel_clock; |
@@ -64,7 +65,7 @@ static inline void copy_timings_omap_to_drm(struct drm_display_mode *mode, | |||
64 | mode->flags |= DRM_MODE_FLAG_NVSYNC; | 65 | mode->flags |= DRM_MODE_FLAG_NVSYNC; |
65 | } | 66 | } |
66 | 67 | ||
67 | static inline void copy_timings_drm_to_omap(struct omap_video_timings *timings, | 68 | void copy_timings_drm_to_omap(struct omap_video_timings *timings, |
68 | struct drm_display_mode *mode) | 69 | struct drm_display_mode *mode) |
69 | { | 70 | { |
70 | timings->pixel_clock = mode->clock; | 71 | timings->pixel_clock = mode->clock; |
@@ -96,48 +97,7 @@ static inline void copy_timings_drm_to_omap(struct omap_video_timings *timings, | |||
96 | timings->sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; | 97 | timings->sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; |
97 | } | 98 | } |
98 | 99 | ||
99 | static void omap_connector_dpms(struct drm_connector *connector, int mode) | 100 | static enum drm_connector_status omap_connector_detect( |
100 | { | ||
101 | struct omap_connector *omap_connector = to_omap_connector(connector); | ||
102 | struct omap_dss_device *dssdev = omap_connector->dssdev; | ||
103 | int old_dpms; | ||
104 | |||
105 | DBG("%s: %d", dssdev->name, mode); | ||
106 | |||
107 | old_dpms = connector->dpms; | ||
108 | |||
109 | /* from off to on, do from crtc to connector */ | ||
110 | if (mode < old_dpms) | ||
111 | drm_helper_connector_dpms(connector, mode); | ||
112 | |||
113 | if (mode == DRM_MODE_DPMS_ON) { | ||
114 | /* store resume info for suspended displays */ | ||
115 | switch (dssdev->state) { | ||
116 | case OMAP_DSS_DISPLAY_SUSPENDED: | ||
117 | dssdev->activate_after_resume = true; | ||
118 | break; | ||
119 | case OMAP_DSS_DISPLAY_DISABLED: { | ||
120 | int ret = dssdev->driver->enable(dssdev); | ||
121 | if (ret) { | ||
122 | DBG("%s: failed to enable: %d", | ||
123 | dssdev->name, ret); | ||
124 | dssdev->driver->disable(dssdev); | ||
125 | } | ||
126 | break; | ||
127 | } | ||
128 | default: | ||
129 | break; | ||
130 | } | ||
131 | } else { | ||
132 | /* TODO */ | ||
133 | } | ||
134 | |||
135 | /* from on to off, do from connector to crtc */ | ||
136 | if (mode > old_dpms) | ||
137 | drm_helper_connector_dpms(connector, mode); | ||
138 | } | ||
139 | |||
140 | enum drm_connector_status omap_connector_detect( | ||
141 | struct drm_connector *connector, bool force) | 101 | struct drm_connector *connector, bool force) |
142 | { | 102 | { |
143 | struct omap_connector *omap_connector = to_omap_connector(connector); | 103 | struct omap_connector *omap_connector = to_omap_connector(connector); |
@@ -164,8 +124,6 @@ static void omap_connector_destroy(struct drm_connector *connector) | |||
164 | struct omap_connector *omap_connector = to_omap_connector(connector); | 124 | struct omap_connector *omap_connector = to_omap_connector(connector); |
165 | struct omap_dss_device *dssdev = omap_connector->dssdev; | 125 | struct omap_dss_device *dssdev = omap_connector->dssdev; |
166 | 126 | ||
167 | dssdev->driver->disable(dssdev); | ||
168 | |||
169 | DBG("%s", omap_connector->dssdev->name); | 127 | DBG("%s", omap_connector->dssdev->name); |
170 | drm_sysfs_connector_remove(connector); | 128 | drm_sysfs_connector_remove(connector); |
171 | drm_connector_cleanup(connector); | 129 | drm_connector_cleanup(connector); |
@@ -261,36 +219,12 @@ static int omap_connector_mode_valid(struct drm_connector *connector, | |||
261 | struct drm_encoder *omap_connector_attached_encoder( | 219 | struct drm_encoder *omap_connector_attached_encoder( |
262 | struct drm_connector *connector) | 220 | struct drm_connector *connector) |
263 | { | 221 | { |
264 | int i; | ||
265 | struct omap_connector *omap_connector = to_omap_connector(connector); | 222 | struct omap_connector *omap_connector = to_omap_connector(connector); |
266 | 223 | return omap_connector->encoder; | |
267 | for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { | ||
268 | struct drm_mode_object *obj; | ||
269 | |||
270 | if (connector->encoder_ids[i] == 0) | ||
271 | break; | ||
272 | |||
273 | obj = drm_mode_object_find(connector->dev, | ||
274 | connector->encoder_ids[i], | ||
275 | DRM_MODE_OBJECT_ENCODER); | ||
276 | |||
277 | if (obj) { | ||
278 | struct drm_encoder *encoder = obj_to_encoder(obj); | ||
279 | struct omap_overlay_manager *mgr = | ||
280 | omap_encoder_get_manager(encoder); | ||
281 | DBG("%s: found %s", omap_connector->dssdev->name, | ||
282 | mgr->name); | ||
283 | return encoder; | ||
284 | } | ||
285 | } | ||
286 | |||
287 | DBG("%s: no encoder", omap_connector->dssdev->name); | ||
288 | |||
289 | return NULL; | ||
290 | } | 224 | } |
291 | 225 | ||
292 | static const struct drm_connector_funcs omap_connector_funcs = { | 226 | static const struct drm_connector_funcs omap_connector_funcs = { |
293 | .dpms = omap_connector_dpms, | 227 | .dpms = drm_helper_connector_dpms, |
294 | .detect = omap_connector_detect, | 228 | .detect = omap_connector_detect, |
295 | .fill_modes = drm_helper_probe_single_connector_modes, | 229 | .fill_modes = drm_helper_probe_single_connector_modes, |
296 | .destroy = omap_connector_destroy, | 230 | .destroy = omap_connector_destroy, |
@@ -302,34 +236,6 @@ static const struct drm_connector_helper_funcs omap_connector_helper_funcs = { | |||
302 | .best_encoder = omap_connector_attached_encoder, | 236 | .best_encoder = omap_connector_attached_encoder, |
303 | }; | 237 | }; |
304 | 238 | ||
305 | /* called from encoder when mode is set, to propagate settings to the dssdev */ | ||
306 | void omap_connector_mode_set(struct drm_connector *connector, | ||
307 | struct drm_display_mode *mode) | ||
308 | { | ||
309 | struct drm_device *dev = connector->dev; | ||
310 | struct omap_connector *omap_connector = to_omap_connector(connector); | ||
311 | struct omap_dss_device *dssdev = omap_connector->dssdev; | ||
312 | struct omap_dss_driver *dssdrv = dssdev->driver; | ||
313 | struct omap_video_timings timings = {0}; | ||
314 | |||
315 | copy_timings_drm_to_omap(&timings, mode); | ||
316 | |||
317 | DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", | ||
318 | omap_connector->dssdev->name, | ||
319 | mode->base.id, mode->name, mode->vrefresh, mode->clock, | ||
320 | mode->hdisplay, mode->hsync_start, | ||
321 | mode->hsync_end, mode->htotal, | ||
322 | mode->vdisplay, mode->vsync_start, | ||
323 | mode->vsync_end, mode->vtotal, mode->type, mode->flags); | ||
324 | |||
325 | if (dssdrv->check_timings(dssdev, &timings)) { | ||
326 | dev_err(dev->dev, "could not set timings\n"); | ||
327 | return; | ||
328 | } | ||
329 | |||
330 | dssdrv->set_timings(dssdev, &timings); | ||
331 | } | ||
332 | |||
333 | /* flush an area of the framebuffer (in case of manual update display that | 239 | /* flush an area of the framebuffer (in case of manual update display that |
334 | * is not automatically flushed) | 240 | * is not automatically flushed) |
335 | */ | 241 | */ |
@@ -344,7 +250,8 @@ void omap_connector_flush(struct drm_connector *connector, | |||
344 | 250 | ||
345 | /* initialize connector */ | 251 | /* initialize connector */ |
346 | struct drm_connector *omap_connector_init(struct drm_device *dev, | 252 | struct drm_connector *omap_connector_init(struct drm_device *dev, |
347 | int connector_type, struct omap_dss_device *dssdev) | 253 | int connector_type, struct omap_dss_device *dssdev, |
254 | struct drm_encoder *encoder) | ||
348 | { | 255 | { |
349 | struct drm_connector *connector = NULL; | 256 | struct drm_connector *connector = NULL; |
350 | struct omap_connector *omap_connector; | 257 | struct omap_connector *omap_connector; |
@@ -360,6 +267,8 @@ struct drm_connector *omap_connector_init(struct drm_device *dev, | |||
360 | } | 267 | } |
361 | 268 | ||
362 | omap_connector->dssdev = dssdev; | 269 | omap_connector->dssdev = dssdev; |
270 | omap_connector->encoder = encoder; | ||
271 | |||
363 | connector = &omap_connector->base; | 272 | connector = &omap_connector->base; |
364 | 273 | ||
365 | drm_connector_init(dev, connector, &omap_connector_funcs, | 274 | drm_connector_init(dev, connector, &omap_connector_funcs, |
diff --git a/drivers/staging/omapdrm/omap_crtc.c b/drivers/staging/omapdrm/omap_crtc.c index d87bd84257bd..5c6ed6040eff 100644 --- a/drivers/staging/omapdrm/omap_crtc.c +++ b/drivers/staging/omapdrm/omap_crtc.c | |||
@@ -28,19 +28,131 @@ | |||
28 | struct omap_crtc { | 28 | struct omap_crtc { |
29 | struct drm_crtc base; | 29 | struct drm_crtc base; |
30 | struct drm_plane *plane; | 30 | struct drm_plane *plane; |
31 | |||
31 | const char *name; | 32 | const char *name; |
32 | int id; | 33 | int pipe; |
34 | enum omap_channel channel; | ||
35 | struct omap_overlay_manager_info info; | ||
36 | |||
37 | /* | ||
38 | * Temporary: eventually this will go away, but it is needed | ||
39 | * for now to keep the output's happy. (They only need | ||
40 | * mgr->id.) Eventually this will be replaced w/ something | ||
41 | * more common-panel-framework-y | ||
42 | */ | ||
43 | struct omap_overlay_manager mgr; | ||
44 | |||
45 | struct omap_video_timings timings; | ||
46 | bool enabled; | ||
47 | bool full_update; | ||
48 | |||
49 | struct omap_drm_apply apply; | ||
50 | |||
51 | struct omap_drm_irq apply_irq; | ||
52 | struct omap_drm_irq error_irq; | ||
53 | |||
54 | /* list of in-progress apply's: */ | ||
55 | struct list_head pending_applies; | ||
56 | |||
57 | /* list of queued apply's: */ | ||
58 | struct list_head queued_applies; | ||
59 | |||
60 | /* for handling queued and in-progress applies: */ | ||
61 | struct work_struct apply_work; | ||
33 | 62 | ||
34 | /* if there is a pending flip, these will be non-null: */ | 63 | /* if there is a pending flip, these will be non-null: */ |
35 | struct drm_pending_vblank_event *event; | 64 | struct drm_pending_vblank_event *event; |
36 | struct drm_framebuffer *old_fb; | 65 | struct drm_framebuffer *old_fb; |
66 | |||
67 | /* for handling page flips without caring about what | ||
68 | * the callback is called from. Possibly we should just | ||
69 | * make omap_gem always call the cb from the worker so | ||
70 | * we don't have to care about this.. | ||
71 | * | ||
72 | * XXX maybe fold into apply_work?? | ||
73 | */ | ||
74 | struct work_struct page_flip_work; | ||
75 | }; | ||
76 | |||
77 | /* | ||
78 | * Manager-ops, callbacks from output when they need to configure | ||
79 | * the upstream part of the video pipe. | ||
80 | * | ||
81 | * Most of these we can ignore until we add support for command-mode | ||
82 | * panels.. for video-mode the crtc-helpers already do an adequate | ||
83 | * job of sequencing the setup of the video pipe in the proper order | ||
84 | */ | ||
85 | |||
86 | /* we can probably ignore these until we support command-mode panels: */ | ||
87 | static void omap_crtc_start_update(struct omap_overlay_manager *mgr) | ||
88 | { | ||
89 | } | ||
90 | |||
91 | static int omap_crtc_enable(struct omap_overlay_manager *mgr) | ||
92 | { | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | static void omap_crtc_disable(struct omap_overlay_manager *mgr) | ||
97 | { | ||
98 | } | ||
99 | |||
100 | static void omap_crtc_set_timings(struct omap_overlay_manager *mgr, | ||
101 | const struct omap_video_timings *timings) | ||
102 | { | ||
103 | struct omap_crtc *omap_crtc = container_of(mgr, struct omap_crtc, mgr); | ||
104 | DBG("%s", omap_crtc->name); | ||
105 | omap_crtc->timings = *timings; | ||
106 | omap_crtc->full_update = true; | ||
107 | } | ||
108 | |||
109 | static void omap_crtc_set_lcd_config(struct omap_overlay_manager *mgr, | ||
110 | const struct dss_lcd_mgr_config *config) | ||
111 | { | ||
112 | struct omap_crtc *omap_crtc = container_of(mgr, struct omap_crtc, mgr); | ||
113 | DBG("%s", omap_crtc->name); | ||
114 | dispc_mgr_set_lcd_config(omap_crtc->channel, config); | ||
115 | } | ||
116 | |||
117 | static int omap_crtc_register_framedone_handler( | ||
118 | struct omap_overlay_manager *mgr, | ||
119 | void (*handler)(void *), void *data) | ||
120 | { | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | static void omap_crtc_unregister_framedone_handler( | ||
125 | struct omap_overlay_manager *mgr, | ||
126 | void (*handler)(void *), void *data) | ||
127 | { | ||
128 | } | ||
129 | |||
130 | static const struct dss_mgr_ops mgr_ops = { | ||
131 | .start_update = omap_crtc_start_update, | ||
132 | .enable = omap_crtc_enable, | ||
133 | .disable = omap_crtc_disable, | ||
134 | .set_timings = omap_crtc_set_timings, | ||
135 | .set_lcd_config = omap_crtc_set_lcd_config, | ||
136 | .register_framedone_handler = omap_crtc_register_framedone_handler, | ||
137 | .unregister_framedone_handler = omap_crtc_unregister_framedone_handler, | ||
37 | }; | 138 | }; |
38 | 139 | ||
140 | /* | ||
141 | * CRTC funcs: | ||
142 | */ | ||
143 | |||
39 | static void omap_crtc_destroy(struct drm_crtc *crtc) | 144 | static void omap_crtc_destroy(struct drm_crtc *crtc) |
40 | { | 145 | { |
41 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | 146 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); |
147 | |||
148 | DBG("%s", omap_crtc->name); | ||
149 | |||
150 | WARN_ON(omap_crtc->apply_irq.registered); | ||
151 | omap_irq_unregister(crtc->dev, &omap_crtc->error_irq); | ||
152 | |||
42 | omap_crtc->plane->funcs->destroy(omap_crtc->plane); | 153 | omap_crtc->plane->funcs->destroy(omap_crtc->plane); |
43 | drm_crtc_cleanup(crtc); | 154 | drm_crtc_cleanup(crtc); |
155 | |||
44 | kfree(omap_crtc); | 156 | kfree(omap_crtc); |
45 | } | 157 | } |
46 | 158 | ||
@@ -48,14 +160,25 @@ static void omap_crtc_dpms(struct drm_crtc *crtc, int mode) | |||
48 | { | 160 | { |
49 | struct omap_drm_private *priv = crtc->dev->dev_private; | 161 | struct omap_drm_private *priv = crtc->dev->dev_private; |
50 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | 162 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); |
163 | bool enabled = (mode == DRM_MODE_DPMS_ON); | ||
51 | int i; | 164 | int i; |
52 | 165 | ||
53 | WARN_ON(omap_plane_dpms(omap_crtc->plane, mode)); | 166 | DBG("%s: %d", omap_crtc->name, mode); |
167 | |||
168 | if (enabled != omap_crtc->enabled) { | ||
169 | omap_crtc->enabled = enabled; | ||
170 | omap_crtc->full_update = true; | ||
171 | omap_crtc_apply(crtc, &omap_crtc->apply); | ||
54 | 172 | ||
55 | for (i = 0; i < priv->num_planes; i++) { | 173 | /* also enable our private plane: */ |
56 | struct drm_plane *plane = priv->planes[i]; | 174 | WARN_ON(omap_plane_dpms(omap_crtc->plane, mode)); |
57 | if (plane->crtc == crtc) | 175 | |
58 | WARN_ON(omap_plane_dpms(plane, mode)); | 176 | /* and any attached overlay planes: */ |
177 | for (i = 0; i < priv->num_planes; i++) { | ||
178 | struct drm_plane *plane = priv->planes[i]; | ||
179 | if (plane->crtc == crtc) | ||
180 | WARN_ON(omap_plane_dpms(plane, mode)); | ||
181 | } | ||
59 | } | 182 | } |
60 | } | 183 | } |
61 | 184 | ||
@@ -73,12 +196,26 @@ static int omap_crtc_mode_set(struct drm_crtc *crtc, | |||
73 | struct drm_framebuffer *old_fb) | 196 | struct drm_framebuffer *old_fb) |
74 | { | 197 | { |
75 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | 198 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); |
76 | struct drm_plane *plane = omap_crtc->plane; | ||
77 | 199 | ||
78 | return omap_plane_mode_set(plane, crtc, crtc->fb, | 200 | mode = adjusted_mode; |
201 | |||
202 | DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", | ||
203 | omap_crtc->name, mode->base.id, mode->name, | ||
204 | mode->vrefresh, mode->clock, | ||
205 | mode->hdisplay, mode->hsync_start, | ||
206 | mode->hsync_end, mode->htotal, | ||
207 | mode->vdisplay, mode->vsync_start, | ||
208 | mode->vsync_end, mode->vtotal, | ||
209 | mode->type, mode->flags); | ||
210 | |||
211 | copy_timings_drm_to_omap(&omap_crtc->timings, mode); | ||
212 | omap_crtc->full_update = true; | ||
213 | |||
214 | return omap_plane_mode_set(omap_crtc->plane, crtc, crtc->fb, | ||
79 | 0, 0, mode->hdisplay, mode->vdisplay, | 215 | 0, 0, mode->hdisplay, mode->vdisplay, |
80 | x << 16, y << 16, | 216 | x << 16, y << 16, |
81 | mode->hdisplay << 16, mode->vdisplay << 16); | 217 | mode->hdisplay << 16, mode->vdisplay << 16, |
218 | NULL, NULL); | ||
82 | } | 219 | } |
83 | 220 | ||
84 | static void omap_crtc_prepare(struct drm_crtc *crtc) | 221 | static void omap_crtc_prepare(struct drm_crtc *crtc) |
@@ -102,10 +239,11 @@ static int omap_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, | |||
102 | struct drm_plane *plane = omap_crtc->plane; | 239 | struct drm_plane *plane = omap_crtc->plane; |
103 | struct drm_display_mode *mode = &crtc->mode; | 240 | struct drm_display_mode *mode = &crtc->mode; |
104 | 241 | ||
105 | return plane->funcs->update_plane(plane, crtc, crtc->fb, | 242 | return omap_plane_mode_set(plane, crtc, crtc->fb, |
106 | 0, 0, mode->hdisplay, mode->vdisplay, | 243 | 0, 0, mode->hdisplay, mode->vdisplay, |
107 | x << 16, y << 16, | 244 | x << 16, y << 16, |
108 | mode->hdisplay << 16, mode->vdisplay << 16); | 245 | mode->hdisplay << 16, mode->vdisplay << 16, |
246 | NULL, NULL); | ||
109 | } | 247 | } |
110 | 248 | ||
111 | static void omap_crtc_load_lut(struct drm_crtc *crtc) | 249 | static void omap_crtc_load_lut(struct drm_crtc *crtc) |
@@ -114,63 +252,54 @@ static void omap_crtc_load_lut(struct drm_crtc *crtc) | |||
114 | 252 | ||
115 | static void vblank_cb(void *arg) | 253 | static void vblank_cb(void *arg) |
116 | { | 254 | { |
117 | static uint32_t sequence; | ||
118 | struct drm_crtc *crtc = arg; | 255 | struct drm_crtc *crtc = arg; |
119 | struct drm_device *dev = crtc->dev; | 256 | struct drm_device *dev = crtc->dev; |
120 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | 257 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); |
121 | struct drm_pending_vblank_event *event = omap_crtc->event; | ||
122 | unsigned long flags; | 258 | unsigned long flags; |
123 | struct timeval now; | ||
124 | 259 | ||
125 | WARN_ON(!event); | 260 | spin_lock_irqsave(&dev->event_lock, flags); |
261 | |||
262 | /* wakeup userspace */ | ||
263 | if (omap_crtc->event) | ||
264 | drm_send_vblank_event(dev, omap_crtc->pipe, omap_crtc->event); | ||
126 | 265 | ||
127 | omap_crtc->event = NULL; | 266 | omap_crtc->event = NULL; |
267 | omap_crtc->old_fb = NULL; | ||
128 | 268 | ||
129 | /* wakeup userspace */ | 269 | spin_unlock_irqrestore(&dev->event_lock, flags); |
130 | if (event) { | ||
131 | do_gettimeofday(&now); | ||
132 | |||
133 | spin_lock_irqsave(&dev->event_lock, flags); | ||
134 | /* TODO: we can't yet use the vblank time accounting, | ||
135 | * because omapdss lower layer is the one that knows | ||
136 | * the irq # and registers the handler, which more or | ||
137 | * less defeats how drm_irq works.. for now just fake | ||
138 | * the sequence number and use gettimeofday.. | ||
139 | * | ||
140 | event->event.sequence = drm_vblank_count_and_time( | ||
141 | dev, omap_crtc->id, &now); | ||
142 | */ | ||
143 | event->event.sequence = sequence++; | ||
144 | event->event.tv_sec = now.tv_sec; | ||
145 | event->event.tv_usec = now.tv_usec; | ||
146 | list_add_tail(&event->base.link, | ||
147 | &event->base.file_priv->event_list); | ||
148 | wake_up_interruptible(&event->base.file_priv->event_wait); | ||
149 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
150 | } | ||
151 | } | 270 | } |
152 | 271 | ||
153 | static void page_flip_cb(void *arg) | 272 | static void page_flip_worker(struct work_struct *work) |
154 | { | 273 | { |
155 | struct drm_crtc *crtc = arg; | 274 | struct omap_crtc *omap_crtc = |
156 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | 275 | container_of(work, struct omap_crtc, page_flip_work); |
157 | struct drm_framebuffer *old_fb = omap_crtc->old_fb; | 276 | struct drm_crtc *crtc = &omap_crtc->base; |
277 | struct drm_device *dev = crtc->dev; | ||
278 | struct drm_display_mode *mode = &crtc->mode; | ||
158 | struct drm_gem_object *bo; | 279 | struct drm_gem_object *bo; |
159 | 280 | ||
160 | omap_crtc->old_fb = NULL; | 281 | mutex_lock(&dev->mode_config.mutex); |
161 | 282 | omap_plane_mode_set(omap_crtc->plane, crtc, crtc->fb, | |
162 | omap_crtc_mode_set_base(crtc, crtc->x, crtc->y, old_fb); | 283 | 0, 0, mode->hdisplay, mode->vdisplay, |
163 | 284 | crtc->x << 16, crtc->y << 16, | |
164 | /* really we'd like to setup the callback atomically w/ setting the | 285 | mode->hdisplay << 16, mode->vdisplay << 16, |
165 | * new scanout buffer to avoid getting stuck waiting an extra vblank | 286 | vblank_cb, crtc); |
166 | * cycle.. for now go for correctness and later figure out speed.. | 287 | mutex_unlock(&dev->mode_config.mutex); |
167 | */ | ||
168 | omap_plane_on_endwin(omap_crtc->plane, vblank_cb, crtc); | ||
169 | 288 | ||
170 | bo = omap_framebuffer_bo(crtc->fb, 0); | 289 | bo = omap_framebuffer_bo(crtc->fb, 0); |
171 | drm_gem_object_unreference_unlocked(bo); | 290 | drm_gem_object_unreference_unlocked(bo); |
172 | } | 291 | } |
173 | 292 | ||
293 | static void page_flip_cb(void *arg) | ||
294 | { | ||
295 | struct drm_crtc *crtc = arg; | ||
296 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | ||
297 | struct omap_drm_private *priv = crtc->dev->dev_private; | ||
298 | |||
299 | /* avoid assumptions about what ctxt we are called from: */ | ||
300 | queue_work(priv->wq, &omap_crtc->page_flip_work); | ||
301 | } | ||
302 | |||
174 | static int omap_crtc_page_flip_locked(struct drm_crtc *crtc, | 303 | static int omap_crtc_page_flip_locked(struct drm_crtc *crtc, |
175 | struct drm_framebuffer *fb, | 304 | struct drm_framebuffer *fb, |
176 | struct drm_pending_vblank_event *event) | 305 | struct drm_pending_vblank_event *event) |
@@ -179,14 +308,14 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc, | |||
179 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | 308 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); |
180 | struct drm_gem_object *bo; | 309 | struct drm_gem_object *bo; |
181 | 310 | ||
182 | DBG("%d -> %d", crtc->fb ? crtc->fb->base.id : -1, fb->base.id); | 311 | DBG("%d -> %d (event=%p)", crtc->fb ? crtc->fb->base.id : -1, |
312 | fb->base.id, event); | ||
183 | 313 | ||
184 | if (omap_crtc->event) { | 314 | if (omap_crtc->old_fb) { |
185 | dev_err(dev->dev, "already a pending flip\n"); | 315 | dev_err(dev->dev, "already a pending flip\n"); |
186 | return -EINVAL; | 316 | return -EINVAL; |
187 | } | 317 | } |
188 | 318 | ||
189 | omap_crtc->old_fb = crtc->fb; | ||
190 | omap_crtc->event = event; | 319 | omap_crtc->event = event; |
191 | crtc->fb = fb; | 320 | crtc->fb = fb; |
192 | 321 | ||
@@ -234,14 +363,244 @@ static const struct drm_crtc_helper_funcs omap_crtc_helper_funcs = { | |||
234 | .load_lut = omap_crtc_load_lut, | 363 | .load_lut = omap_crtc_load_lut, |
235 | }; | 364 | }; |
236 | 365 | ||
366 | const struct omap_video_timings *omap_crtc_timings(struct drm_crtc *crtc) | ||
367 | { | ||
368 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | ||
369 | return &omap_crtc->timings; | ||
370 | } | ||
371 | |||
372 | enum omap_channel omap_crtc_channel(struct drm_crtc *crtc) | ||
373 | { | ||
374 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | ||
375 | return omap_crtc->channel; | ||
376 | } | ||
377 | |||
378 | static void omap_crtc_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus) | ||
379 | { | ||
380 | struct omap_crtc *omap_crtc = | ||
381 | container_of(irq, struct omap_crtc, error_irq); | ||
382 | struct drm_crtc *crtc = &omap_crtc->base; | ||
383 | DRM_ERROR("%s: errors: %08x\n", omap_crtc->name, irqstatus); | ||
384 | /* avoid getting in a flood, unregister the irq until next vblank */ | ||
385 | omap_irq_unregister(crtc->dev, &omap_crtc->error_irq); | ||
386 | } | ||
387 | |||
388 | static void omap_crtc_apply_irq(struct omap_drm_irq *irq, uint32_t irqstatus) | ||
389 | { | ||
390 | struct omap_crtc *omap_crtc = | ||
391 | container_of(irq, struct omap_crtc, apply_irq); | ||
392 | struct drm_crtc *crtc = &omap_crtc->base; | ||
393 | |||
394 | if (!omap_crtc->error_irq.registered) | ||
395 | omap_irq_register(crtc->dev, &omap_crtc->error_irq); | ||
396 | |||
397 | if (!dispc_mgr_go_busy(omap_crtc->channel)) { | ||
398 | struct omap_drm_private *priv = | ||
399 | crtc->dev->dev_private; | ||
400 | DBG("%s: apply done", omap_crtc->name); | ||
401 | omap_irq_unregister(crtc->dev, &omap_crtc->apply_irq); | ||
402 | queue_work(priv->wq, &omap_crtc->apply_work); | ||
403 | } | ||
404 | } | ||
405 | |||
406 | static void apply_worker(struct work_struct *work) | ||
407 | { | ||
408 | struct omap_crtc *omap_crtc = | ||
409 | container_of(work, struct omap_crtc, apply_work); | ||
410 | struct drm_crtc *crtc = &omap_crtc->base; | ||
411 | struct drm_device *dev = crtc->dev; | ||
412 | struct omap_drm_apply *apply, *n; | ||
413 | bool need_apply; | ||
414 | |||
415 | /* | ||
416 | * Synchronize everything on mode_config.mutex, to keep | ||
417 | * the callbacks and list modification all serialized | ||
418 | * with respect to modesetting ioctls from userspace. | ||
419 | */ | ||
420 | mutex_lock(&dev->mode_config.mutex); | ||
421 | dispc_runtime_get(); | ||
422 | |||
423 | /* | ||
424 | * If we are still pending a previous update, wait.. when the | ||
425 | * pending update completes, we get kicked again. | ||
426 | */ | ||
427 | if (omap_crtc->apply_irq.registered) | ||
428 | goto out; | ||
429 | |||
430 | /* finish up previous apply's: */ | ||
431 | list_for_each_entry_safe(apply, n, | ||
432 | &omap_crtc->pending_applies, pending_node) { | ||
433 | apply->post_apply(apply); | ||
434 | list_del(&apply->pending_node); | ||
435 | } | ||
436 | |||
437 | need_apply = !list_empty(&omap_crtc->queued_applies); | ||
438 | |||
439 | /* then handle the next round of of queued apply's: */ | ||
440 | list_for_each_entry_safe(apply, n, | ||
441 | &omap_crtc->queued_applies, queued_node) { | ||
442 | apply->pre_apply(apply); | ||
443 | list_del(&apply->queued_node); | ||
444 | apply->queued = false; | ||
445 | list_add_tail(&apply->pending_node, | ||
446 | &omap_crtc->pending_applies); | ||
447 | } | ||
448 | |||
449 | if (need_apply) { | ||
450 | enum omap_channel channel = omap_crtc->channel; | ||
451 | |||
452 | DBG("%s: GO", omap_crtc->name); | ||
453 | |||
454 | if (dispc_mgr_is_enabled(channel)) { | ||
455 | omap_irq_register(dev, &omap_crtc->apply_irq); | ||
456 | dispc_mgr_go(channel); | ||
457 | } else { | ||
458 | struct omap_drm_private *priv = dev->dev_private; | ||
459 | queue_work(priv->wq, &omap_crtc->apply_work); | ||
460 | } | ||
461 | } | ||
462 | |||
463 | out: | ||
464 | dispc_runtime_put(); | ||
465 | mutex_unlock(&dev->mode_config.mutex); | ||
466 | } | ||
467 | |||
468 | int omap_crtc_apply(struct drm_crtc *crtc, | ||
469 | struct omap_drm_apply *apply) | ||
470 | { | ||
471 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | ||
472 | struct drm_device *dev = crtc->dev; | ||
473 | |||
474 | WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); | ||
475 | |||
476 | /* no need to queue it again if it is already queued: */ | ||
477 | if (apply->queued) | ||
478 | return 0; | ||
479 | |||
480 | apply->queued = true; | ||
481 | list_add_tail(&apply->queued_node, &omap_crtc->queued_applies); | ||
482 | |||
483 | /* | ||
484 | * If there are no currently pending updates, then go ahead and | ||
485 | * kick the worker immediately, otherwise it will run again when | ||
486 | * the current update finishes. | ||
487 | */ | ||
488 | if (list_empty(&omap_crtc->pending_applies)) { | ||
489 | struct omap_drm_private *priv = crtc->dev->dev_private; | ||
490 | queue_work(priv->wq, &omap_crtc->apply_work); | ||
491 | } | ||
492 | |||
493 | return 0; | ||
494 | } | ||
495 | |||
496 | /* called only from apply */ | ||
497 | static void set_enabled(struct drm_crtc *crtc, bool enable) | ||
498 | { | ||
499 | struct drm_device *dev = crtc->dev; | ||
500 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | ||
501 | enum omap_channel channel = omap_crtc->channel; | ||
502 | struct omap_irq_wait *wait = NULL; | ||
503 | |||
504 | if (dispc_mgr_is_enabled(channel) == enable) | ||
505 | return; | ||
506 | |||
507 | /* ignore sync-lost irqs during enable/disable */ | ||
508 | omap_irq_unregister(crtc->dev, &omap_crtc->error_irq); | ||
509 | |||
510 | if (dispc_mgr_get_framedone_irq(channel)) { | ||
511 | if (!enable) { | ||
512 | wait = omap_irq_wait_init(dev, | ||
513 | dispc_mgr_get_framedone_irq(channel), 1); | ||
514 | } | ||
515 | } else { | ||
516 | /* | ||
517 | * When we disable digit output, we need to wait until fields | ||
518 | * are done. Otherwise the DSS is still working, and turning | ||
519 | * off the clocks prevents DSS from going to OFF mode. And when | ||
520 | * enabling, we need to wait for the extra sync losts | ||
521 | */ | ||
522 | wait = omap_irq_wait_init(dev, | ||
523 | dispc_mgr_get_vsync_irq(channel), 2); | ||
524 | } | ||
525 | |||
526 | dispc_mgr_enable(channel, enable); | ||
527 | |||
528 | if (wait) { | ||
529 | int ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100)); | ||
530 | if (ret) { | ||
531 | dev_err(dev->dev, "%s: timeout waiting for %s\n", | ||
532 | omap_crtc->name, enable ? "enable" : "disable"); | ||
533 | } | ||
534 | } | ||
535 | |||
536 | omap_irq_register(crtc->dev, &omap_crtc->error_irq); | ||
537 | } | ||
538 | |||
539 | static void omap_crtc_pre_apply(struct omap_drm_apply *apply) | ||
540 | { | ||
541 | struct omap_crtc *omap_crtc = | ||
542 | container_of(apply, struct omap_crtc, apply); | ||
543 | struct drm_crtc *crtc = &omap_crtc->base; | ||
544 | struct drm_encoder *encoder = NULL; | ||
545 | |||
546 | DBG("%s: enabled=%d, full=%d", omap_crtc->name, | ||
547 | omap_crtc->enabled, omap_crtc->full_update); | ||
548 | |||
549 | if (omap_crtc->full_update) { | ||
550 | struct omap_drm_private *priv = crtc->dev->dev_private; | ||
551 | int i; | ||
552 | for (i = 0; i < priv->num_encoders; i++) { | ||
553 | if (priv->encoders[i]->crtc == crtc) { | ||
554 | encoder = priv->encoders[i]; | ||
555 | break; | ||
556 | } | ||
557 | } | ||
558 | } | ||
559 | |||
560 | if (!omap_crtc->enabled) { | ||
561 | set_enabled(&omap_crtc->base, false); | ||
562 | if (encoder) | ||
563 | omap_encoder_set_enabled(encoder, false); | ||
564 | } else { | ||
565 | if (encoder) { | ||
566 | omap_encoder_set_enabled(encoder, false); | ||
567 | omap_encoder_update(encoder, &omap_crtc->mgr, | ||
568 | &omap_crtc->timings); | ||
569 | omap_encoder_set_enabled(encoder, true); | ||
570 | omap_crtc->full_update = false; | ||
571 | } | ||
572 | |||
573 | dispc_mgr_setup(omap_crtc->channel, &omap_crtc->info); | ||
574 | dispc_mgr_set_timings(omap_crtc->channel, | ||
575 | &omap_crtc->timings); | ||
576 | set_enabled(&omap_crtc->base, true); | ||
577 | } | ||
578 | |||
579 | omap_crtc->full_update = false; | ||
580 | } | ||
581 | |||
582 | static void omap_crtc_post_apply(struct omap_drm_apply *apply) | ||
583 | { | ||
584 | /* nothing needed for post-apply */ | ||
585 | } | ||
586 | |||
587 | static const char *channel_names[] = { | ||
588 | [OMAP_DSS_CHANNEL_LCD] = "lcd", | ||
589 | [OMAP_DSS_CHANNEL_DIGIT] = "tv", | ||
590 | [OMAP_DSS_CHANNEL_LCD2] = "lcd2", | ||
591 | }; | ||
592 | |||
237 | /* initialize crtc */ | 593 | /* initialize crtc */ |
238 | struct drm_crtc *omap_crtc_init(struct drm_device *dev, | 594 | struct drm_crtc *omap_crtc_init(struct drm_device *dev, |
239 | struct omap_overlay *ovl, int id) | 595 | struct drm_plane *plane, enum omap_channel channel, int id) |
240 | { | 596 | { |
241 | struct drm_crtc *crtc = NULL; | 597 | struct drm_crtc *crtc = NULL; |
242 | struct omap_crtc *omap_crtc = kzalloc(sizeof(*omap_crtc), GFP_KERNEL); | 598 | struct omap_crtc *omap_crtc; |
599 | struct omap_overlay_manager_info *info; | ||
600 | |||
601 | DBG("%s", channel_names[channel]); | ||
243 | 602 | ||
244 | DBG("%s", ovl->name); | 603 | omap_crtc = kzalloc(sizeof(*omap_crtc), GFP_KERNEL); |
245 | 604 | ||
246 | if (!omap_crtc) { | 605 | if (!omap_crtc) { |
247 | dev_err(dev->dev, "could not allocate CRTC\n"); | 606 | dev_err(dev->dev, "could not allocate CRTC\n"); |
@@ -250,10 +609,40 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, | |||
250 | 609 | ||
251 | crtc = &omap_crtc->base; | 610 | crtc = &omap_crtc->base; |
252 | 611 | ||
253 | omap_crtc->plane = omap_plane_init(dev, ovl, (1 << id), true); | 612 | INIT_WORK(&omap_crtc->page_flip_work, page_flip_worker); |
613 | INIT_WORK(&omap_crtc->apply_work, apply_worker); | ||
614 | |||
615 | INIT_LIST_HEAD(&omap_crtc->pending_applies); | ||
616 | INIT_LIST_HEAD(&omap_crtc->queued_applies); | ||
617 | |||
618 | omap_crtc->apply.pre_apply = omap_crtc_pre_apply; | ||
619 | omap_crtc->apply.post_apply = omap_crtc_post_apply; | ||
620 | |||
621 | omap_crtc->apply_irq.irqmask = pipe2vbl(id); | ||
622 | omap_crtc->apply_irq.irq = omap_crtc_apply_irq; | ||
623 | |||
624 | omap_crtc->error_irq.irqmask = | ||
625 | dispc_mgr_get_sync_lost_irq(channel); | ||
626 | omap_crtc->error_irq.irq = omap_crtc_error_irq; | ||
627 | omap_irq_register(dev, &omap_crtc->error_irq); | ||
628 | |||
629 | omap_crtc->channel = channel; | ||
630 | omap_crtc->plane = plane; | ||
254 | omap_crtc->plane->crtc = crtc; | 631 | omap_crtc->plane->crtc = crtc; |
255 | omap_crtc->name = ovl->name; | 632 | omap_crtc->name = channel_names[channel]; |
256 | omap_crtc->id = id; | 633 | omap_crtc->pipe = id; |
634 | |||
635 | /* temporary: */ | ||
636 | omap_crtc->mgr.id = channel; | ||
637 | |||
638 | dss_install_mgr_ops(&mgr_ops); | ||
639 | |||
640 | /* TODO: fix hard-coded setup.. add properties! */ | ||
641 | info = &omap_crtc->info; | ||
642 | info->default_color = 0x00000000; | ||
643 | info->trans_key = 0x00000000; | ||
644 | info->trans_key_type = OMAP_DSS_COLOR_KEY_GFX_DST; | ||
645 | info->trans_enabled = false; | ||
257 | 646 | ||
258 | drm_crtc_init(dev, crtc, &omap_crtc_funcs); | 647 | drm_crtc_init(dev, crtc, &omap_crtc_funcs); |
259 | drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs); | 648 | drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs); |
diff --git a/drivers/staging/omapdrm/omap_drv.c b/drivers/staging/omapdrm/omap_drv.c index 84943e5ba1d6..ae5ecc2efbc7 100644 --- a/drivers/staging/omapdrm/omap_drv.c +++ b/drivers/staging/omapdrm/omap_drv.c | |||
@@ -74,320 +74,99 @@ static int get_connector_type(struct omap_dss_device *dssdev) | |||
74 | } | 74 | } |
75 | } | 75 | } |
76 | 76 | ||
77 | #if 0 /* enable when dss2 supports hotplug */ | 77 | static int omap_modeset_init(struct drm_device *dev) |
78 | static int omap_drm_notifier(struct notifier_block *nb, | ||
79 | unsigned long evt, void *arg) | ||
80 | { | ||
81 | switch (evt) { | ||
82 | case OMAP_DSS_SIZE_CHANGE: | ||
83 | case OMAP_DSS_HOTPLUG_CONNECT: | ||
84 | case OMAP_DSS_HOTPLUG_DISCONNECT: { | ||
85 | struct drm_device *dev = drm_device; | ||
86 | DBG("hotplug event: evt=%d, dev=%p", evt, dev); | ||
87 | if (dev) | ||
88 | drm_sysfs_hotplug_event(dev); | ||
89 | |||
90 | return NOTIFY_OK; | ||
91 | } | ||
92 | default: /* don't care about other events for now */ | ||
93 | return NOTIFY_DONE; | ||
94 | } | ||
95 | } | ||
96 | #endif | ||
97 | |||
98 | static void dump_video_chains(void) | ||
99 | { | ||
100 | int i; | ||
101 | |||
102 | DBG("dumping video chains: "); | ||
103 | for (i = 0; i < omap_dss_get_num_overlays(); i++) { | ||
104 | struct omap_overlay *ovl = omap_dss_get_overlay(i); | ||
105 | struct omap_overlay_manager *mgr = ovl->manager; | ||
106 | struct omap_dss_device *dssdev = mgr ? | ||
107 | mgr->get_device(mgr) : NULL; | ||
108 | if (dssdev) { | ||
109 | DBG("%d: %s -> %s -> %s", i, ovl->name, mgr->name, | ||
110 | dssdev->name); | ||
111 | } else if (mgr) { | ||
112 | DBG("%d: %s -> %s", i, ovl->name, mgr->name); | ||
113 | } else { | ||
114 | DBG("%d: %s", i, ovl->name); | ||
115 | } | ||
116 | } | ||
117 | } | ||
118 | |||
119 | /* create encoders for each manager */ | ||
120 | static int create_encoder(struct drm_device *dev, | ||
121 | struct omap_overlay_manager *mgr) | ||
122 | { | ||
123 | struct omap_drm_private *priv = dev->dev_private; | ||
124 | struct drm_encoder *encoder = omap_encoder_init(dev, mgr); | ||
125 | |||
126 | if (!encoder) { | ||
127 | dev_err(dev->dev, "could not create encoder: %s\n", | ||
128 | mgr->name); | ||
129 | return -ENOMEM; | ||
130 | } | ||
131 | |||
132 | BUG_ON(priv->num_encoders >= ARRAY_SIZE(priv->encoders)); | ||
133 | |||
134 | priv->encoders[priv->num_encoders++] = encoder; | ||
135 | |||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | /* create connectors for each display device */ | ||
140 | static int create_connector(struct drm_device *dev, | ||
141 | struct omap_dss_device *dssdev) | ||
142 | { | 78 | { |
143 | struct omap_drm_private *priv = dev->dev_private; | 79 | struct omap_drm_private *priv = dev->dev_private; |
144 | static struct notifier_block *notifier; | 80 | struct omap_dss_device *dssdev = NULL; |
145 | struct drm_connector *connector; | 81 | int num_ovls = dss_feat_get_num_ovls(); |
146 | int j; | 82 | int id; |
147 | |||
148 | if (!dssdev->driver) { | ||
149 | dev_warn(dev->dev, "%s has no driver.. skipping it\n", | ||
150 | dssdev->name); | ||
151 | return 0; | ||
152 | } | ||
153 | 83 | ||
154 | if (!(dssdev->driver->get_timings || | 84 | drm_mode_config_init(dev); |
155 | dssdev->driver->read_edid)) { | ||
156 | dev_warn(dev->dev, "%s driver does not support " | ||
157 | "get_timings or read_edid.. skipping it!\n", | ||
158 | dssdev->name); | ||
159 | return 0; | ||
160 | } | ||
161 | 85 | ||
162 | connector = omap_connector_init(dev, | 86 | omap_drm_irq_install(dev); |
163 | get_connector_type(dssdev), dssdev); | ||
164 | 87 | ||
165 | if (!connector) { | 88 | /* |
166 | dev_err(dev->dev, "could not create connector: %s\n", | 89 | * Create private planes and CRTCs for the last NUM_CRTCs overlay |
167 | dssdev->name); | 90 | * plus manager: |
168 | return -ENOMEM; | 91 | */ |
169 | } | 92 | for (id = 0; id < min(num_crtc, num_ovls); id++) { |
170 | 93 | struct drm_plane *plane; | |
171 | BUG_ON(priv->num_connectors >= ARRAY_SIZE(priv->connectors)); | 94 | struct drm_crtc *crtc; |
172 | 95 | ||
173 | priv->connectors[priv->num_connectors++] = connector; | 96 | plane = omap_plane_init(dev, id, true); |
97 | crtc = omap_crtc_init(dev, plane, pipe2chan(id), id); | ||
174 | 98 | ||
175 | #if 0 /* enable when dss2 supports hotplug */ | 99 | BUG_ON(priv->num_crtcs >= ARRAY_SIZE(priv->crtcs)); |
176 | notifier = kzalloc(sizeof(struct notifier_block), GFP_KERNEL); | 100 | priv->crtcs[id] = crtc; |
177 | notifier->notifier_call = omap_drm_notifier; | 101 | priv->num_crtcs++; |
178 | omap_dss_add_notify(dssdev, notifier); | ||
179 | #else | ||
180 | notifier = NULL; | ||
181 | #endif | ||
182 | 102 | ||
183 | for (j = 0; j < priv->num_encoders; j++) { | 103 | priv->planes[id] = plane; |
184 | struct omap_overlay_manager *mgr = | 104 | priv->num_planes++; |
185 | omap_encoder_get_manager(priv->encoders[j]); | ||
186 | if (mgr->get_device(mgr) == dssdev) { | ||
187 | drm_mode_connector_attach_encoder(connector, | ||
188 | priv->encoders[j]); | ||
189 | } | ||
190 | } | 105 | } |
191 | 106 | ||
192 | return 0; | 107 | /* |
193 | } | 108 | * Create normal planes for the remaining overlays: |
194 | |||
195 | /* create up to max_overlays CRTCs mapping to overlays.. by default, | ||
196 | * connect the overlays to different managers/encoders, giving priority | ||
197 | * to encoders connected to connectors with a detected connection | ||
198 | */ | ||
199 | static int create_crtc(struct drm_device *dev, struct omap_overlay *ovl, | ||
200 | int *j, unsigned int connected_connectors) | ||
201 | { | ||
202 | struct omap_drm_private *priv = dev->dev_private; | ||
203 | struct omap_overlay_manager *mgr = NULL; | ||
204 | struct drm_crtc *crtc; | ||
205 | |||
206 | /* find next best connector, ones with detected connection first | ||
207 | */ | 109 | */ |
208 | while (*j < priv->num_connectors && !mgr) { | 110 | for (; id < num_ovls; id++) { |
209 | if (connected_connectors & (1 << *j)) { | 111 | struct drm_plane *plane = omap_plane_init(dev, id, false); |
210 | struct drm_encoder *encoder = | ||
211 | omap_connector_attached_encoder( | ||
212 | priv->connectors[*j]); | ||
213 | if (encoder) | ||
214 | mgr = omap_encoder_get_manager(encoder); | ||
215 | 112 | ||
216 | } | 113 | BUG_ON(priv->num_planes >= ARRAY_SIZE(priv->planes)); |
217 | (*j)++; | 114 | priv->planes[priv->num_planes++] = plane; |
218 | } | 115 | } |
219 | 116 | ||
220 | /* if we couldn't find another connected connector, lets start | 117 | for_each_dss_dev(dssdev) { |
221 | * looking at the unconnected connectors: | 118 | struct drm_connector *connector; |
222 | * | 119 | struct drm_encoder *encoder; |
223 | * note: it might not be immediately apparent, but thanks to | ||
224 | * the !mgr check in both this loop and the one above, the only | ||
225 | * way to enter this loop is with *j == priv->num_connectors, | ||
226 | * so idx can never go negative. | ||
227 | */ | ||
228 | while (*j < 2 * priv->num_connectors && !mgr) { | ||
229 | int idx = *j - priv->num_connectors; | ||
230 | if (!(connected_connectors & (1 << idx))) { | ||
231 | struct drm_encoder *encoder = | ||
232 | omap_connector_attached_encoder( | ||
233 | priv->connectors[idx]); | ||
234 | if (encoder) | ||
235 | mgr = omap_encoder_get_manager(encoder); | ||
236 | 120 | ||
121 | if (!dssdev->driver) { | ||
122 | dev_warn(dev->dev, "%s has no driver.. skipping it\n", | ||
123 | dssdev->name); | ||
124 | return 0; | ||
237 | } | 125 | } |
238 | (*j)++; | ||
239 | } | ||
240 | |||
241 | crtc = omap_crtc_init(dev, ovl, priv->num_crtcs); | ||
242 | |||
243 | if (!crtc) { | ||
244 | dev_err(dev->dev, "could not create CRTC: %s\n", | ||
245 | ovl->name); | ||
246 | return -ENOMEM; | ||
247 | } | ||
248 | 126 | ||
249 | BUG_ON(priv->num_crtcs >= ARRAY_SIZE(priv->crtcs)); | 127 | if (!(dssdev->driver->get_timings || |
250 | 128 | dssdev->driver->read_edid)) { | |
251 | priv->crtcs[priv->num_crtcs++] = crtc; | 129 | dev_warn(dev->dev, "%s driver does not support " |
252 | 130 | "get_timings or read_edid.. skipping it!\n", | |
253 | return 0; | 131 | dssdev->name); |
254 | } | 132 | return 0; |
255 | |||
256 | static int create_plane(struct drm_device *dev, struct omap_overlay *ovl, | ||
257 | unsigned int possible_crtcs) | ||
258 | { | ||
259 | struct omap_drm_private *priv = dev->dev_private; | ||
260 | struct drm_plane *plane = | ||
261 | omap_plane_init(dev, ovl, possible_crtcs, false); | ||
262 | |||
263 | if (!plane) { | ||
264 | dev_err(dev->dev, "could not create plane: %s\n", | ||
265 | ovl->name); | ||
266 | return -ENOMEM; | ||
267 | } | ||
268 | |||
269 | BUG_ON(priv->num_planes >= ARRAY_SIZE(priv->planes)); | ||
270 | |||
271 | priv->planes[priv->num_planes++] = plane; | ||
272 | |||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | static int match_dev_name(struct omap_dss_device *dssdev, void *data) | ||
277 | { | ||
278 | return !strcmp(dssdev->name, data); | ||
279 | } | ||
280 | |||
281 | static unsigned int detect_connectors(struct drm_device *dev) | ||
282 | { | ||
283 | struct omap_drm_private *priv = dev->dev_private; | ||
284 | unsigned int connected_connectors = 0; | ||
285 | int i; | ||
286 | |||
287 | for (i = 0; i < priv->num_connectors; i++) { | ||
288 | struct drm_connector *connector = priv->connectors[i]; | ||
289 | if (omap_connector_detect(connector, true) == | ||
290 | connector_status_connected) { | ||
291 | connected_connectors |= (1 << i); | ||
292 | } | 133 | } |
293 | } | ||
294 | |||
295 | return connected_connectors; | ||
296 | } | ||
297 | 134 | ||
298 | static int omap_modeset_init(struct drm_device *dev) | 135 | encoder = omap_encoder_init(dev, dssdev); |
299 | { | ||
300 | const struct omap_drm_platform_data *pdata = dev->dev->platform_data; | ||
301 | struct omap_kms_platform_data *kms_pdata = NULL; | ||
302 | struct omap_drm_private *priv = dev->dev_private; | ||
303 | struct omap_dss_device *dssdev = NULL; | ||
304 | int i, j; | ||
305 | unsigned int connected_connectors = 0; | ||
306 | 136 | ||
307 | drm_mode_config_init(dev); | 137 | if (!encoder) { |
308 | 138 | dev_err(dev->dev, "could not create encoder: %s\n", | |
309 | if (pdata && pdata->kms_pdata) { | 139 | dssdev->name); |
310 | kms_pdata = pdata->kms_pdata; | 140 | return -ENOMEM; |
311 | |||
312 | /* if platform data is provided by the board file, use it to | ||
313 | * control which overlays, managers, and devices we own. | ||
314 | */ | ||
315 | for (i = 0; i < kms_pdata->mgr_cnt; i++) { | ||
316 | struct omap_overlay_manager *mgr = | ||
317 | omap_dss_get_overlay_manager( | ||
318 | kms_pdata->mgr_ids[i]); | ||
319 | create_encoder(dev, mgr); | ||
320 | } | ||
321 | |||
322 | for (i = 0; i < kms_pdata->dev_cnt; i++) { | ||
323 | struct omap_dss_device *dssdev = | ||
324 | omap_dss_find_device( | ||
325 | (void *)kms_pdata->dev_names[i], | ||
326 | match_dev_name); | ||
327 | if (!dssdev) { | ||
328 | dev_warn(dev->dev, "no such dssdev: %s\n", | ||
329 | kms_pdata->dev_names[i]); | ||
330 | continue; | ||
331 | } | ||
332 | create_connector(dev, dssdev); | ||
333 | } | 141 | } |
334 | 142 | ||
335 | connected_connectors = detect_connectors(dev); | 143 | connector = omap_connector_init(dev, |
144 | get_connector_type(dssdev), dssdev, encoder); | ||
336 | 145 | ||
337 | j = 0; | 146 | if (!connector) { |
338 | for (i = 0; i < kms_pdata->ovl_cnt; i++) { | 147 | dev_err(dev->dev, "could not create connector: %s\n", |
339 | struct omap_overlay *ovl = | 148 | dssdev->name); |
340 | omap_dss_get_overlay(kms_pdata->ovl_ids[i]); | 149 | return -ENOMEM; |
341 | create_crtc(dev, ovl, &j, connected_connectors); | ||
342 | } | 150 | } |
343 | 151 | ||
344 | for (i = 0; i < kms_pdata->pln_cnt; i++) { | 152 | BUG_ON(priv->num_encoders >= ARRAY_SIZE(priv->encoders)); |
345 | struct omap_overlay *ovl = | 153 | BUG_ON(priv->num_connectors >= ARRAY_SIZE(priv->connectors)); |
346 | omap_dss_get_overlay(kms_pdata->pln_ids[i]); | ||
347 | create_plane(dev, ovl, (1 << priv->num_crtcs) - 1); | ||
348 | } | ||
349 | } else { | ||
350 | /* otherwise just grab up to CONFIG_DRM_OMAP_NUM_CRTCS and try | ||
351 | * to make educated guesses about everything else | ||
352 | */ | ||
353 | int max_overlays = min(omap_dss_get_num_overlays(), num_crtc); | ||
354 | 154 | ||
355 | for (i = 0; i < omap_dss_get_num_overlay_managers(); i++) | 155 | priv->encoders[priv->num_encoders++] = encoder; |
356 | create_encoder(dev, omap_dss_get_overlay_manager(i)); | 156 | priv->connectors[priv->num_connectors++] = connector; |
357 | |||
358 | for_each_dss_dev(dssdev) { | ||
359 | create_connector(dev, dssdev); | ||
360 | } | ||
361 | 157 | ||
362 | connected_connectors = detect_connectors(dev); | 158 | drm_mode_connector_attach_encoder(connector, encoder); |
363 | 159 | ||
364 | j = 0; | 160 | /* figure out which crtc's we can connect the encoder to: */ |
365 | for (i = 0; i < max_overlays; i++) { | 161 | encoder->possible_crtcs = 0; |
366 | create_crtc(dev, omap_dss_get_overlay(i), | 162 | for (id = 0; id < priv->num_crtcs; id++) { |
367 | &j, connected_connectors); | 163 | enum omap_dss_output_id supported_outputs = |
368 | } | 164 | dss_feat_get_supported_outputs(pipe2chan(id)); |
369 | 165 | if (supported_outputs & dssdev->output->id) | |
370 | /* use any remaining overlays as drm planes */ | 166 | encoder->possible_crtcs |= (1 << id); |
371 | for (; i < omap_dss_get_num_overlays(); i++) { | ||
372 | struct omap_overlay *ovl = omap_dss_get_overlay(i); | ||
373 | create_plane(dev, ovl, (1 << priv->num_crtcs) - 1); | ||
374 | } | 167 | } |
375 | } | 168 | } |
376 | 169 | ||
377 | /* for now keep the mapping of CRTCs and encoders static.. */ | ||
378 | for (i = 0; i < priv->num_encoders; i++) { | ||
379 | struct drm_encoder *encoder = priv->encoders[i]; | ||
380 | struct omap_overlay_manager *mgr = | ||
381 | omap_encoder_get_manager(encoder); | ||
382 | |||
383 | encoder->possible_crtcs = (1 << priv->num_crtcs) - 1; | ||
384 | |||
385 | DBG("%s: possible_crtcs=%08x", mgr->name, | ||
386 | encoder->possible_crtcs); | ||
387 | } | ||
388 | |||
389 | dump_video_chains(); | ||
390 | |||
391 | dev->mode_config.min_width = 32; | 170 | dev->mode_config.min_width = 32; |
392 | dev->mode_config.min_height = 32; | 171 | dev->mode_config.min_height = 32; |
393 | 172 | ||
@@ -450,7 +229,7 @@ static int ioctl_gem_new(struct drm_device *dev, void *data, | |||
450 | struct drm_file *file_priv) | 229 | struct drm_file *file_priv) |
451 | { | 230 | { |
452 | struct drm_omap_gem_new *args = data; | 231 | struct drm_omap_gem_new *args = data; |
453 | DBG("%p:%p: size=0x%08x, flags=%08x", dev, file_priv, | 232 | VERB("%p:%p: size=0x%08x, flags=%08x", dev, file_priv, |
454 | args->size.bytes, args->flags); | 233 | args->size.bytes, args->flags); |
455 | return omap_gem_new_handle(dev, file_priv, args->size, | 234 | return omap_gem_new_handle(dev, file_priv, args->size, |
456 | args->flags, &args->handle); | 235 | args->flags, &args->handle); |
@@ -510,7 +289,7 @@ static int ioctl_gem_info(struct drm_device *dev, void *data, | |||
510 | struct drm_gem_object *obj; | 289 | struct drm_gem_object *obj; |
511 | int ret = 0; | 290 | int ret = 0; |
512 | 291 | ||
513 | DBG("%p:%p: handle=%d", dev, file_priv, args->handle); | 292 | VERB("%p:%p: handle=%d", dev, file_priv, args->handle); |
514 | 293 | ||
515 | obj = drm_gem_object_lookup(dev, file_priv, args->handle); | 294 | obj = drm_gem_object_lookup(dev, file_priv, args->handle); |
516 | if (!obj) | 295 | if (!obj) |
@@ -565,14 +344,6 @@ static int dev_load(struct drm_device *dev, unsigned long flags) | |||
565 | 344 | ||
566 | dev->dev_private = priv; | 345 | dev->dev_private = priv; |
567 | 346 | ||
568 | ret = omapdss_compat_init(); | ||
569 | if (ret) { | ||
570 | dev_err(dev->dev, "coult not init omapdss\n"); | ||
571 | dev->dev_private = NULL; | ||
572 | kfree(priv); | ||
573 | return ret; | ||
574 | } | ||
575 | |||
576 | priv->wq = alloc_ordered_workqueue("omapdrm", 0); | 347 | priv->wq = alloc_ordered_workqueue("omapdrm", 0); |
577 | 348 | ||
578 | INIT_LIST_HEAD(&priv->obj_list); | 349 | INIT_LIST_HEAD(&priv->obj_list); |
@@ -584,10 +355,13 @@ static int dev_load(struct drm_device *dev, unsigned long flags) | |||
584 | dev_err(dev->dev, "omap_modeset_init failed: ret=%d\n", ret); | 355 | dev_err(dev->dev, "omap_modeset_init failed: ret=%d\n", ret); |
585 | dev->dev_private = NULL; | 356 | dev->dev_private = NULL; |
586 | kfree(priv); | 357 | kfree(priv); |
587 | omapdss_compat_uninit(); | ||
588 | return ret; | 358 | return ret; |
589 | } | 359 | } |
590 | 360 | ||
361 | ret = drm_vblank_init(dev, priv->num_crtcs); | ||
362 | if (ret) | ||
363 | dev_warn(dev->dev, "could not init vblank\n"); | ||
364 | |||
591 | priv->fbdev = omap_fbdev_init(dev); | 365 | priv->fbdev = omap_fbdev_init(dev); |
592 | if (!priv->fbdev) { | 366 | if (!priv->fbdev) { |
593 | dev_warn(dev->dev, "omap_fbdev_init failed\n"); | 367 | dev_warn(dev->dev, "omap_fbdev_init failed\n"); |
@@ -596,10 +370,6 @@ static int dev_load(struct drm_device *dev, unsigned long flags) | |||
596 | 370 | ||
597 | drm_kms_helper_poll_init(dev); | 371 | drm_kms_helper_poll_init(dev); |
598 | 372 | ||
599 | ret = drm_vblank_init(dev, priv->num_crtcs); | ||
600 | if (ret) | ||
601 | dev_warn(dev->dev, "could not init vblank\n"); | ||
602 | |||
603 | return 0; | 373 | return 0; |
604 | } | 374 | } |
605 | 375 | ||
@@ -609,8 +379,9 @@ static int dev_unload(struct drm_device *dev) | |||
609 | 379 | ||
610 | DBG("unload: dev=%p", dev); | 380 | DBG("unload: dev=%p", dev); |
611 | 381 | ||
612 | drm_vblank_cleanup(dev); | ||
613 | drm_kms_helper_poll_fini(dev); | 382 | drm_kms_helper_poll_fini(dev); |
383 | drm_vblank_cleanup(dev); | ||
384 | omap_drm_irq_uninstall(dev); | ||
614 | 385 | ||
615 | omap_fbdev_free(dev); | 386 | omap_fbdev_free(dev); |
616 | omap_modeset_free(dev); | 387 | omap_modeset_free(dev); |
@@ -619,8 +390,6 @@ static int dev_unload(struct drm_device *dev) | |||
619 | flush_workqueue(priv->wq); | 390 | flush_workqueue(priv->wq); |
620 | destroy_workqueue(priv->wq); | 391 | destroy_workqueue(priv->wq); |
621 | 392 | ||
622 | omapdss_compat_uninit(); | ||
623 | |||
624 | kfree(dev->dev_private); | 393 | kfree(dev->dev_private); |
625 | dev->dev_private = NULL; | 394 | dev->dev_private = NULL; |
626 | 395 | ||
@@ -680,7 +449,9 @@ static void dev_lastclose(struct drm_device *dev) | |||
680 | } | 449 | } |
681 | } | 450 | } |
682 | 451 | ||
452 | mutex_lock(&dev->mode_config.mutex); | ||
683 | ret = drm_fb_helper_restore_fbdev_mode(priv->fbdev); | 453 | ret = drm_fb_helper_restore_fbdev_mode(priv->fbdev); |
454 | mutex_unlock(&dev->mode_config.mutex); | ||
684 | if (ret) | 455 | if (ret) |
685 | DBG("failed to restore crtc mode"); | 456 | DBG("failed to restore crtc mode"); |
686 | } | 457 | } |
@@ -695,60 +466,6 @@ static void dev_postclose(struct drm_device *dev, struct drm_file *file) | |||
695 | DBG("postclose: dev=%p, file=%p", dev, file); | 466 | DBG("postclose: dev=%p, file=%p", dev, file); |
696 | } | 467 | } |
697 | 468 | ||
698 | /** | ||
699 | * enable_vblank - enable vblank interrupt events | ||
700 | * @dev: DRM device | ||
701 | * @crtc: which irq to enable | ||
702 | * | ||
703 | * Enable vblank interrupts for @crtc. If the device doesn't have | ||
704 | * a hardware vblank counter, this routine should be a no-op, since | ||
705 | * interrupts will have to stay on to keep the count accurate. | ||
706 | * | ||
707 | * RETURNS | ||
708 | * Zero on success, appropriate errno if the given @crtc's vblank | ||
709 | * interrupt cannot be enabled. | ||
710 | */ | ||
711 | static int dev_enable_vblank(struct drm_device *dev, int crtc) | ||
712 | { | ||
713 | DBG("enable_vblank: dev=%p, crtc=%d", dev, crtc); | ||
714 | return 0; | ||
715 | } | ||
716 | |||
717 | /** | ||
718 | * disable_vblank - disable vblank interrupt events | ||
719 | * @dev: DRM device | ||
720 | * @crtc: which irq to enable | ||
721 | * | ||
722 | * Disable vblank interrupts for @crtc. If the device doesn't have | ||
723 | * a hardware vblank counter, this routine should be a no-op, since | ||
724 | * interrupts will have to stay on to keep the count accurate. | ||
725 | */ | ||
726 | static void dev_disable_vblank(struct drm_device *dev, int crtc) | ||
727 | { | ||
728 | DBG("disable_vblank: dev=%p, crtc=%d", dev, crtc); | ||
729 | } | ||
730 | |||
731 | static irqreturn_t dev_irq_handler(DRM_IRQ_ARGS) | ||
732 | { | ||
733 | return IRQ_HANDLED; | ||
734 | } | ||
735 | |||
736 | static void dev_irq_preinstall(struct drm_device *dev) | ||
737 | { | ||
738 | DBG("irq_preinstall: dev=%p", dev); | ||
739 | } | ||
740 | |||
741 | static int dev_irq_postinstall(struct drm_device *dev) | ||
742 | { | ||
743 | DBG("irq_postinstall: dev=%p", dev); | ||
744 | return 0; | ||
745 | } | ||
746 | |||
747 | static void dev_irq_uninstall(struct drm_device *dev) | ||
748 | { | ||
749 | DBG("irq_uninstall: dev=%p", dev); | ||
750 | } | ||
751 | |||
752 | static const struct vm_operations_struct omap_gem_vm_ops = { | 469 | static const struct vm_operations_struct omap_gem_vm_ops = { |
753 | .fault = omap_gem_fault, | 470 | .fault = omap_gem_fault, |
754 | .open = drm_gem_vm_open, | 471 | .open = drm_gem_vm_open, |
@@ -778,12 +495,12 @@ static struct drm_driver omap_drm_driver = { | |||
778 | .preclose = dev_preclose, | 495 | .preclose = dev_preclose, |
779 | .postclose = dev_postclose, | 496 | .postclose = dev_postclose, |
780 | .get_vblank_counter = drm_vblank_count, | 497 | .get_vblank_counter = drm_vblank_count, |
781 | .enable_vblank = dev_enable_vblank, | 498 | .enable_vblank = omap_irq_enable_vblank, |
782 | .disable_vblank = dev_disable_vblank, | 499 | .disable_vblank = omap_irq_disable_vblank, |
783 | .irq_preinstall = dev_irq_preinstall, | 500 | .irq_preinstall = omap_irq_preinstall, |
784 | .irq_postinstall = dev_irq_postinstall, | 501 | .irq_postinstall = omap_irq_postinstall, |
785 | .irq_uninstall = dev_irq_uninstall, | 502 | .irq_uninstall = omap_irq_uninstall, |
786 | .irq_handler = dev_irq_handler, | 503 | .irq_handler = omap_irq_handler, |
787 | #ifdef CONFIG_DEBUG_FS | 504 | #ifdef CONFIG_DEBUG_FS |
788 | .debugfs_init = omap_debugfs_init, | 505 | .debugfs_init = omap_debugfs_init, |
789 | .debugfs_cleanup = omap_debugfs_cleanup, | 506 | .debugfs_cleanup = omap_debugfs_cleanup, |
diff --git a/drivers/staging/omapdrm/omap_drv.h b/drivers/staging/omapdrm/omap_drv.h index 1d4aea53b75d..cd1f22b0b124 100644 --- a/drivers/staging/omapdrm/omap_drv.h +++ b/drivers/staging/omapdrm/omap_drv.h | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/platform_data/omap_drm.h> | 28 | #include <linux/platform_data/omap_drm.h> |
29 | #include "omap_drm.h" | 29 | #include "omap_drm.h" |
30 | 30 | ||
31 | |||
31 | #define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__) | 32 | #define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__) |
32 | #define VERB(fmt, ...) if (0) DRM_DEBUG(fmt, ##__VA_ARGS__) /* verbose debug */ | 33 | #define VERB(fmt, ...) if (0) DRM_DEBUG(fmt, ##__VA_ARGS__) /* verbose debug */ |
33 | 34 | ||
@@ -39,6 +40,51 @@ | |||
39 | */ | 40 | */ |
40 | #define MAX_MAPPERS 2 | 41 | #define MAX_MAPPERS 2 |
41 | 42 | ||
43 | /* parameters which describe (unrotated) coordinates of scanout within a fb: */ | ||
44 | struct omap_drm_window { | ||
45 | uint32_t rotation; | ||
46 | int32_t crtc_x, crtc_y; /* signed because can be offscreen */ | ||
47 | uint32_t crtc_w, crtc_h; | ||
48 | uint32_t src_x, src_y; | ||
49 | uint32_t src_w, src_h; | ||
50 | }; | ||
51 | |||
52 | /* Once GO bit is set, we can't make further updates to shadowed registers | ||
53 | * until the GO bit is cleared. So various parts in the kms code that need | ||
54 | * to update shadowed registers queue up a pair of callbacks, pre_apply | ||
55 | * which is called before setting GO bit, and post_apply that is called | ||
56 | * after GO bit is cleared. The crtc manages the queuing, and everyone | ||
57 | * else goes thru omap_crtc_apply() using these callbacks so that the | ||
58 | * code which has to deal w/ GO bit state is centralized. | ||
59 | */ | ||
60 | struct omap_drm_apply { | ||
61 | struct list_head pending_node, queued_node; | ||
62 | bool queued; | ||
63 | void (*pre_apply)(struct omap_drm_apply *apply); | ||
64 | void (*post_apply)(struct omap_drm_apply *apply); | ||
65 | }; | ||
66 | |||
67 | /* For transiently registering for different DSS irqs that various parts | ||
68 | * of the KMS code need during setup/configuration. We these are not | ||
69 | * necessarily the same as what drm_vblank_get/put() are requesting, and | ||
70 | * the hysteresis in drm_vblank_put() is not necessarily desirable for | ||
71 | * internal housekeeping related irq usage. | ||
72 | */ | ||
73 | struct omap_drm_irq { | ||
74 | struct list_head node; | ||
75 | uint32_t irqmask; | ||
76 | bool registered; | ||
77 | void (*irq)(struct omap_drm_irq *irq, uint32_t irqstatus); | ||
78 | }; | ||
79 | |||
80 | /* For KMS code that needs to wait for a certain # of IRQs: | ||
81 | */ | ||
82 | struct omap_irq_wait; | ||
83 | struct omap_irq_wait * omap_irq_wait_init(struct drm_device *dev, | ||
84 | uint32_t irqmask, int count); | ||
85 | int omap_irq_wait(struct drm_device *dev, struct omap_irq_wait *wait, | ||
86 | unsigned long timeout); | ||
87 | |||
42 | struct omap_drm_private { | 88 | struct omap_drm_private { |
43 | uint32_t omaprev; | 89 | uint32_t omaprev; |
44 | 90 | ||
@@ -58,6 +104,7 @@ struct omap_drm_private { | |||
58 | 104 | ||
59 | struct workqueue_struct *wq; | 105 | struct workqueue_struct *wq; |
60 | 106 | ||
107 | /* list of GEM objects: */ | ||
61 | struct list_head obj_list; | 108 | struct list_head obj_list; |
62 | 109 | ||
63 | bool has_dmm; | 110 | bool has_dmm; |
@@ -65,6 +112,11 @@ struct omap_drm_private { | |||
65 | /* properties: */ | 112 | /* properties: */ |
66 | struct drm_property *rotation_prop; | 113 | struct drm_property *rotation_prop; |
67 | struct drm_property *zorder_prop; | 114 | struct drm_property *zorder_prop; |
115 | |||
116 | /* irq handling: */ | ||
117 | struct list_head irq_list; /* list of omap_drm_irq */ | ||
118 | uint32_t vblank_mask; /* irq bits set for userspace vblank */ | ||
119 | struct omap_drm_irq error_handler; | ||
68 | }; | 120 | }; |
69 | 121 | ||
70 | /* this should probably be in drm-core to standardize amongst drivers */ | 122 | /* this should probably be in drm-core to standardize amongst drivers */ |
@@ -75,15 +127,6 @@ struct omap_drm_private { | |||
75 | #define DRM_REFLECT_X 4 | 127 | #define DRM_REFLECT_X 4 |
76 | #define DRM_REFLECT_Y 5 | 128 | #define DRM_REFLECT_Y 5 |
77 | 129 | ||
78 | /* parameters which describe (unrotated) coordinates of scanout within a fb: */ | ||
79 | struct omap_drm_window { | ||
80 | uint32_t rotation; | ||
81 | int32_t crtc_x, crtc_y; /* signed because can be offscreen */ | ||
82 | uint32_t crtc_w, crtc_h; | ||
83 | uint32_t src_x, src_y; | ||
84 | uint32_t src_w, src_h; | ||
85 | }; | ||
86 | |||
87 | #ifdef CONFIG_DEBUG_FS | 130 | #ifdef CONFIG_DEBUG_FS |
88 | int omap_debugfs_init(struct drm_minor *minor); | 131 | int omap_debugfs_init(struct drm_minor *minor); |
89 | void omap_debugfs_cleanup(struct drm_minor *minor); | 132 | void omap_debugfs_cleanup(struct drm_minor *minor); |
@@ -92,23 +135,36 @@ void omap_gem_describe(struct drm_gem_object *obj, struct seq_file *m); | |||
92 | void omap_gem_describe_objects(struct list_head *list, struct seq_file *m); | 135 | void omap_gem_describe_objects(struct list_head *list, struct seq_file *m); |
93 | #endif | 136 | #endif |
94 | 137 | ||
138 | int omap_irq_enable_vblank(struct drm_device *dev, int crtc); | ||
139 | void omap_irq_disable_vblank(struct drm_device *dev, int crtc); | ||
140 | irqreturn_t omap_irq_handler(DRM_IRQ_ARGS); | ||
141 | void omap_irq_preinstall(struct drm_device *dev); | ||
142 | int omap_irq_postinstall(struct drm_device *dev); | ||
143 | void omap_irq_uninstall(struct drm_device *dev); | ||
144 | void omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq); | ||
145 | void omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq); | ||
146 | int omap_drm_irq_uninstall(struct drm_device *dev); | ||
147 | int omap_drm_irq_install(struct drm_device *dev); | ||
148 | |||
95 | struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev); | 149 | struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev); |
96 | void omap_fbdev_free(struct drm_device *dev); | 150 | void omap_fbdev_free(struct drm_device *dev); |
97 | 151 | ||
152 | const struct omap_video_timings *omap_crtc_timings(struct drm_crtc *crtc); | ||
153 | enum omap_channel omap_crtc_channel(struct drm_crtc *crtc); | ||
154 | int omap_crtc_apply(struct drm_crtc *crtc, | ||
155 | struct omap_drm_apply *apply); | ||
98 | struct drm_crtc *omap_crtc_init(struct drm_device *dev, | 156 | struct drm_crtc *omap_crtc_init(struct drm_device *dev, |
99 | struct omap_overlay *ovl, int id); | 157 | struct drm_plane *plane, enum omap_channel channel, int id); |
100 | 158 | ||
101 | struct drm_plane *omap_plane_init(struct drm_device *dev, | 159 | struct drm_plane *omap_plane_init(struct drm_device *dev, |
102 | struct omap_overlay *ovl, unsigned int possible_crtcs, | 160 | int plane_id, bool private_plane); |
103 | bool priv); | ||
104 | int omap_plane_dpms(struct drm_plane *plane, int mode); | 161 | int omap_plane_dpms(struct drm_plane *plane, int mode); |
105 | int omap_plane_mode_set(struct drm_plane *plane, | 162 | int omap_plane_mode_set(struct drm_plane *plane, |
106 | struct drm_crtc *crtc, struct drm_framebuffer *fb, | 163 | struct drm_crtc *crtc, struct drm_framebuffer *fb, |
107 | int crtc_x, int crtc_y, | 164 | int crtc_x, int crtc_y, |
108 | unsigned int crtc_w, unsigned int crtc_h, | 165 | unsigned int crtc_w, unsigned int crtc_h, |
109 | uint32_t src_x, uint32_t src_y, | 166 | uint32_t src_x, uint32_t src_y, |
110 | uint32_t src_w, uint32_t src_h); | 167 | uint32_t src_w, uint32_t src_h, |
111 | void omap_plane_on_endwin(struct drm_plane *plane, | ||
112 | void (*fxn)(void *), void *arg); | 168 | void (*fxn)(void *), void *arg); |
113 | void omap_plane_install_properties(struct drm_plane *plane, | 169 | void omap_plane_install_properties(struct drm_plane *plane, |
114 | struct drm_mode_object *obj); | 170 | struct drm_mode_object *obj); |
@@ -116,21 +172,25 @@ int omap_plane_set_property(struct drm_plane *plane, | |||
116 | struct drm_property *property, uint64_t val); | 172 | struct drm_property *property, uint64_t val); |
117 | 173 | ||
118 | struct drm_encoder *omap_encoder_init(struct drm_device *dev, | 174 | struct drm_encoder *omap_encoder_init(struct drm_device *dev, |
119 | struct omap_overlay_manager *mgr); | 175 | struct omap_dss_device *dssdev); |
120 | struct omap_overlay_manager *omap_encoder_get_manager( | 176 | int omap_encoder_set_enabled(struct drm_encoder *encoder, bool enabled); |
177 | int omap_encoder_update(struct drm_encoder *encoder, | ||
178 | struct omap_overlay_manager *mgr, | ||
179 | struct omap_video_timings *timings); | ||
180 | |||
181 | struct drm_connector *omap_connector_init(struct drm_device *dev, | ||
182 | int connector_type, struct omap_dss_device *dssdev, | ||
121 | struct drm_encoder *encoder); | 183 | struct drm_encoder *encoder); |
122 | struct drm_encoder *omap_connector_attached_encoder( | 184 | struct drm_encoder *omap_connector_attached_encoder( |
123 | struct drm_connector *connector); | 185 | struct drm_connector *connector); |
124 | enum drm_connector_status omap_connector_detect( | ||
125 | struct drm_connector *connector, bool force); | ||
126 | |||
127 | struct drm_connector *omap_connector_init(struct drm_device *dev, | ||
128 | int connector_type, struct omap_dss_device *dssdev); | ||
129 | void omap_connector_mode_set(struct drm_connector *connector, | ||
130 | struct drm_display_mode *mode); | ||
131 | void omap_connector_flush(struct drm_connector *connector, | 186 | void omap_connector_flush(struct drm_connector *connector, |
132 | int x, int y, int w, int h); | 187 | int x, int y, int w, int h); |
133 | 188 | ||
189 | void copy_timings_omap_to_drm(struct drm_display_mode *mode, | ||
190 | struct omap_video_timings *timings); | ||
191 | void copy_timings_drm_to_omap(struct omap_video_timings *timings, | ||
192 | struct drm_display_mode *mode); | ||
193 | |||
134 | uint32_t omap_framebuffer_get_formats(uint32_t *pixel_formats, | 194 | uint32_t omap_framebuffer_get_formats(uint32_t *pixel_formats, |
135 | uint32_t max_formats, enum omap_color_mode supported_modes); | 195 | uint32_t max_formats, enum omap_color_mode supported_modes); |
136 | struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev, | 196 | struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev, |
@@ -207,6 +267,40 @@ static inline int align_pitch(int pitch, int width, int bpp) | |||
207 | return ALIGN(pitch, 8 * bytespp); | 267 | return ALIGN(pitch, 8 * bytespp); |
208 | } | 268 | } |
209 | 269 | ||
270 | static inline enum omap_channel pipe2chan(int pipe) | ||
271 | { | ||
272 | int num_mgrs = dss_feat_get_num_mgrs(); | ||
273 | |||
274 | /* | ||
275 | * We usually don't want to create a CRTC for each manager, | ||
276 | * at least not until we have a way to expose private planes | ||
277 | * to userspace. Otherwise there would not be enough video | ||
278 | * pipes left for drm planes. The higher #'d managers tend | ||
279 | * to have more features so start in reverse order. | ||
280 | */ | ||
281 | return num_mgrs - pipe - 1; | ||
282 | } | ||
283 | |||
284 | /* map crtc to vblank mask */ | ||
285 | static inline uint32_t pipe2vbl(int crtc) | ||
286 | { | ||
287 | enum omap_channel channel = pipe2chan(crtc); | ||
288 | return dispc_mgr_get_vsync_irq(channel); | ||
289 | } | ||
290 | |||
291 | static inline int crtc2pipe(struct drm_device *dev, struct drm_crtc *crtc) | ||
292 | { | ||
293 | struct omap_drm_private *priv = dev->dev_private; | ||
294 | int i; | ||
295 | |||
296 | for (i = 0; i < ARRAY_SIZE(priv->crtcs); i++) | ||
297 | if (priv->crtcs[i] == crtc) | ||
298 | return i; | ||
299 | |||
300 | BUG(); /* bogus CRTC ptr */ | ||
301 | return -1; | ||
302 | } | ||
303 | |||
210 | /* should these be made into common util helpers? | 304 | /* should these be made into common util helpers? |
211 | */ | 305 | */ |
212 | 306 | ||
diff --git a/drivers/staging/omapdrm/omap_encoder.c b/drivers/staging/omapdrm/omap_encoder.c index 5341d5e3e317..e053160d2db3 100644 --- a/drivers/staging/omapdrm/omap_encoder.c +++ b/drivers/staging/omapdrm/omap_encoder.c | |||
@@ -22,37 +22,56 @@ | |||
22 | #include "drm_crtc.h" | 22 | #include "drm_crtc.h" |
23 | #include "drm_crtc_helper.h" | 23 | #include "drm_crtc_helper.h" |
24 | 24 | ||
25 | #include <linux/list.h> | ||
26 | |||
27 | |||
25 | /* | 28 | /* |
26 | * encoder funcs | 29 | * encoder funcs |
27 | */ | 30 | */ |
28 | 31 | ||
29 | #define to_omap_encoder(x) container_of(x, struct omap_encoder, base) | 32 | #define to_omap_encoder(x) container_of(x, struct omap_encoder, base) |
30 | 33 | ||
34 | /* The encoder and connector both map to same dssdev.. the encoder | ||
35 | * handles the 'active' parts, ie. anything the modifies the state | ||
36 | * of the hw, and the connector handles the 'read-only' parts, like | ||
37 | * detecting connection and reading edid. | ||
38 | */ | ||
31 | struct omap_encoder { | 39 | struct omap_encoder { |
32 | struct drm_encoder base; | 40 | struct drm_encoder base; |
33 | struct omap_overlay_manager *mgr; | 41 | struct omap_dss_device *dssdev; |
34 | }; | 42 | }; |
35 | 43 | ||
36 | static void omap_encoder_destroy(struct drm_encoder *encoder) | 44 | static void omap_encoder_destroy(struct drm_encoder *encoder) |
37 | { | 45 | { |
38 | struct omap_encoder *omap_encoder = to_omap_encoder(encoder); | 46 | struct omap_encoder *omap_encoder = to_omap_encoder(encoder); |
39 | DBG("%s", omap_encoder->mgr->name); | ||
40 | drm_encoder_cleanup(encoder); | 47 | drm_encoder_cleanup(encoder); |
41 | kfree(omap_encoder); | 48 | kfree(omap_encoder); |
42 | } | 49 | } |
43 | 50 | ||
51 | static const struct drm_encoder_funcs omap_encoder_funcs = { | ||
52 | .destroy = omap_encoder_destroy, | ||
53 | }; | ||
54 | |||
55 | /* | ||
56 | * The CRTC drm_crtc_helper_set_mode() doesn't really give us the right | ||
57 | * order.. the easiest way to work around this for now is to make all | ||
58 | * the encoder-helper's no-op's and have the omap_crtc code take care | ||
59 | * of the sequencing and call us in the right points. | ||
60 | * | ||
61 | * Eventually to handle connecting CRTCs to different encoders properly, | ||
62 | * either the CRTC helpers need to change or we need to replace | ||
63 | * drm_crtc_helper_set_mode(), but lets wait until atomic-modeset for | ||
64 | * that. | ||
65 | */ | ||
66 | |||
44 | static void omap_encoder_dpms(struct drm_encoder *encoder, int mode) | 67 | static void omap_encoder_dpms(struct drm_encoder *encoder, int mode) |
45 | { | 68 | { |
46 | struct omap_encoder *omap_encoder = to_omap_encoder(encoder); | ||
47 | DBG("%s: %d", omap_encoder->mgr->name, mode); | ||
48 | } | 69 | } |
49 | 70 | ||
50 | static bool omap_encoder_mode_fixup(struct drm_encoder *encoder, | 71 | static bool omap_encoder_mode_fixup(struct drm_encoder *encoder, |
51 | const struct drm_display_mode *mode, | 72 | const struct drm_display_mode *mode, |
52 | struct drm_display_mode *adjusted_mode) | 73 | struct drm_display_mode *adjusted_mode) |
53 | { | 74 | { |
54 | struct omap_encoder *omap_encoder = to_omap_encoder(encoder); | ||
55 | DBG("%s", omap_encoder->mgr->name); | ||
56 | return true; | 75 | return true; |
57 | } | 76 | } |
58 | 77 | ||
@@ -60,47 +79,16 @@ static void omap_encoder_mode_set(struct drm_encoder *encoder, | |||
60 | struct drm_display_mode *mode, | 79 | struct drm_display_mode *mode, |
61 | struct drm_display_mode *adjusted_mode) | 80 | struct drm_display_mode *adjusted_mode) |
62 | { | 81 | { |
63 | struct omap_encoder *omap_encoder = to_omap_encoder(encoder); | ||
64 | struct drm_device *dev = encoder->dev; | ||
65 | struct omap_drm_private *priv = dev->dev_private; | ||
66 | int i; | ||
67 | |||
68 | mode = adjusted_mode; | ||
69 | |||
70 | DBG("%s: set mode: %dx%d", omap_encoder->mgr->name, | ||
71 | mode->hdisplay, mode->vdisplay); | ||
72 | |||
73 | for (i = 0; i < priv->num_connectors; i++) { | ||
74 | struct drm_connector *connector = priv->connectors[i]; | ||
75 | if (connector->encoder == encoder) | ||
76 | omap_connector_mode_set(connector, mode); | ||
77 | |||
78 | } | ||
79 | } | 82 | } |
80 | 83 | ||
81 | static void omap_encoder_prepare(struct drm_encoder *encoder) | 84 | static void omap_encoder_prepare(struct drm_encoder *encoder) |
82 | { | 85 | { |
83 | struct omap_encoder *omap_encoder = to_omap_encoder(encoder); | ||
84 | struct drm_encoder_helper_funcs *encoder_funcs = | ||
85 | encoder->helper_private; | ||
86 | DBG("%s", omap_encoder->mgr->name); | ||
87 | encoder_funcs->dpms(encoder, DRM_MODE_DPMS_OFF); | ||
88 | } | 86 | } |
89 | 87 | ||
90 | static void omap_encoder_commit(struct drm_encoder *encoder) | 88 | static void omap_encoder_commit(struct drm_encoder *encoder) |
91 | { | 89 | { |
92 | struct omap_encoder *omap_encoder = to_omap_encoder(encoder); | ||
93 | struct drm_encoder_helper_funcs *encoder_funcs = | ||
94 | encoder->helper_private; | ||
95 | DBG("%s", omap_encoder->mgr->name); | ||
96 | omap_encoder->mgr->apply(omap_encoder->mgr); | ||
97 | encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); | ||
98 | } | 90 | } |
99 | 91 | ||
100 | static const struct drm_encoder_funcs omap_encoder_funcs = { | ||
101 | .destroy = omap_encoder_destroy, | ||
102 | }; | ||
103 | |||
104 | static const struct drm_encoder_helper_funcs omap_encoder_helper_funcs = { | 92 | static const struct drm_encoder_helper_funcs omap_encoder_helper_funcs = { |
105 | .dpms = omap_encoder_dpms, | 93 | .dpms = omap_encoder_dpms, |
106 | .mode_fixup = omap_encoder_mode_fixup, | 94 | .mode_fixup = omap_encoder_mode_fixup, |
@@ -109,23 +97,54 @@ static const struct drm_encoder_helper_funcs omap_encoder_helper_funcs = { | |||
109 | .commit = omap_encoder_commit, | 97 | .commit = omap_encoder_commit, |
110 | }; | 98 | }; |
111 | 99 | ||
112 | struct omap_overlay_manager *omap_encoder_get_manager( | 100 | /* |
113 | struct drm_encoder *encoder) | 101 | * Instead of relying on the helpers for modeset, the omap_crtc code |
102 | * calls these functions in the proper sequence. | ||
103 | */ | ||
104 | |||
105 | int omap_encoder_set_enabled(struct drm_encoder *encoder, bool enabled) | ||
114 | { | 106 | { |
115 | struct omap_encoder *omap_encoder = to_omap_encoder(encoder); | 107 | struct omap_encoder *omap_encoder = to_omap_encoder(encoder); |
116 | return omap_encoder->mgr; | 108 | struct omap_dss_device *dssdev = omap_encoder->dssdev; |
109 | struct omap_dss_driver *dssdrv = dssdev->driver; | ||
110 | |||
111 | if (enabled) { | ||
112 | return dssdrv->enable(dssdev); | ||
113 | } else { | ||
114 | dssdrv->disable(dssdev); | ||
115 | return 0; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | int omap_encoder_update(struct drm_encoder *encoder, | ||
120 | struct omap_overlay_manager *mgr, | ||
121 | struct omap_video_timings *timings) | ||
122 | { | ||
123 | struct drm_device *dev = encoder->dev; | ||
124 | struct omap_encoder *omap_encoder = to_omap_encoder(encoder); | ||
125 | struct omap_dss_device *dssdev = omap_encoder->dssdev; | ||
126 | struct omap_dss_driver *dssdrv = dssdev->driver; | ||
127 | int ret; | ||
128 | |||
129 | dssdev->output->manager = mgr; | ||
130 | |||
131 | ret = dssdrv->check_timings(dssdev, timings); | ||
132 | if (ret) { | ||
133 | dev_err(dev->dev, "could not set timings: %d\n", ret); | ||
134 | return ret; | ||
135 | } | ||
136 | |||
137 | dssdrv->set_timings(dssdev, timings); | ||
138 | |||
139 | return 0; | ||
117 | } | 140 | } |
118 | 141 | ||
119 | /* initialize encoder */ | 142 | /* initialize encoder */ |
120 | struct drm_encoder *omap_encoder_init(struct drm_device *dev, | 143 | struct drm_encoder *omap_encoder_init(struct drm_device *dev, |
121 | struct omap_overlay_manager *mgr) | 144 | struct omap_dss_device *dssdev) |
122 | { | 145 | { |
123 | struct drm_encoder *encoder = NULL; | 146 | struct drm_encoder *encoder = NULL; |
124 | struct omap_encoder *omap_encoder; | 147 | struct omap_encoder *omap_encoder; |
125 | struct omap_overlay_manager_info info; | ||
126 | int ret; | ||
127 | |||
128 | DBG("%s", mgr->name); | ||
129 | 148 | ||
130 | omap_encoder = kzalloc(sizeof(*omap_encoder), GFP_KERNEL); | 149 | omap_encoder = kzalloc(sizeof(*omap_encoder), GFP_KERNEL); |
131 | if (!omap_encoder) { | 150 | if (!omap_encoder) { |
@@ -133,33 +152,14 @@ struct drm_encoder *omap_encoder_init(struct drm_device *dev, | |||
133 | goto fail; | 152 | goto fail; |
134 | } | 153 | } |
135 | 154 | ||
136 | omap_encoder->mgr = mgr; | 155 | omap_encoder->dssdev = dssdev; |
156 | |||
137 | encoder = &omap_encoder->base; | 157 | encoder = &omap_encoder->base; |
138 | 158 | ||
139 | drm_encoder_init(dev, encoder, &omap_encoder_funcs, | 159 | drm_encoder_init(dev, encoder, &omap_encoder_funcs, |
140 | DRM_MODE_ENCODER_TMDS); | 160 | DRM_MODE_ENCODER_TMDS); |
141 | drm_encoder_helper_add(encoder, &omap_encoder_helper_funcs); | 161 | drm_encoder_helper_add(encoder, &omap_encoder_helper_funcs); |
142 | 162 | ||
143 | mgr->get_manager_info(mgr, &info); | ||
144 | |||
145 | /* TODO: fix hard-coded setup.. */ | ||
146 | info.default_color = 0x00000000; | ||
147 | info.trans_key = 0x00000000; | ||
148 | info.trans_key_type = OMAP_DSS_COLOR_KEY_GFX_DST; | ||
149 | info.trans_enabled = false; | ||
150 | |||
151 | ret = mgr->set_manager_info(mgr, &info); | ||
152 | if (ret) { | ||
153 | dev_err(dev->dev, "could not set manager info\n"); | ||
154 | goto fail; | ||
155 | } | ||
156 | |||
157 | ret = mgr->apply(mgr); | ||
158 | if (ret) { | ||
159 | dev_err(dev->dev, "could not apply\n"); | ||
160 | goto fail; | ||
161 | } | ||
162 | |||
163 | return encoder; | 163 | return encoder; |
164 | 164 | ||
165 | fail: | 165 | fail: |
diff --git a/drivers/staging/omapdrm/omap_gem_dmabuf.c b/drivers/staging/omapdrm/omap_gem_dmabuf.c index ea3840038250..b6c5b5c6c8c5 100644 --- a/drivers/staging/omapdrm/omap_gem_dmabuf.c +++ b/drivers/staging/omapdrm/omap_gem_dmabuf.c | |||
@@ -194,7 +194,7 @@ struct dma_buf_ops omap_dmabuf_ops = { | |||
194 | struct dma_buf *omap_gem_prime_export(struct drm_device *dev, | 194 | struct dma_buf *omap_gem_prime_export(struct drm_device *dev, |
195 | struct drm_gem_object *obj, int flags) | 195 | struct drm_gem_object *obj, int flags) |
196 | { | 196 | { |
197 | return dma_buf_export(obj, &omap_dmabuf_ops, obj->size, 0600); | 197 | return dma_buf_export(obj, &omap_dmabuf_ops, obj->size, flags); |
198 | } | 198 | } |
199 | 199 | ||
200 | struct drm_gem_object *omap_gem_prime_import(struct drm_device *dev, | 200 | struct drm_gem_object *omap_gem_prime_import(struct drm_device *dev, |
diff --git a/drivers/staging/omapdrm/omap_irq.c b/drivers/staging/omapdrm/omap_irq.c new file mode 100644 index 000000000000..2629ba7be6c8 --- /dev/null +++ b/drivers/staging/omapdrm/omap_irq.c | |||
@@ -0,0 +1,322 @@ | |||
1 | /* | ||
2 | * drivers/staging/omapdrm/omap_irq.c | ||
3 | * | ||
4 | * Copyright (C) 2012 Texas Instruments | ||
5 | * Author: Rob Clark <rob.clark@linaro.org> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License version 2 as published by | ||
9 | * the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
14 | * more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along with | ||
17 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | |||
20 | #include "omap_drv.h" | ||
21 | |||
22 | static DEFINE_SPINLOCK(list_lock); | ||
23 | |||
24 | static void omap_irq_error_handler(struct omap_drm_irq *irq, | ||
25 | uint32_t irqstatus) | ||
26 | { | ||
27 | DRM_ERROR("errors: %08x\n", irqstatus); | ||
28 | } | ||
29 | |||
30 | /* call with list_lock and dispc runtime held */ | ||
31 | static void omap_irq_update(struct drm_device *dev) | ||
32 | { | ||
33 | struct omap_drm_private *priv = dev->dev_private; | ||
34 | struct omap_drm_irq *irq; | ||
35 | uint32_t irqmask = priv->vblank_mask; | ||
36 | |||
37 | BUG_ON(!spin_is_locked(&list_lock)); | ||
38 | |||
39 | list_for_each_entry(irq, &priv->irq_list, node) | ||
40 | irqmask |= irq->irqmask; | ||
41 | |||
42 | DBG("irqmask=%08x", irqmask); | ||
43 | |||
44 | dispc_write_irqenable(irqmask); | ||
45 | dispc_read_irqenable(); /* flush posted write */ | ||
46 | } | ||
47 | |||
48 | void omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq) | ||
49 | { | ||
50 | struct omap_drm_private *priv = dev->dev_private; | ||
51 | unsigned long flags; | ||
52 | |||
53 | dispc_runtime_get(); | ||
54 | spin_lock_irqsave(&list_lock, flags); | ||
55 | |||
56 | if (!WARN_ON(irq->registered)) { | ||
57 | irq->registered = true; | ||
58 | list_add(&irq->node, &priv->irq_list); | ||
59 | omap_irq_update(dev); | ||
60 | } | ||
61 | |||
62 | spin_unlock_irqrestore(&list_lock, flags); | ||
63 | dispc_runtime_put(); | ||
64 | } | ||
65 | |||
66 | void omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq) | ||
67 | { | ||
68 | unsigned long flags; | ||
69 | |||
70 | dispc_runtime_get(); | ||
71 | spin_lock_irqsave(&list_lock, flags); | ||
72 | |||
73 | if (!WARN_ON(!irq->registered)) { | ||
74 | irq->registered = false; | ||
75 | list_del(&irq->node); | ||
76 | omap_irq_update(dev); | ||
77 | } | ||
78 | |||
79 | spin_unlock_irqrestore(&list_lock, flags); | ||
80 | dispc_runtime_put(); | ||
81 | } | ||
82 | |||
83 | struct omap_irq_wait { | ||
84 | struct omap_drm_irq irq; | ||
85 | int count; | ||
86 | }; | ||
87 | |||
88 | static DECLARE_WAIT_QUEUE_HEAD(wait_event); | ||
89 | |||
90 | static void wait_irq(struct omap_drm_irq *irq, uint32_t irqstatus) | ||
91 | { | ||
92 | struct omap_irq_wait *wait = | ||
93 | container_of(irq, struct omap_irq_wait, irq); | ||
94 | wait->count--; | ||
95 | wake_up_all(&wait_event); | ||
96 | } | ||
97 | |||
98 | struct omap_irq_wait * omap_irq_wait_init(struct drm_device *dev, | ||
99 | uint32_t irqmask, int count) | ||
100 | { | ||
101 | struct omap_irq_wait *wait = kzalloc(sizeof(*wait), GFP_KERNEL); | ||
102 | wait->irq.irq = wait_irq; | ||
103 | wait->irq.irqmask = irqmask; | ||
104 | wait->count = count; | ||
105 | omap_irq_register(dev, &wait->irq); | ||
106 | return wait; | ||
107 | } | ||
108 | |||
109 | int omap_irq_wait(struct drm_device *dev, struct omap_irq_wait *wait, | ||
110 | unsigned long timeout) | ||
111 | { | ||
112 | int ret = wait_event_timeout(wait_event, (wait->count <= 0), timeout); | ||
113 | omap_irq_unregister(dev, &wait->irq); | ||
114 | kfree(wait); | ||
115 | if (ret == 0) | ||
116 | return -1; | ||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | /** | ||
121 | * enable_vblank - enable vblank interrupt events | ||
122 | * @dev: DRM device | ||
123 | * @crtc: which irq to enable | ||
124 | * | ||
125 | * Enable vblank interrupts for @crtc. If the device doesn't have | ||
126 | * a hardware vblank counter, this routine should be a no-op, since | ||
127 | * interrupts will have to stay on to keep the count accurate. | ||
128 | * | ||
129 | * RETURNS | ||
130 | * Zero on success, appropriate errno if the given @crtc's vblank | ||
131 | * interrupt cannot be enabled. | ||
132 | */ | ||
133 | int omap_irq_enable_vblank(struct drm_device *dev, int crtc) | ||
134 | { | ||
135 | struct omap_drm_private *priv = dev->dev_private; | ||
136 | unsigned long flags; | ||
137 | |||
138 | DBG("dev=%p, crtc=%d", dev, crtc); | ||
139 | |||
140 | dispc_runtime_get(); | ||
141 | spin_lock_irqsave(&list_lock, flags); | ||
142 | priv->vblank_mask |= pipe2vbl(crtc); | ||
143 | omap_irq_update(dev); | ||
144 | spin_unlock_irqrestore(&list_lock, flags); | ||
145 | dispc_runtime_put(); | ||
146 | |||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | /** | ||
151 | * disable_vblank - disable vblank interrupt events | ||
152 | * @dev: DRM device | ||
153 | * @crtc: which irq to enable | ||
154 | * | ||
155 | * Disable vblank interrupts for @crtc. If the device doesn't have | ||
156 | * a hardware vblank counter, this routine should be a no-op, since | ||
157 | * interrupts will have to stay on to keep the count accurate. | ||
158 | */ | ||
159 | void omap_irq_disable_vblank(struct drm_device *dev, int crtc) | ||
160 | { | ||
161 | struct omap_drm_private *priv = dev->dev_private; | ||
162 | unsigned long flags; | ||
163 | |||
164 | DBG("dev=%p, crtc=%d", dev, crtc); | ||
165 | |||
166 | dispc_runtime_get(); | ||
167 | spin_lock_irqsave(&list_lock, flags); | ||
168 | priv->vblank_mask &= ~pipe2vbl(crtc); | ||
169 | omap_irq_update(dev); | ||
170 | spin_unlock_irqrestore(&list_lock, flags); | ||
171 | dispc_runtime_put(); | ||
172 | } | ||
173 | |||
174 | irqreturn_t omap_irq_handler(DRM_IRQ_ARGS) | ||
175 | { | ||
176 | struct drm_device *dev = (struct drm_device *) arg; | ||
177 | struct omap_drm_private *priv = dev->dev_private; | ||
178 | struct omap_drm_irq *handler, *n; | ||
179 | unsigned long flags; | ||
180 | unsigned int id; | ||
181 | u32 irqstatus; | ||
182 | |||
183 | irqstatus = dispc_read_irqstatus(); | ||
184 | dispc_clear_irqstatus(irqstatus); | ||
185 | dispc_read_irqstatus(); /* flush posted write */ | ||
186 | |||
187 | VERB("irqs: %08x", irqstatus); | ||
188 | |||
189 | for (id = 0; id < priv->num_crtcs; id++) | ||
190 | if (irqstatus & pipe2vbl(id)) | ||
191 | drm_handle_vblank(dev, id); | ||
192 | |||
193 | spin_lock_irqsave(&list_lock, flags); | ||
194 | list_for_each_entry_safe(handler, n, &priv->irq_list, node) { | ||
195 | if (handler->irqmask & irqstatus) { | ||
196 | spin_unlock_irqrestore(&list_lock, flags); | ||
197 | handler->irq(handler, handler->irqmask & irqstatus); | ||
198 | spin_lock_irqsave(&list_lock, flags); | ||
199 | } | ||
200 | } | ||
201 | spin_unlock_irqrestore(&list_lock, flags); | ||
202 | |||
203 | return IRQ_HANDLED; | ||
204 | } | ||
205 | |||
206 | void omap_irq_preinstall(struct drm_device *dev) | ||
207 | { | ||
208 | DBG("dev=%p", dev); | ||
209 | dispc_runtime_get(); | ||
210 | dispc_clear_irqstatus(0xffffffff); | ||
211 | dispc_runtime_put(); | ||
212 | } | ||
213 | |||
214 | int omap_irq_postinstall(struct drm_device *dev) | ||
215 | { | ||
216 | struct omap_drm_private *priv = dev->dev_private; | ||
217 | struct omap_drm_irq *error_handler = &priv->error_handler; | ||
218 | |||
219 | DBG("dev=%p", dev); | ||
220 | |||
221 | INIT_LIST_HEAD(&priv->irq_list); | ||
222 | |||
223 | error_handler->irq = omap_irq_error_handler; | ||
224 | error_handler->irqmask = DISPC_IRQ_OCP_ERR; | ||
225 | |||
226 | /* for now ignore DISPC_IRQ_SYNC_LOST_DIGIT.. really I think | ||
227 | * we just need to ignore it while enabling tv-out | ||
228 | */ | ||
229 | error_handler->irqmask &= ~DISPC_IRQ_SYNC_LOST_DIGIT; | ||
230 | |||
231 | omap_irq_register(dev, error_handler); | ||
232 | |||
233 | return 0; | ||
234 | } | ||
235 | |||
236 | void omap_irq_uninstall(struct drm_device *dev) | ||
237 | { | ||
238 | DBG("dev=%p", dev); | ||
239 | // TODO prolly need to call drm_irq_uninstall() somewhere too | ||
240 | } | ||
241 | |||
242 | /* | ||
243 | * We need a special version, instead of just using drm_irq_install(), | ||
244 | * because we need to register the irq via omapdss. Once omapdss and | ||
245 | * omapdrm are merged together we can assign the dispc hwmod data to | ||
246 | * ourselves and drop these and just use drm_irq_{install,uninstall}() | ||
247 | */ | ||
248 | |||
249 | int omap_drm_irq_install(struct drm_device *dev) | ||
250 | { | ||
251 | int ret; | ||
252 | |||
253 | mutex_lock(&dev->struct_mutex); | ||
254 | |||
255 | if (dev->irq_enabled) { | ||
256 | mutex_unlock(&dev->struct_mutex); | ||
257 | return -EBUSY; | ||
258 | } | ||
259 | dev->irq_enabled = 1; | ||
260 | mutex_unlock(&dev->struct_mutex); | ||
261 | |||
262 | /* Before installing handler */ | ||
263 | if (dev->driver->irq_preinstall) | ||
264 | dev->driver->irq_preinstall(dev); | ||
265 | |||
266 | ret = dispc_request_irq(dev->driver->irq_handler, dev); | ||
267 | |||
268 | if (ret < 0) { | ||
269 | mutex_lock(&dev->struct_mutex); | ||
270 | dev->irq_enabled = 0; | ||
271 | mutex_unlock(&dev->struct_mutex); | ||
272 | return ret; | ||
273 | } | ||
274 | |||
275 | /* After installing handler */ | ||
276 | if (dev->driver->irq_postinstall) | ||
277 | ret = dev->driver->irq_postinstall(dev); | ||
278 | |||
279 | if (ret < 0) { | ||
280 | mutex_lock(&dev->struct_mutex); | ||
281 | dev->irq_enabled = 0; | ||
282 | mutex_unlock(&dev->struct_mutex); | ||
283 | dispc_free_irq(dev); | ||
284 | } | ||
285 | |||
286 | return ret; | ||
287 | } | ||
288 | |||
289 | int omap_drm_irq_uninstall(struct drm_device *dev) | ||
290 | { | ||
291 | unsigned long irqflags; | ||
292 | int irq_enabled, i; | ||
293 | |||
294 | mutex_lock(&dev->struct_mutex); | ||
295 | irq_enabled = dev->irq_enabled; | ||
296 | dev->irq_enabled = 0; | ||
297 | mutex_unlock(&dev->struct_mutex); | ||
298 | |||
299 | /* | ||
300 | * Wake up any waiters so they don't hang. | ||
301 | */ | ||
302 | if (dev->num_crtcs) { | ||
303 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | ||
304 | for (i = 0; i < dev->num_crtcs; i++) { | ||
305 | DRM_WAKEUP(&dev->vbl_queue[i]); | ||
306 | dev->vblank_enabled[i] = 0; | ||
307 | dev->last_vblank[i] = | ||
308 | dev->driver->get_vblank_counter(dev, i); | ||
309 | } | ||
310 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | ||
311 | } | ||
312 | |||
313 | if (!irq_enabled) | ||
314 | return -EINVAL; | ||
315 | |||
316 | if (dev->driver->irq_uninstall) | ||
317 | dev->driver->irq_uninstall(dev); | ||
318 | |||
319 | dispc_free_irq(dev); | ||
320 | |||
321 | return 0; | ||
322 | } | ||
diff --git a/drivers/staging/omapdrm/omap_plane.c b/drivers/staging/omapdrm/omap_plane.c index 2a8e5bab49c9..bb989d7f026d 100644 --- a/drivers/staging/omapdrm/omap_plane.c +++ b/drivers/staging/omapdrm/omap_plane.c | |||
@@ -41,12 +41,14 @@ struct callback { | |||
41 | 41 | ||
42 | struct omap_plane { | 42 | struct omap_plane { |
43 | struct drm_plane base; | 43 | struct drm_plane base; |
44 | struct omap_overlay *ovl; | 44 | int id; /* TODO rename omap_plane -> omap_plane_id in omapdss so I can use the enum */ |
45 | const char *name; | ||
45 | struct omap_overlay_info info; | 46 | struct omap_overlay_info info; |
47 | struct omap_drm_apply apply; | ||
46 | 48 | ||
47 | /* position/orientation of scanout within the fb: */ | 49 | /* position/orientation of scanout within the fb: */ |
48 | struct omap_drm_window win; | 50 | struct omap_drm_window win; |
49 | 51 | bool enabled; | |
50 | 52 | ||
51 | /* last fb that we pinned: */ | 53 | /* last fb that we pinned: */ |
52 | struct drm_framebuffer *pinned_fb; | 54 | struct drm_framebuffer *pinned_fb; |
@@ -54,189 +56,15 @@ struct omap_plane { | |||
54 | uint32_t nformats; | 56 | uint32_t nformats; |
55 | uint32_t formats[32]; | 57 | uint32_t formats[32]; |
56 | 58 | ||
57 | /* for synchronizing access to unpins fifo */ | 59 | struct omap_drm_irq error_irq; |
58 | struct mutex unpin_mutex; | ||
59 | 60 | ||
60 | /* set of bo's pending unpin until next END_WIN irq */ | 61 | /* set of bo's pending unpin until next post_apply() */ |
61 | DECLARE_KFIFO_PTR(unpin_fifo, struct drm_gem_object *); | 62 | DECLARE_KFIFO_PTR(unpin_fifo, struct drm_gem_object *); |
62 | int num_unpins, pending_num_unpins; | ||
63 | |||
64 | /* for deferred unpin when we need to wait for scanout complete irq */ | ||
65 | struct work_struct work; | ||
66 | |||
67 | /* callback on next endwin irq */ | ||
68 | struct callback endwin; | ||
69 | }; | ||
70 | 63 | ||
71 | /* map from ovl->id to the irq we are interested in for scanout-done */ | 64 | // XXX maybe get rid of this and handle vblank in crtc too? |
72 | static const uint32_t id2irq[] = { | 65 | struct callback apply_done_cb; |
73 | [OMAP_DSS_GFX] = DISPC_IRQ_GFX_END_WIN, | ||
74 | [OMAP_DSS_VIDEO1] = DISPC_IRQ_VID1_END_WIN, | ||
75 | [OMAP_DSS_VIDEO2] = DISPC_IRQ_VID2_END_WIN, | ||
76 | [OMAP_DSS_VIDEO3] = DISPC_IRQ_VID3_END_WIN, | ||
77 | }; | 66 | }; |
78 | 67 | ||
79 | static void dispc_isr(void *arg, uint32_t mask) | ||
80 | { | ||
81 | struct drm_plane *plane = arg; | ||
82 | struct omap_plane *omap_plane = to_omap_plane(plane); | ||
83 | struct omap_drm_private *priv = plane->dev->dev_private; | ||
84 | |||
85 | omap_dispc_unregister_isr(dispc_isr, plane, | ||
86 | id2irq[omap_plane->ovl->id]); | ||
87 | |||
88 | queue_work(priv->wq, &omap_plane->work); | ||
89 | } | ||
90 | |||
91 | static void unpin_worker(struct work_struct *work) | ||
92 | { | ||
93 | struct omap_plane *omap_plane = | ||
94 | container_of(work, struct omap_plane, work); | ||
95 | struct callback endwin; | ||
96 | |||
97 | mutex_lock(&omap_plane->unpin_mutex); | ||
98 | DBG("unpinning %d of %d", omap_plane->num_unpins, | ||
99 | omap_plane->num_unpins + omap_plane->pending_num_unpins); | ||
100 | while (omap_plane->num_unpins > 0) { | ||
101 | struct drm_gem_object *bo = NULL; | ||
102 | int ret = kfifo_get(&omap_plane->unpin_fifo, &bo); | ||
103 | WARN_ON(!ret); | ||
104 | omap_gem_put_paddr(bo); | ||
105 | drm_gem_object_unreference_unlocked(bo); | ||
106 | omap_plane->num_unpins--; | ||
107 | } | ||
108 | endwin = omap_plane->endwin; | ||
109 | omap_plane->endwin.fxn = NULL; | ||
110 | mutex_unlock(&omap_plane->unpin_mutex); | ||
111 | |||
112 | if (endwin.fxn) | ||
113 | endwin.fxn(endwin.arg); | ||
114 | } | ||
115 | |||
116 | static void install_irq(struct drm_plane *plane) | ||
117 | { | ||
118 | struct omap_plane *omap_plane = to_omap_plane(plane); | ||
119 | struct omap_overlay *ovl = omap_plane->ovl; | ||
120 | int ret; | ||
121 | |||
122 | ret = omap_dispc_register_isr(dispc_isr, plane, id2irq[ovl->id]); | ||
123 | |||
124 | /* | ||
125 | * omapdss has upper limit on # of registered irq handlers, | ||
126 | * which we shouldn't hit.. but if we do the limit should | ||
127 | * be raised or bad things happen: | ||
128 | */ | ||
129 | WARN_ON(ret == -EBUSY); | ||
130 | } | ||
131 | |||
132 | /* push changes down to dss2 */ | ||
133 | static int commit(struct drm_plane *plane) | ||
134 | { | ||
135 | struct drm_device *dev = plane->dev; | ||
136 | struct omap_plane *omap_plane = to_omap_plane(plane); | ||
137 | struct omap_overlay *ovl = omap_plane->ovl; | ||
138 | struct omap_overlay_info *info = &omap_plane->info; | ||
139 | int ret; | ||
140 | |||
141 | DBG("%s", ovl->name); | ||
142 | DBG("%dx%d -> %dx%d (%d)", info->width, info->height, info->out_width, | ||
143 | info->out_height, info->screen_width); | ||
144 | DBG("%d,%d %08x %08x", info->pos_x, info->pos_y, | ||
145 | info->paddr, info->p_uv_addr); | ||
146 | |||
147 | /* NOTE: do we want to do this at all here, or just wait | ||
148 | * for dpms(ON) since other CRTC's may not have their mode | ||
149 | * set yet, so fb dimensions may still change.. | ||
150 | */ | ||
151 | ret = ovl->set_overlay_info(ovl, info); | ||
152 | if (ret) { | ||
153 | dev_err(dev->dev, "could not set overlay info\n"); | ||
154 | return ret; | ||
155 | } | ||
156 | |||
157 | mutex_lock(&omap_plane->unpin_mutex); | ||
158 | omap_plane->num_unpins += omap_plane->pending_num_unpins; | ||
159 | omap_plane->pending_num_unpins = 0; | ||
160 | mutex_unlock(&omap_plane->unpin_mutex); | ||
161 | |||
162 | /* our encoder doesn't necessarily get a commit() after this, in | ||
163 | * particular in the dpms() and mode_set_base() cases, so force the | ||
164 | * manager to update: | ||
165 | * | ||
166 | * could this be in the encoder somehow? | ||
167 | */ | ||
168 | if (ovl->manager) { | ||
169 | ret = ovl->manager->apply(ovl->manager); | ||
170 | if (ret) { | ||
171 | dev_err(dev->dev, "could not apply settings\n"); | ||
172 | return ret; | ||
173 | } | ||
174 | |||
175 | /* | ||
176 | * NOTE: really this should be atomic w/ mgr->apply() but | ||
177 | * omapdss does not expose such an API | ||
178 | */ | ||
179 | if (omap_plane->num_unpins > 0) | ||
180 | install_irq(plane); | ||
181 | |||
182 | } else { | ||
183 | struct omap_drm_private *priv = dev->dev_private; | ||
184 | queue_work(priv->wq, &omap_plane->work); | ||
185 | } | ||
186 | |||
187 | |||
188 | if (ovl->is_enabled(ovl)) { | ||
189 | omap_framebuffer_flush(plane->fb, info->pos_x, info->pos_y, | ||
190 | info->out_width, info->out_height); | ||
191 | } | ||
192 | |||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | /* when CRTC that we are attached to has potentially changed, this checks | ||
197 | * if we are attached to proper manager, and if necessary updates. | ||
198 | */ | ||
199 | static void update_manager(struct drm_plane *plane) | ||
200 | { | ||
201 | struct omap_drm_private *priv = plane->dev->dev_private; | ||
202 | struct omap_plane *omap_plane = to_omap_plane(plane); | ||
203 | struct omap_overlay *ovl = omap_plane->ovl; | ||
204 | struct omap_overlay_manager *mgr = NULL; | ||
205 | int i; | ||
206 | |||
207 | if (plane->crtc) { | ||
208 | for (i = 0; i < priv->num_encoders; i++) { | ||
209 | struct drm_encoder *encoder = priv->encoders[i]; | ||
210 | if (encoder->crtc == plane->crtc) { | ||
211 | mgr = omap_encoder_get_manager(encoder); | ||
212 | break; | ||
213 | } | ||
214 | } | ||
215 | } | ||
216 | |||
217 | if (ovl->manager != mgr) { | ||
218 | bool enabled = ovl->is_enabled(ovl); | ||
219 | |||
220 | /* don't switch things around with enabled overlays: */ | ||
221 | if (enabled) | ||
222 | omap_plane_dpms(plane, DRM_MODE_DPMS_OFF); | ||
223 | |||
224 | if (ovl->manager) { | ||
225 | DBG("disconnecting %s from %s", ovl->name, | ||
226 | ovl->manager->name); | ||
227 | ovl->unset_manager(ovl); | ||
228 | } | ||
229 | |||
230 | if (mgr) { | ||
231 | DBG("connecting %s to %s", ovl->name, mgr->name); | ||
232 | ovl->set_manager(ovl, mgr); | ||
233 | } | ||
234 | |||
235 | if (enabled && mgr) | ||
236 | omap_plane_dpms(plane, DRM_MODE_DPMS_ON); | ||
237 | } | ||
238 | } | ||
239 | |||
240 | static void unpin(void *arg, struct drm_gem_object *bo) | 68 | static void unpin(void *arg, struct drm_gem_object *bo) |
241 | { | 69 | { |
242 | struct drm_plane *plane = arg; | 70 | struct drm_plane *plane = arg; |
@@ -244,7 +72,6 @@ static void unpin(void *arg, struct drm_gem_object *bo) | |||
244 | 72 | ||
245 | if (kfifo_put(&omap_plane->unpin_fifo, | 73 | if (kfifo_put(&omap_plane->unpin_fifo, |
246 | (const struct drm_gem_object **)&bo)) { | 74 | (const struct drm_gem_object **)&bo)) { |
247 | omap_plane->pending_num_unpins++; | ||
248 | /* also hold a ref so it isn't free'd while pinned */ | 75 | /* also hold a ref so it isn't free'd while pinned */ |
249 | drm_gem_object_reference(bo); | 76 | drm_gem_object_reference(bo); |
250 | } else { | 77 | } else { |
@@ -264,13 +91,19 @@ static int update_pin(struct drm_plane *plane, struct drm_framebuffer *fb) | |||
264 | 91 | ||
265 | DBG("%p -> %p", pinned_fb, fb); | 92 | DBG("%p -> %p", pinned_fb, fb); |
266 | 93 | ||
267 | mutex_lock(&omap_plane->unpin_mutex); | 94 | if (fb) |
95 | drm_framebuffer_reference(fb); | ||
96 | |||
268 | ret = omap_framebuffer_replace(pinned_fb, fb, plane, unpin); | 97 | ret = omap_framebuffer_replace(pinned_fb, fb, plane, unpin); |
269 | mutex_unlock(&omap_plane->unpin_mutex); | 98 | |
99 | if (pinned_fb) | ||
100 | drm_framebuffer_unreference(pinned_fb); | ||
270 | 101 | ||
271 | if (ret) { | 102 | if (ret) { |
272 | dev_err(plane->dev->dev, "could not swap %p -> %p\n", | 103 | dev_err(plane->dev->dev, "could not swap %p -> %p\n", |
273 | omap_plane->pinned_fb, fb); | 104 | omap_plane->pinned_fb, fb); |
105 | if (fb) | ||
106 | drm_framebuffer_unreference(fb); | ||
274 | omap_plane->pinned_fb = NULL; | 107 | omap_plane->pinned_fb = NULL; |
275 | return ret; | 108 | return ret; |
276 | } | 109 | } |
@@ -281,31 +114,90 @@ static int update_pin(struct drm_plane *plane, struct drm_framebuffer *fb) | |||
281 | return 0; | 114 | return 0; |
282 | } | 115 | } |
283 | 116 | ||
284 | /* update parameters that are dependent on the framebuffer dimensions and | 117 | static void omap_plane_pre_apply(struct omap_drm_apply *apply) |
285 | * position within the fb that this plane scans out from. This is called | ||
286 | * when framebuffer or x,y base may have changed. | ||
287 | */ | ||
288 | static void update_scanout(struct drm_plane *plane) | ||
289 | { | 118 | { |
290 | struct omap_plane *omap_plane = to_omap_plane(plane); | 119 | struct omap_plane *omap_plane = |
291 | struct omap_overlay_info *info = &omap_plane->info; | 120 | container_of(apply, struct omap_plane, apply); |
292 | struct omap_drm_window *win = &omap_plane->win; | 121 | struct omap_drm_window *win = &omap_plane->win; |
122 | struct drm_plane *plane = &omap_plane->base; | ||
123 | struct drm_device *dev = plane->dev; | ||
124 | struct omap_overlay_info *info = &omap_plane->info; | ||
125 | struct drm_crtc *crtc = plane->crtc; | ||
126 | enum omap_channel channel; | ||
127 | bool enabled = omap_plane->enabled && crtc; | ||
128 | bool ilace, replication; | ||
293 | int ret; | 129 | int ret; |
294 | 130 | ||
295 | ret = update_pin(plane, plane->fb); | 131 | DBG("%s, enabled=%d", omap_plane->name, enabled); |
296 | if (ret) { | 132 | |
297 | dev_err(plane->dev->dev, | 133 | /* if fb has changed, pin new fb: */ |
298 | "could not pin fb: %d\n", ret); | 134 | update_pin(plane, enabled ? plane->fb : NULL); |
299 | omap_plane_dpms(plane, DRM_MODE_DPMS_OFF); | 135 | |
136 | if (!enabled) { | ||
137 | dispc_ovl_enable(omap_plane->id, false); | ||
300 | return; | 138 | return; |
301 | } | 139 | } |
302 | 140 | ||
141 | channel = omap_crtc_channel(crtc); | ||
142 | |||
143 | /* update scanout: */ | ||
303 | omap_framebuffer_update_scanout(plane->fb, win, info); | 144 | omap_framebuffer_update_scanout(plane->fb, win, info); |
304 | 145 | ||
305 | DBG("%s: %d,%d: %08x %08x (%d)", omap_plane->ovl->name, | 146 | DBG("%dx%d -> %dx%d (%d)", info->width, info->height, |
306 | win->src_x, win->src_y, | 147 | info->out_width, info->out_height, |
307 | (u32)info->paddr, (u32)info->p_uv_addr, | ||
308 | info->screen_width); | 148 | info->screen_width); |
149 | DBG("%d,%d %08x %08x", info->pos_x, info->pos_y, | ||
150 | info->paddr, info->p_uv_addr); | ||
151 | |||
152 | /* TODO: */ | ||
153 | ilace = false; | ||
154 | replication = false; | ||
155 | |||
156 | /* and finally, update omapdss: */ | ||
157 | ret = dispc_ovl_setup(omap_plane->id, info, | ||
158 | replication, omap_crtc_timings(crtc), false); | ||
159 | if (ret) { | ||
160 | dev_err(dev->dev, "dispc_ovl_setup failed: %d\n", ret); | ||
161 | return; | ||
162 | } | ||
163 | |||
164 | dispc_ovl_enable(omap_plane->id, true); | ||
165 | dispc_ovl_set_channel_out(omap_plane->id, channel); | ||
166 | } | ||
167 | |||
168 | static void omap_plane_post_apply(struct omap_drm_apply *apply) | ||
169 | { | ||
170 | struct omap_plane *omap_plane = | ||
171 | container_of(apply, struct omap_plane, apply); | ||
172 | struct drm_plane *plane = &omap_plane->base; | ||
173 | struct omap_overlay_info *info = &omap_plane->info; | ||
174 | struct drm_gem_object *bo = NULL; | ||
175 | struct callback cb; | ||
176 | |||
177 | cb = omap_plane->apply_done_cb; | ||
178 | omap_plane->apply_done_cb.fxn = NULL; | ||
179 | |||
180 | while (kfifo_get(&omap_plane->unpin_fifo, &bo)) { | ||
181 | omap_gem_put_paddr(bo); | ||
182 | drm_gem_object_unreference_unlocked(bo); | ||
183 | } | ||
184 | |||
185 | if (cb.fxn) | ||
186 | cb.fxn(cb.arg); | ||
187 | |||
188 | if (omap_plane->enabled) { | ||
189 | omap_framebuffer_flush(plane->fb, info->pos_x, info->pos_y, | ||
190 | info->out_width, info->out_height); | ||
191 | } | ||
192 | } | ||
193 | |||
194 | static int apply(struct drm_plane *plane) | ||
195 | { | ||
196 | if (plane->crtc) { | ||
197 | struct omap_plane *omap_plane = to_omap_plane(plane); | ||
198 | return omap_crtc_apply(plane->crtc, &omap_plane->apply); | ||
199 | } | ||
200 | return 0; | ||
309 | } | 201 | } |
310 | 202 | ||
311 | int omap_plane_mode_set(struct drm_plane *plane, | 203 | int omap_plane_mode_set(struct drm_plane *plane, |
@@ -313,7 +205,8 @@ int omap_plane_mode_set(struct drm_plane *plane, | |||
313 | int crtc_x, int crtc_y, | 205 | int crtc_x, int crtc_y, |
314 | unsigned int crtc_w, unsigned int crtc_h, | 206 | unsigned int crtc_w, unsigned int crtc_h, |
315 | uint32_t src_x, uint32_t src_y, | 207 | uint32_t src_x, uint32_t src_y, |
316 | uint32_t src_w, uint32_t src_h) | 208 | uint32_t src_w, uint32_t src_h, |
209 | void (*fxn)(void *), void *arg) | ||
317 | { | 210 | { |
318 | struct omap_plane *omap_plane = to_omap_plane(plane); | 211 | struct omap_plane *omap_plane = to_omap_plane(plane); |
319 | struct omap_drm_window *win = &omap_plane->win; | 212 | struct omap_drm_window *win = &omap_plane->win; |
@@ -329,17 +222,20 @@ int omap_plane_mode_set(struct drm_plane *plane, | |||
329 | win->src_w = src_w >> 16; | 222 | win->src_w = src_w >> 16; |
330 | win->src_h = src_h >> 16; | 223 | win->src_h = src_h >> 16; |
331 | 224 | ||
332 | /* note: this is done after this fxn returns.. but if we need | 225 | if (fxn) { |
333 | * to do a commit/update_scanout, etc before this returns we | 226 | /* omap_crtc should ensure that a new page flip |
334 | * need the current value. | 227 | * isn't permitted while there is one pending: |
335 | */ | 228 | */ |
229 | BUG_ON(omap_plane->apply_done_cb.fxn); | ||
230 | |||
231 | omap_plane->apply_done_cb.fxn = fxn; | ||
232 | omap_plane->apply_done_cb.arg = arg; | ||
233 | } | ||
234 | |||
336 | plane->fb = fb; | 235 | plane->fb = fb; |
337 | plane->crtc = crtc; | 236 | plane->crtc = crtc; |
338 | 237 | ||
339 | update_scanout(plane); | 238 | return apply(plane); |
340 | update_manager(plane); | ||
341 | |||
342 | return 0; | ||
343 | } | 239 | } |
344 | 240 | ||
345 | static int omap_plane_update(struct drm_plane *plane, | 241 | static int omap_plane_update(struct drm_plane *plane, |
@@ -349,9 +245,12 @@ static int omap_plane_update(struct drm_plane *plane, | |||
349 | uint32_t src_x, uint32_t src_y, | 245 | uint32_t src_x, uint32_t src_y, |
350 | uint32_t src_w, uint32_t src_h) | 246 | uint32_t src_w, uint32_t src_h) |
351 | { | 247 | { |
352 | omap_plane_mode_set(plane, crtc, fb, crtc_x, crtc_y, crtc_w, crtc_h, | 248 | struct omap_plane *omap_plane = to_omap_plane(plane); |
353 | src_x, src_y, src_w, src_h); | 249 | omap_plane->enabled = true; |
354 | return omap_plane_dpms(plane, DRM_MODE_DPMS_ON); | 250 | return omap_plane_mode_set(plane, crtc, fb, |
251 | crtc_x, crtc_y, crtc_w, crtc_h, | ||
252 | src_x, src_y, src_w, src_h, | ||
253 | NULL, NULL); | ||
355 | } | 254 | } |
356 | 255 | ||
357 | static int omap_plane_disable(struct drm_plane *plane) | 256 | static int omap_plane_disable(struct drm_plane *plane) |
@@ -364,48 +263,32 @@ static int omap_plane_disable(struct drm_plane *plane) | |||
364 | static void omap_plane_destroy(struct drm_plane *plane) | 263 | static void omap_plane_destroy(struct drm_plane *plane) |
365 | { | 264 | { |
366 | struct omap_plane *omap_plane = to_omap_plane(plane); | 265 | struct omap_plane *omap_plane = to_omap_plane(plane); |
367 | DBG("%s", omap_plane->ovl->name); | 266 | |
267 | DBG("%s", omap_plane->name); | ||
268 | |||
269 | omap_irq_unregister(plane->dev, &omap_plane->error_irq); | ||
270 | |||
368 | omap_plane_disable(plane); | 271 | omap_plane_disable(plane); |
369 | drm_plane_cleanup(plane); | 272 | drm_plane_cleanup(plane); |
370 | WARN_ON(omap_plane->pending_num_unpins + omap_plane->num_unpins > 0); | 273 | |
274 | WARN_ON(!kfifo_is_empty(&omap_plane->unpin_fifo)); | ||
371 | kfifo_free(&omap_plane->unpin_fifo); | 275 | kfifo_free(&omap_plane->unpin_fifo); |
276 | |||
372 | kfree(omap_plane); | 277 | kfree(omap_plane); |
373 | } | 278 | } |
374 | 279 | ||
375 | int omap_plane_dpms(struct drm_plane *plane, int mode) | 280 | int omap_plane_dpms(struct drm_plane *plane, int mode) |
376 | { | 281 | { |
377 | struct omap_plane *omap_plane = to_omap_plane(plane); | 282 | struct omap_plane *omap_plane = to_omap_plane(plane); |
378 | struct omap_overlay *ovl = omap_plane->ovl; | 283 | bool enabled = (mode == DRM_MODE_DPMS_ON); |
379 | int r; | 284 | int ret = 0; |
380 | 285 | ||
381 | DBG("%s: %d", omap_plane->ovl->name, mode); | 286 | if (enabled != omap_plane->enabled) { |
382 | 287 | omap_plane->enabled = enabled; | |
383 | if (mode == DRM_MODE_DPMS_ON) { | 288 | ret = apply(plane); |
384 | update_scanout(plane); | ||
385 | r = commit(plane); | ||
386 | if (!r) | ||
387 | r = ovl->enable(ovl); | ||
388 | } else { | ||
389 | struct omap_drm_private *priv = plane->dev->dev_private; | ||
390 | r = ovl->disable(ovl); | ||
391 | update_pin(plane, NULL); | ||
392 | queue_work(priv->wq, &omap_plane->work); | ||
393 | } | 289 | } |
394 | 290 | ||
395 | return r; | 291 | return ret; |
396 | } | ||
397 | |||
398 | void omap_plane_on_endwin(struct drm_plane *plane, | ||
399 | void (*fxn)(void *), void *arg) | ||
400 | { | ||
401 | struct omap_plane *omap_plane = to_omap_plane(plane); | ||
402 | |||
403 | mutex_lock(&omap_plane->unpin_mutex); | ||
404 | omap_plane->endwin.fxn = fxn; | ||
405 | omap_plane->endwin.arg = arg; | ||
406 | mutex_unlock(&omap_plane->unpin_mutex); | ||
407 | |||
408 | install_irq(plane); | ||
409 | } | 292 | } |
410 | 293 | ||
411 | /* helper to install properties which are common to planes and crtcs */ | 294 | /* helper to install properties which are common to planes and crtcs */ |
@@ -454,25 +337,13 @@ int omap_plane_set_property(struct drm_plane *plane, | |||
454 | int ret = -EINVAL; | 337 | int ret = -EINVAL; |
455 | 338 | ||
456 | if (property == priv->rotation_prop) { | 339 | if (property == priv->rotation_prop) { |
457 | struct omap_overlay *ovl = omap_plane->ovl; | 340 | DBG("%s: rotation: %02x", omap_plane->name, (uint32_t)val); |
458 | |||
459 | DBG("%s: rotation: %02x", ovl->name, (uint32_t)val); | ||
460 | omap_plane->win.rotation = val; | 341 | omap_plane->win.rotation = val; |
461 | 342 | ret = apply(plane); | |
462 | if (ovl->is_enabled(ovl)) | ||
463 | ret = omap_plane_dpms(plane, DRM_MODE_DPMS_ON); | ||
464 | else | ||
465 | ret = 0; | ||
466 | } else if (property == priv->zorder_prop) { | 343 | } else if (property == priv->zorder_prop) { |
467 | struct omap_overlay *ovl = omap_plane->ovl; | 344 | DBG("%s: zorder: %02x", omap_plane->name, (uint32_t)val); |
468 | |||
469 | DBG("%s: zorder: %d", ovl->name, (uint32_t)val); | ||
470 | omap_plane->info.zorder = val; | 345 | omap_plane->info.zorder = val; |
471 | 346 | ret = apply(plane); | |
472 | if (ovl->is_enabled(ovl)) | ||
473 | ret = omap_plane_dpms(plane, DRM_MODE_DPMS_ON); | ||
474 | else | ||
475 | ret = 0; | ||
476 | } | 347 | } |
477 | 348 | ||
478 | return ret; | 349 | return ret; |
@@ -485,20 +356,38 @@ static const struct drm_plane_funcs omap_plane_funcs = { | |||
485 | .set_property = omap_plane_set_property, | 356 | .set_property = omap_plane_set_property, |
486 | }; | 357 | }; |
487 | 358 | ||
359 | static void omap_plane_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus) | ||
360 | { | ||
361 | struct omap_plane *omap_plane = | ||
362 | container_of(irq, struct omap_plane, error_irq); | ||
363 | DRM_ERROR("%s: errors: %08x\n", omap_plane->name, irqstatus); | ||
364 | } | ||
365 | |||
366 | static const char *plane_names[] = { | ||
367 | [OMAP_DSS_GFX] = "gfx", | ||
368 | [OMAP_DSS_VIDEO1] = "vid1", | ||
369 | [OMAP_DSS_VIDEO2] = "vid2", | ||
370 | [OMAP_DSS_VIDEO3] = "vid3", | ||
371 | }; | ||
372 | |||
373 | static const uint32_t error_irqs[] = { | ||
374 | [OMAP_DSS_GFX] = DISPC_IRQ_GFX_FIFO_UNDERFLOW, | ||
375 | [OMAP_DSS_VIDEO1] = DISPC_IRQ_VID1_FIFO_UNDERFLOW, | ||
376 | [OMAP_DSS_VIDEO2] = DISPC_IRQ_VID2_FIFO_UNDERFLOW, | ||
377 | [OMAP_DSS_VIDEO3] = DISPC_IRQ_VID3_FIFO_UNDERFLOW, | ||
378 | }; | ||
379 | |||
488 | /* initialize plane */ | 380 | /* initialize plane */ |
489 | struct drm_plane *omap_plane_init(struct drm_device *dev, | 381 | struct drm_plane *omap_plane_init(struct drm_device *dev, |
490 | struct omap_overlay *ovl, unsigned int possible_crtcs, | 382 | int id, bool private_plane) |
491 | bool priv) | ||
492 | { | 383 | { |
384 | struct omap_drm_private *priv = dev->dev_private; | ||
493 | struct drm_plane *plane = NULL; | 385 | struct drm_plane *plane = NULL; |
494 | struct omap_plane *omap_plane; | 386 | struct omap_plane *omap_plane; |
387 | struct omap_overlay_info *info; | ||
495 | int ret; | 388 | int ret; |
496 | 389 | ||
497 | DBG("%s: possible_crtcs=%08x, priv=%d", ovl->name, | 390 | DBG("%s: priv=%d", plane_names[id], private_plane); |
498 | possible_crtcs, priv); | ||
499 | |||
500 | /* friendly reminder to update table for future hw: */ | ||
501 | WARN_ON(ovl->id >= ARRAY_SIZE(id2irq)); | ||
502 | 391 | ||
503 | omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL); | 392 | omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL); |
504 | if (!omap_plane) { | 393 | if (!omap_plane) { |
@@ -506,47 +395,50 @@ struct drm_plane *omap_plane_init(struct drm_device *dev, | |||
506 | goto fail; | 395 | goto fail; |
507 | } | 396 | } |
508 | 397 | ||
509 | mutex_init(&omap_plane->unpin_mutex); | ||
510 | |||
511 | ret = kfifo_alloc(&omap_plane->unpin_fifo, 16, GFP_KERNEL); | 398 | ret = kfifo_alloc(&omap_plane->unpin_fifo, 16, GFP_KERNEL); |
512 | if (ret) { | 399 | if (ret) { |
513 | dev_err(dev->dev, "could not allocate unpin FIFO\n"); | 400 | dev_err(dev->dev, "could not allocate unpin FIFO\n"); |
514 | goto fail; | 401 | goto fail; |
515 | } | 402 | } |
516 | 403 | ||
517 | INIT_WORK(&omap_plane->work, unpin_worker); | ||
518 | |||
519 | omap_plane->nformats = omap_framebuffer_get_formats( | 404 | omap_plane->nformats = omap_framebuffer_get_formats( |
520 | omap_plane->formats, ARRAY_SIZE(omap_plane->formats), | 405 | omap_plane->formats, ARRAY_SIZE(omap_plane->formats), |
521 | ovl->supported_modes); | 406 | dss_feat_get_supported_color_modes(id)); |
522 | omap_plane->ovl = ovl; | 407 | omap_plane->id = id; |
408 | omap_plane->name = plane_names[id]; | ||
409 | |||
523 | plane = &omap_plane->base; | 410 | plane = &omap_plane->base; |
524 | 411 | ||
525 | drm_plane_init(dev, plane, possible_crtcs, &omap_plane_funcs, | 412 | omap_plane->apply.pre_apply = omap_plane_pre_apply; |
526 | omap_plane->formats, omap_plane->nformats, priv); | 413 | omap_plane->apply.post_apply = omap_plane_post_apply; |
414 | |||
415 | omap_plane->error_irq.irqmask = error_irqs[id]; | ||
416 | omap_plane->error_irq.irq = omap_plane_error_irq; | ||
417 | omap_irq_register(dev, &omap_plane->error_irq); | ||
418 | |||
419 | drm_plane_init(dev, plane, (1 << priv->num_crtcs) - 1, &omap_plane_funcs, | ||
420 | omap_plane->formats, omap_plane->nformats, private_plane); | ||
527 | 421 | ||
528 | omap_plane_install_properties(plane, &plane->base); | 422 | omap_plane_install_properties(plane, &plane->base); |
529 | 423 | ||
530 | /* get our starting configuration, set defaults for parameters | 424 | /* get our starting configuration, set defaults for parameters |
531 | * we don't currently use, etc: | 425 | * we don't currently use, etc: |
532 | */ | 426 | */ |
533 | ovl->get_overlay_info(ovl, &omap_plane->info); | 427 | info = &omap_plane->info; |
534 | omap_plane->info.rotation_type = OMAP_DSS_ROT_DMA; | 428 | info->rotation_type = OMAP_DSS_ROT_DMA; |
535 | omap_plane->info.rotation = OMAP_DSS_ROT_0; | 429 | info->rotation = OMAP_DSS_ROT_0; |
536 | omap_plane->info.global_alpha = 0xff; | 430 | info->global_alpha = 0xff; |
537 | omap_plane->info.mirror = 0; | 431 | info->mirror = 0; |
538 | 432 | ||
539 | /* Set defaults depending on whether we are a CRTC or overlay | 433 | /* Set defaults depending on whether we are a CRTC or overlay |
540 | * layer. | 434 | * layer. |
541 | * TODO add ioctl to give userspace an API to change this.. this | 435 | * TODO add ioctl to give userspace an API to change this.. this |
542 | * will come in a subsequent patch. | 436 | * will come in a subsequent patch. |
543 | */ | 437 | */ |
544 | if (priv) | 438 | if (private_plane) |
545 | omap_plane->info.zorder = 0; | 439 | omap_plane->info.zorder = 0; |
546 | else | 440 | else |
547 | omap_plane->info.zorder = ovl->id; | 441 | omap_plane->info.zorder = id; |
548 | |||
549 | update_manager(plane); | ||
550 | 442 | ||
551 | return plane; | 443 | return plane; |
552 | 444 | ||
diff --git a/drivers/staging/rtl8187se/r8180_core.c b/drivers/staging/rtl8187se/r8180_core.c index ae38475854b5..d10d75e8a33f 100644 --- a/drivers/staging/rtl8187se/r8180_core.c +++ b/drivers/staging/rtl8187se/r8180_core.c | |||
@@ -937,7 +937,8 @@ short alloc_rx_desc_ring(struct net_device *dev, u16 bufsize, int count) | |||
937 | 937 | ||
938 | dma_tmp = pci_map_single(pdev, buf, bufsize * sizeof(u8), | 938 | dma_tmp = pci_map_single(pdev, buf, bufsize * sizeof(u8), |
939 | PCI_DMA_FROMDEVICE); | 939 | PCI_DMA_FROMDEVICE); |
940 | 940 | if (pci_dma_mapping_error(pdev, dma_tmp)) | |
941 | return -1; | ||
941 | if (-1 == buffer_add(&(priv->rxbuffer), buf, dma_tmp, | 942 | if (-1 == buffer_add(&(priv->rxbuffer), buf, dma_tmp, |
942 | &(priv->rxbufferhead))) { | 943 | &(priv->rxbufferhead))) { |
943 | DMESGE("Unable to allocate mem RX buf"); | 944 | DMESGE("Unable to allocate mem RX buf"); |
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 808aab6fa5ef..a9d78e9651c6 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | |||
@@ -1183,6 +1183,8 @@ void rtl8192_tx_fill_desc(struct net_device *dev, struct tx_desc *pdesc, | |||
1183 | pTxFwInfo->TxRate, | 1183 | pTxFwInfo->TxRate, |
1184 | cb_desc); | 1184 | cb_desc); |
1185 | 1185 | ||
1186 | if (pci_dma_mapping_error(priv->pdev, mapping)) | ||
1187 | RT_TRACE(COMP_ERR, "DMA Mapping error\n");; | ||
1186 | if (cb_desc->bAMPDUEnable) { | 1188 | if (cb_desc->bAMPDUEnable) { |
1187 | pTxFwInfo->AllowAggregation = 1; | 1189 | pTxFwInfo->AllowAggregation = 1; |
1188 | pTxFwInfo->RxMF = cb_desc->ampdu_factor; | 1190 | pTxFwInfo->RxMF = cb_desc->ampdu_factor; |
@@ -1280,6 +1282,8 @@ void rtl8192_tx_fill_cmd_desc(struct net_device *dev, | |||
1280 | dma_addr_t mapping = pci_map_single(priv->pdev, skb->data, skb->len, | 1282 | dma_addr_t mapping = pci_map_single(priv->pdev, skb->data, skb->len, |
1281 | PCI_DMA_TODEVICE); | 1283 | PCI_DMA_TODEVICE); |
1282 | 1284 | ||
1285 | if (pci_dma_mapping_error(priv->pdev, mapping)) | ||
1286 | RT_TRACE(COMP_ERR, "DMA Mapping error\n");; | ||
1283 | memset(entry, 0, 12); | 1287 | memset(entry, 0, 12); |
1284 | entry->LINIP = cb_desc->bLastIniPkt; | 1288 | entry->LINIP = cb_desc->bLastIniPkt; |
1285 | entry->FirstSeg = 1; | 1289 | entry->FirstSeg = 1; |
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 1a70f324552f..4ebf99b30975 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c | |||
@@ -2104,7 +2104,10 @@ static short rtl8192_alloc_rx_desc_ring(struct net_device *dev) | |||
2104 | skb_tail_pointer_rsl(skb), | 2104 | skb_tail_pointer_rsl(skb), |
2105 | priv->rxbuffersize, | 2105 | priv->rxbuffersize, |
2106 | PCI_DMA_FROMDEVICE); | 2106 | PCI_DMA_FROMDEVICE); |
2107 | 2107 | if (pci_dma_mapping_error(priv->pdev, *mapping)) { | |
2108 | dev_kfree_skb_any(skb); | ||
2109 | return -1; | ||
2110 | } | ||
2108 | entry->BufferAddress = cpu_to_le32(*mapping); | 2111 | entry->BufferAddress = cpu_to_le32(*mapping); |
2109 | 2112 | ||
2110 | entry->Length = priv->rxbuffersize; | 2113 | entry->Length = priv->rxbuffersize; |
@@ -2397,7 +2400,11 @@ static void rtl8192_rx_normal(struct net_device *dev) | |||
2397 | skb_tail_pointer_rsl(skb), | 2400 | skb_tail_pointer_rsl(skb), |
2398 | priv->rxbuffersize, | 2401 | priv->rxbuffersize, |
2399 | PCI_DMA_FROMDEVICE); | 2402 | PCI_DMA_FROMDEVICE); |
2400 | 2403 | if (pci_dma_mapping_error(priv->pdev, | |
2404 | *((dma_addr_t *)skb->cb))) { | ||
2405 | dev_kfree_skb_any(skb); | ||
2406 | return; | ||
2407 | } | ||
2401 | } | 2408 | } |
2402 | done: | 2409 | done: |
2403 | pdesc->BufferAddress = cpu_to_le32(*((dma_addr_t *)skb->cb)); | 2410 | pdesc->BufferAddress = cpu_to_le32(*((dma_addr_t *)skb->cb)); |
diff --git a/drivers/staging/rtl8712/usb_intf.c b/drivers/staging/rtl8712/usb_intf.c index 6b73843e580a..a96cd06d69dd 100644 --- a/drivers/staging/rtl8712/usb_intf.c +++ b/drivers/staging/rtl8712/usb_intf.c | |||
@@ -63,6 +63,8 @@ static struct usb_device_id rtl871x_usb_id_tbl[] = { | |||
63 | {USB_DEVICE(0x0B05, 0x1791)}, /* 11n mode disable */ | 63 | {USB_DEVICE(0x0B05, 0x1791)}, /* 11n mode disable */ |
64 | /* Belkin */ | 64 | /* Belkin */ |
65 | {USB_DEVICE(0x050D, 0x945A)}, | 65 | {USB_DEVICE(0x050D, 0x945A)}, |
66 | /* ISY IWL - Belkin clone */ | ||
67 | {USB_DEVICE(0x050D, 0x11F1)}, | ||
66 | /* Corega */ | 68 | /* Corega */ |
67 | {USB_DEVICE(0x07AA, 0x0047)}, | 69 | {USB_DEVICE(0x07AA, 0x0047)}, |
68 | /* D-Link */ | 70 | /* D-Link */ |
diff --git a/drivers/staging/sb105x/Kconfig b/drivers/staging/sb105x/Kconfig index ac87c5e38dee..1facad625554 100644 --- a/drivers/staging/sb105x/Kconfig +++ b/drivers/staging/sb105x/Kconfig | |||
@@ -2,6 +2,7 @@ config SB105X | |||
2 | tristate "SystemBase PCI Multiport UART" | 2 | tristate "SystemBase PCI Multiport UART" |
3 | select SERIAL_CORE | 3 | select SERIAL_CORE |
4 | depends on PCI | 4 | depends on PCI |
5 | depends on X86 | ||
5 | help | 6 | help |
6 | A driver for the SystemBase Multi-2/PCI serial card | 7 | A driver for the SystemBase Multi-2/PCI serial card |
7 | 8 | ||
diff --git a/drivers/staging/sb105x/sb_pci_mp.c b/drivers/staging/sb105x/sb_pci_mp.c index edb2a85b9d52..9464f3874346 100644 --- a/drivers/staging/sb105x/sb_pci_mp.c +++ b/drivers/staging/sb105x/sb_pci_mp.c | |||
@@ -3054,6 +3054,7 @@ static int init_mp_dev(struct pci_dev *pcidev, mppcibrd_t brd) | |||
3054 | sbdev->nr_ports = ((portnum_hex/16)*10) + (portnum_hex % 16); | 3054 | sbdev->nr_ports = ((portnum_hex/16)*10) + (portnum_hex % 16); |
3055 | } | 3055 | } |
3056 | break; | 3056 | break; |
3057 | #ifdef CONFIG_PARPORT_PC | ||
3057 | case PCI_DEVICE_ID_MP2S1P : | 3058 | case PCI_DEVICE_ID_MP2S1P : |
3058 | sbdev->nr_ports = 2; | 3059 | sbdev->nr_ports = 2; |
3059 | 3060 | ||
@@ -3073,6 +3074,7 @@ static int init_mp_dev(struct pci_dev *pcidev, mppcibrd_t brd) | |||
3073 | /* add PC compatible parallel port */ | 3074 | /* add PC compatible parallel port */ |
3074 | parport_pc_probe_port(pcidev->resource[2].start, pcidev->resource[3].start, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, &pcidev->dev, 0); | 3075 | parport_pc_probe_port(pcidev->resource[2].start, pcidev->resource[3].start, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, &pcidev->dev, 0); |
3075 | break; | 3076 | break; |
3077 | #endif | ||
3076 | } | 3078 | } |
3077 | 3079 | ||
3078 | ret = request_region(sbdev->uart_access_addr, (8*sbdev->nr_ports), sbdev->name); | 3080 | ret = request_region(sbdev->uart_access_addr, (8*sbdev->nr_ports), sbdev->name); |
diff --git a/drivers/staging/speakup/synth.c b/drivers/staging/speakup/synth.c index df9533798095..7616f058a00b 100644 --- a/drivers/staging/speakup/synth.c +++ b/drivers/staging/speakup/synth.c | |||
@@ -342,7 +342,7 @@ int synth_init(char *synth_name) | |||
342 | 342 | ||
343 | mutex_lock(&spk_mutex); | 343 | mutex_lock(&spk_mutex); |
344 | /* First, check if we already have it loaded. */ | 344 | /* First, check if we already have it loaded. */ |
345 | for (i = 0; synths[i] != NULL && i < MAXSYNTHS; i++) | 345 | for (i = 0; i < MAXSYNTHS && synths[i] != NULL; i++) |
346 | if (strcmp(synths[i]->name, synth_name) == 0) | 346 | if (strcmp(synths[i]->name, synth_name) == 0) |
347 | synth = synths[i]; | 347 | synth = synths[i]; |
348 | 348 | ||
@@ -423,7 +423,7 @@ int synth_add(struct spk_synth *in_synth) | |||
423 | int i; | 423 | int i; |
424 | int status = 0; | 424 | int status = 0; |
425 | mutex_lock(&spk_mutex); | 425 | mutex_lock(&spk_mutex); |
426 | for (i = 0; synths[i] != NULL && i < MAXSYNTHS; i++) | 426 | for (i = 0; i < MAXSYNTHS && synths[i] != NULL; i++) |
427 | /* synth_remove() is responsible for rotating the array down */ | 427 | /* synth_remove() is responsible for rotating the array down */ |
428 | if (in_synth == synths[i]) { | 428 | if (in_synth == synths[i]) { |
429 | mutex_unlock(&spk_mutex); | 429 | mutex_unlock(&spk_mutex); |
diff --git a/drivers/staging/tidspbridge/core/_tiomap.h b/drivers/staging/tidspbridge/core/_tiomap.h index 543a127c7d4d..b783bfa59b1c 100644 --- a/drivers/staging/tidspbridge/core/_tiomap.h +++ b/drivers/staging/tidspbridge/core/_tiomap.h | |||
@@ -31,7 +31,7 @@ | |||
31 | * driver should read or write to PRM/CM registers directly; they | 31 | * driver should read or write to PRM/CM registers directly; they |
32 | * should rely on OMAP core code to do this. | 32 | * should rely on OMAP core code to do this. |
33 | */ | 33 | */ |
34 | #include <mach-omap2/cm2xxx_3xxx.h> | 34 | #include <mach-omap2/cm3xxx.h> |
35 | #include <mach-omap2/prm-regbits-34xx.h> | 35 | #include <mach-omap2/prm-regbits-34xx.h> |
36 | #include <mach-omap2/cm-regbits-34xx.h> | 36 | #include <mach-omap2/cm-regbits-34xx.h> |
37 | #include <dspbridge/devdefs.h> | 37 | #include <dspbridge/devdefs.h> |
diff --git a/drivers/staging/tidspbridge/core/dsp-clock.c b/drivers/staging/tidspbridge/core/dsp-clock.c index b647207928b1..2f084e181d39 100644 --- a/drivers/staging/tidspbridge/core/dsp-clock.c +++ b/drivers/staging/tidspbridge/core/dsp-clock.c | |||
@@ -121,9 +121,13 @@ void dsp_clk_exit(void) | |||
121 | for (i = 0; i < DM_TIMER_CLOCKS; i++) | 121 | for (i = 0; i < DM_TIMER_CLOCKS; i++) |
122 | omap_dm_timer_free(timer[i]); | 122 | omap_dm_timer_free(timer[i]); |
123 | 123 | ||
124 | clk_unprepare(iva2_clk); | ||
124 | clk_put(iva2_clk); | 125 | clk_put(iva2_clk); |
126 | clk_unprepare(ssi.sst_fck); | ||
125 | clk_put(ssi.sst_fck); | 127 | clk_put(ssi.sst_fck); |
128 | clk_unprepare(ssi.ssr_fck); | ||
126 | clk_put(ssi.ssr_fck); | 129 | clk_put(ssi.ssr_fck); |
130 | clk_unprepare(ssi.ick); | ||
127 | clk_put(ssi.ick); | 131 | clk_put(ssi.ick); |
128 | } | 132 | } |
129 | 133 | ||
@@ -145,14 +149,21 @@ void dsp_clk_init(void) | |||
145 | iva2_clk = clk_get(&dspbridge_device.dev, "iva2_ck"); | 149 | iva2_clk = clk_get(&dspbridge_device.dev, "iva2_ck"); |
146 | if (IS_ERR(iva2_clk)) | 150 | if (IS_ERR(iva2_clk)) |
147 | dev_err(bridge, "failed to get iva2 clock %p\n", iva2_clk); | 151 | dev_err(bridge, "failed to get iva2 clock %p\n", iva2_clk); |
152 | else | ||
153 | clk_prepare(iva2_clk); | ||
148 | 154 | ||
149 | ssi.sst_fck = clk_get(&dspbridge_device.dev, "ssi_sst_fck"); | 155 | ssi.sst_fck = clk_get(&dspbridge_device.dev, "ssi_sst_fck"); |
150 | ssi.ssr_fck = clk_get(&dspbridge_device.dev, "ssi_ssr_fck"); | 156 | ssi.ssr_fck = clk_get(&dspbridge_device.dev, "ssi_ssr_fck"); |
151 | ssi.ick = clk_get(&dspbridge_device.dev, "ssi_ick"); | 157 | ssi.ick = clk_get(&dspbridge_device.dev, "ssi_ick"); |
152 | 158 | ||
153 | if (IS_ERR(ssi.sst_fck) || IS_ERR(ssi.ssr_fck) || IS_ERR(ssi.ick)) | 159 | if (IS_ERR(ssi.sst_fck) || IS_ERR(ssi.ssr_fck) || IS_ERR(ssi.ick)) { |
154 | dev_err(bridge, "failed to get ssi: sst %p, ssr %p, ick %p\n", | 160 | dev_err(bridge, "failed to get ssi: sst %p, ssr %p, ick %p\n", |
155 | ssi.sst_fck, ssi.ssr_fck, ssi.ick); | 161 | ssi.sst_fck, ssi.ssr_fck, ssi.ick); |
162 | } else { | ||
163 | clk_prepare(ssi.sst_fck); | ||
164 | clk_prepare(ssi.ssr_fck); | ||
165 | clk_prepare(ssi.ick); | ||
166 | } | ||
156 | } | 167 | } |
157 | 168 | ||
158 | /** | 169 | /** |
diff --git a/drivers/staging/tidspbridge/core/wdt.c b/drivers/staging/tidspbridge/core/wdt.c index 1dce36fb828f..7ff0e6c98039 100644 --- a/drivers/staging/tidspbridge/core/wdt.c +++ b/drivers/staging/tidspbridge/core/wdt.c | |||
@@ -63,11 +63,15 @@ int dsp_wdt_init(void) | |||
63 | dsp_wdt.fclk = clk_get(NULL, "wdt3_fck"); | 63 | dsp_wdt.fclk = clk_get(NULL, "wdt3_fck"); |
64 | 64 | ||
65 | if (!IS_ERR(dsp_wdt.fclk)) { | 65 | if (!IS_ERR(dsp_wdt.fclk)) { |
66 | clk_prepare(dsp_wdt.fclk); | ||
67 | |||
66 | dsp_wdt.iclk = clk_get(NULL, "wdt3_ick"); | 68 | dsp_wdt.iclk = clk_get(NULL, "wdt3_ick"); |
67 | if (IS_ERR(dsp_wdt.iclk)) { | 69 | if (IS_ERR(dsp_wdt.iclk)) { |
68 | clk_put(dsp_wdt.fclk); | 70 | clk_put(dsp_wdt.fclk); |
69 | dsp_wdt.fclk = NULL; | 71 | dsp_wdt.fclk = NULL; |
70 | ret = -EFAULT; | 72 | ret = -EFAULT; |
73 | } else { | ||
74 | clk_prepare(dsp_wdt.iclk); | ||
71 | } | 75 | } |
72 | } else | 76 | } else |
73 | ret = -EFAULT; | 77 | ret = -EFAULT; |
@@ -95,10 +99,14 @@ void dsp_wdt_exit(void) | |||
95 | free_irq(INT_34XX_WDT3_IRQ, &dsp_wdt); | 99 | free_irq(INT_34XX_WDT3_IRQ, &dsp_wdt); |
96 | tasklet_kill(&dsp_wdt.wdt3_tasklet); | 100 | tasklet_kill(&dsp_wdt.wdt3_tasklet); |
97 | 101 | ||
98 | if (dsp_wdt.fclk) | 102 | if (dsp_wdt.fclk) { |
103 | clk_unprepare(dsp_wdt.fclk); | ||
99 | clk_put(dsp_wdt.fclk); | 104 | clk_put(dsp_wdt.fclk); |
100 | if (dsp_wdt.iclk) | 105 | } |
106 | if (dsp_wdt.iclk) { | ||
107 | clk_unprepare(dsp_wdt.iclk); | ||
101 | clk_put(dsp_wdt.iclk); | 108 | clk_put(dsp_wdt.iclk); |
109 | } | ||
102 | 110 | ||
103 | dsp_wdt.fclk = NULL; | 111 | dsp_wdt.fclk = NULL; |
104 | dsp_wdt.iclk = NULL; | 112 | dsp_wdt.iclk = NULL; |
diff --git a/drivers/staging/vme/devices/vme_pio2_core.c b/drivers/staging/vme/devices/vme_pio2_core.c index 0331178ca3b3..bf73ba26e88a 100644 --- a/drivers/staging/vme/devices/vme_pio2_core.c +++ b/drivers/staging/vme/devices/vme_pio2_core.c | |||
@@ -162,11 +162,9 @@ static struct vme_driver pio2_driver = { | |||
162 | 162 | ||
163 | static int __init pio2_init(void) | 163 | static int __init pio2_init(void) |
164 | { | 164 | { |
165 | int retval = 0; | ||
166 | |||
167 | if (bus_num == 0) { | 165 | if (bus_num == 0) { |
168 | pr_err("No cards, skipping registration\n"); | 166 | pr_err("No cards, skipping registration\n"); |
169 | goto err_nocard; | 167 | return -ENODEV; |
170 | } | 168 | } |
171 | 169 | ||
172 | if (bus_num > PIO2_CARDS_MAX) { | 170 | if (bus_num > PIO2_CARDS_MAX) { |
@@ -176,15 +174,7 @@ static int __init pio2_init(void) | |||
176 | } | 174 | } |
177 | 175 | ||
178 | /* Register the PIO2 driver */ | 176 | /* Register the PIO2 driver */ |
179 | retval = vme_register_driver(&pio2_driver, bus_num); | 177 | return vme_register_driver(&pio2_driver, bus_num); |
180 | if (retval != 0) | ||
181 | goto err_reg; | ||
182 | |||
183 | return retval; | ||
184 | |||
185 | err_reg: | ||
186 | err_nocard: | ||
187 | return retval; | ||
188 | } | 178 | } |
189 | 179 | ||
190 | static int pio2_match(struct vme_dev *vdev) | 180 | static int pio2_match(struct vme_dev *vdev) |
diff --git a/drivers/staging/vt6656/bssdb.h b/drivers/staging/vt6656/bssdb.h index 6b2ec390e775..806cbf72fb59 100644 --- a/drivers/staging/vt6656/bssdb.h +++ b/drivers/staging/vt6656/bssdb.h | |||
@@ -90,7 +90,6 @@ typedef struct tagSRSNCapObject { | |||
90 | } SRSNCapObject, *PSRSNCapObject; | 90 | } SRSNCapObject, *PSRSNCapObject; |
91 | 91 | ||
92 | // BSS info(AP) | 92 | // BSS info(AP) |
93 | #pragma pack(1) | ||
94 | typedef struct tagKnownBSS { | 93 | typedef struct tagKnownBSS { |
95 | // BSS info | 94 | // BSS info |
96 | BOOL bActive; | 95 | BOOL bActive; |
diff --git a/drivers/staging/vt6656/int.h b/drivers/staging/vt6656/int.h index 5d8faf9f96ec..e0d2b07ba608 100644 --- a/drivers/staging/vt6656/int.h +++ b/drivers/staging/vt6656/int.h | |||
@@ -34,7 +34,6 @@ | |||
34 | #include "device.h" | 34 | #include "device.h" |
35 | 35 | ||
36 | /*--------------------- Export Definitions -------------------------*/ | 36 | /*--------------------- Export Definitions -------------------------*/ |
37 | #pragma pack(1) | ||
38 | typedef struct tagSINTData { | 37 | typedef struct tagSINTData { |
39 | BYTE byTSR0; | 38 | BYTE byTSR0; |
40 | BYTE byPkt0; | 39 | BYTE byPkt0; |
diff --git a/drivers/staging/vt6656/iocmd.h b/drivers/staging/vt6656/iocmd.h index 22710cef751d..ae6e2d237b20 100644 --- a/drivers/staging/vt6656/iocmd.h +++ b/drivers/staging/vt6656/iocmd.h | |||
@@ -95,13 +95,12 @@ typedef enum tagWZONETYPE { | |||
95 | // Ioctl interface structure | 95 | // Ioctl interface structure |
96 | // Command structure | 96 | // Command structure |
97 | // | 97 | // |
98 | #pragma pack(1) | ||
99 | typedef struct tagSCmdRequest { | 98 | typedef struct tagSCmdRequest { |
100 | u8 name[16]; | 99 | u8 name[16]; |
101 | void *data; | 100 | void *data; |
102 | u16 wResult; | 101 | u16 wResult; |
103 | u16 wCmdCode; | 102 | u16 wCmdCode; |
104 | } SCmdRequest, *PSCmdRequest; | 103 | } __packed SCmdRequest, *PSCmdRequest; |
105 | 104 | ||
106 | // | 105 | // |
107 | // Scan | 106 | // Scan |
@@ -111,7 +110,7 @@ typedef struct tagSCmdScan { | |||
111 | 110 | ||
112 | u8 ssid[SSID_MAXLEN + 2]; | 111 | u8 ssid[SSID_MAXLEN + 2]; |
113 | 112 | ||
114 | } SCmdScan, *PSCmdScan; | 113 | } __packed SCmdScan, *PSCmdScan; |
115 | 114 | ||
116 | // | 115 | // |
117 | // BSS Join | 116 | // BSS Join |
@@ -126,7 +125,7 @@ typedef struct tagSCmdBSSJoin { | |||
126 | BOOL bPSEnable; | 125 | BOOL bPSEnable; |
127 | BOOL bShareKeyAuth; | 126 | BOOL bShareKeyAuth; |
128 | 127 | ||
129 | } SCmdBSSJoin, *PSCmdBSSJoin; | 128 | } __packed SCmdBSSJoin, *PSCmdBSSJoin; |
130 | 129 | ||
131 | // | 130 | // |
132 | // Zonetype Setting | 131 | // Zonetype Setting |
@@ -137,7 +136,7 @@ typedef struct tagSCmdZoneTypeSet { | |||
137 | BOOL bWrite; | 136 | BOOL bWrite; |
138 | WZONETYPE ZoneType; | 137 | WZONETYPE ZoneType; |
139 | 138 | ||
140 | } SCmdZoneTypeSet, *PSCmdZoneTypeSet; | 139 | } __packed SCmdZoneTypeSet, *PSCmdZoneTypeSet; |
141 | 140 | ||
142 | typedef struct tagSWPAResult { | 141 | typedef struct tagSWPAResult { |
143 | char ifname[100]; | 142 | char ifname[100]; |
@@ -145,7 +144,7 @@ typedef struct tagSWPAResult { | |||
145 | u8 key_mgmt; | 144 | u8 key_mgmt; |
146 | u8 eap_type; | 145 | u8 eap_type; |
147 | BOOL authenticated; | 146 | BOOL authenticated; |
148 | } SWPAResult, *PSWPAResult; | 147 | } __packed SWPAResult, *PSWPAResult; |
149 | 148 | ||
150 | typedef struct tagSCmdStartAP { | 149 | typedef struct tagSCmdStartAP { |
151 | 150 | ||
@@ -157,7 +156,7 @@ typedef struct tagSCmdStartAP { | |||
157 | BOOL bShareKeyAuth; | 156 | BOOL bShareKeyAuth; |
158 | u8 byBasicRate; | 157 | u8 byBasicRate; |
159 | 158 | ||
160 | } SCmdStartAP, *PSCmdStartAP; | 159 | } __packed SCmdStartAP, *PSCmdStartAP; |
161 | 160 | ||
162 | typedef struct tagSCmdSetWEP { | 161 | typedef struct tagSCmdSetWEP { |
163 | 162 | ||
@@ -167,7 +166,7 @@ typedef struct tagSCmdSetWEP { | |||
167 | BOOL bWepKeyAvailable[WEP_NKEYS]; | 166 | BOOL bWepKeyAvailable[WEP_NKEYS]; |
168 | u32 auWepKeyLength[WEP_NKEYS]; | 167 | u32 auWepKeyLength[WEP_NKEYS]; |
169 | 168 | ||
170 | } SCmdSetWEP, *PSCmdSetWEP; | 169 | } __packed SCmdSetWEP, *PSCmdSetWEP; |
171 | 170 | ||
172 | typedef struct tagSBSSIDItem { | 171 | typedef struct tagSBSSIDItem { |
173 | 172 | ||
@@ -180,14 +179,14 @@ typedef struct tagSBSSIDItem { | |||
180 | BOOL bWEPOn; | 179 | BOOL bWEPOn; |
181 | u32 uRSSI; | 180 | u32 uRSSI; |
182 | 181 | ||
183 | } SBSSIDItem; | 182 | } __packed SBSSIDItem; |
184 | 183 | ||
185 | 184 | ||
186 | typedef struct tagSBSSIDList { | 185 | typedef struct tagSBSSIDList { |
187 | 186 | ||
188 | u32 uItem; | 187 | u32 uItem; |
189 | SBSSIDItem sBSSIDList[0]; | 188 | SBSSIDItem sBSSIDList[0]; |
190 | } SBSSIDList, *PSBSSIDList; | 189 | } __packed SBSSIDList, *PSBSSIDList; |
191 | 190 | ||
192 | 191 | ||
193 | typedef struct tagSNodeItem { | 192 | typedef struct tagSNodeItem { |
@@ -208,7 +207,7 @@ typedef struct tagSNodeItem { | |||
208 | u32 uTxAttempts; | 207 | u32 uTxAttempts; |
209 | u16 wFailureRatio; | 208 | u16 wFailureRatio; |
210 | 209 | ||
211 | } SNodeItem; | 210 | } __packed SNodeItem; |
212 | 211 | ||
213 | 212 | ||
214 | typedef struct tagSNodeList { | 213 | typedef struct tagSNodeList { |
@@ -216,7 +215,7 @@ typedef struct tagSNodeList { | |||
216 | u32 uItem; | 215 | u32 uItem; |
217 | SNodeItem sNodeList[0]; | 216 | SNodeItem sNodeList[0]; |
218 | 217 | ||
219 | } SNodeList, *PSNodeList; | 218 | } __packed SNodeList, *PSNodeList; |
220 | 219 | ||
221 | 220 | ||
222 | typedef struct tagSCmdLinkStatus { | 221 | typedef struct tagSCmdLinkStatus { |
@@ -229,7 +228,7 @@ typedef struct tagSCmdLinkStatus { | |||
229 | u32 uChannel; | 228 | u32 uChannel; |
230 | u32 uLinkRate; | 229 | u32 uLinkRate; |
231 | 230 | ||
232 | } SCmdLinkStatus, *PSCmdLinkStatus; | 231 | } __packed SCmdLinkStatus, *PSCmdLinkStatus; |
233 | 232 | ||
234 | // | 233 | // |
235 | // 802.11 counter | 234 | // 802.11 counter |
@@ -247,7 +246,7 @@ typedef struct tagSDot11MIBCount { | |||
247 | u32 ReceivedFragmentCount; | 246 | u32 ReceivedFragmentCount; |
248 | u32 MulticastReceivedFrameCount; | 247 | u32 MulticastReceivedFrameCount; |
249 | u32 FCSErrorCount; | 248 | u32 FCSErrorCount; |
250 | } SDot11MIBCount, *PSDot11MIBCount; | 249 | } __packed SDot11MIBCount, *PSDot11MIBCount; |
251 | 250 | ||
252 | 251 | ||
253 | 252 | ||
@@ -355,13 +354,13 @@ typedef struct tagSStatMIBCount { | |||
355 | u32 ullTxBroadcastBytes[2]; | 354 | u32 ullTxBroadcastBytes[2]; |
356 | u32 ullTxMulticastBytes[2]; | 355 | u32 ullTxMulticastBytes[2]; |
357 | u32 ullTxDirectedBytes[2]; | 356 | u32 ullTxDirectedBytes[2]; |
358 | } SStatMIBCount, *PSStatMIBCount; | 357 | } __packed SStatMIBCount, *PSStatMIBCount; |
359 | 358 | ||
360 | typedef struct tagSCmdValue { | 359 | typedef struct tagSCmdValue { |
361 | 360 | ||
362 | u32 dwValue; | 361 | u32 dwValue; |
363 | 362 | ||
364 | } SCmdValue, *PSCmdValue; | 363 | } __packed SCmdValue, *PSCmdValue; |
365 | 364 | ||
366 | // | 365 | // |
367 | // hostapd & viawget ioctl related | 366 | // hostapd & viawget ioctl related |
@@ -431,7 +430,7 @@ struct viawget_hostapd_param { | |||
431 | u8 ssid[32]; | 430 | u8 ssid[32]; |
432 | } scan_req; | 431 | } scan_req; |
433 | } u; | 432 | } u; |
434 | }; | 433 | } __packed; |
435 | 434 | ||
436 | /*--------------------- Export Classes ----------------------------*/ | 435 | /*--------------------- Export Classes ----------------------------*/ |
437 | 436 | ||
diff --git a/drivers/staging/vt6656/iowpa.h b/drivers/staging/vt6656/iowpa.h index 959c8868f6e2..2522ddec718d 100644 --- a/drivers/staging/vt6656/iowpa.h +++ b/drivers/staging/vt6656/iowpa.h | |||
@@ -67,12 +67,11 @@ enum { | |||
67 | 67 | ||
68 | 68 | ||
69 | 69 | ||
70 | #pragma pack(1) | ||
71 | typedef struct viawget_wpa_header { | 70 | typedef struct viawget_wpa_header { |
72 | u8 type; | 71 | u8 type; |
73 | u16 req_ie_len; | 72 | u16 req_ie_len; |
74 | u16 resp_ie_len; | 73 | u16 resp_ie_len; |
75 | } viawget_wpa_header; | 74 | } __packed viawget_wpa_header; |
76 | 75 | ||
77 | struct viawget_wpa_param { | 76 | struct viawget_wpa_param { |
78 | u32 cmd; | 77 | u32 cmd; |
@@ -113,9 +112,8 @@ struct viawget_wpa_param { | |||
113 | u8 *buf; | 112 | u8 *buf; |
114 | } scan_results; | 113 | } scan_results; |
115 | } u; | 114 | } u; |
116 | }; | 115 | } __packed; |
117 | 116 | ||
118 | #pragma pack(1) | ||
119 | struct viawget_scan_result { | 117 | struct viawget_scan_result { |
120 | u8 bssid[6]; | 118 | u8 bssid[6]; |
121 | u8 ssid[32]; | 119 | u8 ssid[32]; |
@@ -130,7 +128,7 @@ struct viawget_scan_result { | |||
130 | int noise; | 128 | int noise; |
131 | int level; | 129 | int level; |
132 | int maxrate; | 130 | int maxrate; |
133 | }; | 131 | } __packed; |
134 | 132 | ||
135 | /*--------------------- Export Classes ----------------------------*/ | 133 | /*--------------------- Export Classes ----------------------------*/ |
136 | 134 | ||
diff --git a/drivers/staging/wlan-ng/cfg80211.c b/drivers/staging/wlan-ng/cfg80211.c index 18c06a59c091..1d31eab19d16 100644 --- a/drivers/staging/wlan-ng/cfg80211.c +++ b/drivers/staging/wlan-ng/cfg80211.c | |||
@@ -638,8 +638,8 @@ int prism2_leave_ibss(struct wiphy *wiphy, struct net_device *dev) | |||
638 | } | 638 | } |
639 | 639 | ||
640 | 640 | ||
641 | int prism2_set_tx_power(struct wiphy *wiphy, enum nl80211_tx_power_setting type, | 641 | int prism2_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, |
642 | int mbm) | 642 | enum nl80211_tx_power_setting type, int mbm) |
643 | { | 643 | { |
644 | struct prism2_wiphy_private *priv = wiphy_priv(wiphy); | 644 | struct prism2_wiphy_private *priv = wiphy_priv(wiphy); |
645 | wlandevice_t *wlandev = priv->wlandev; | 645 | wlandevice_t *wlandev = priv->wlandev; |
@@ -665,7 +665,8 @@ exit: | |||
665 | return err; | 665 | return err; |
666 | } | 666 | } |
667 | 667 | ||
668 | int prism2_get_tx_power(struct wiphy *wiphy, int *dbm) | 668 | int prism2_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, |
669 | int *dbm) | ||
669 | { | 670 | { |
670 | struct prism2_wiphy_private *priv = wiphy_priv(wiphy); | 671 | struct prism2_wiphy_private *priv = wiphy_priv(wiphy); |
671 | wlandevice_t *wlandev = priv->wlandev; | 672 | wlandevice_t *wlandev = priv->wlandev; |
diff --git a/drivers/staging/wlan-ng/prism2mgmt.c b/drivers/staging/wlan-ng/prism2mgmt.c index 4efa9bc0fcf0..89bfd858bb28 100644 --- a/drivers/staging/wlan-ng/prism2mgmt.c +++ b/drivers/staging/wlan-ng/prism2mgmt.c | |||
@@ -406,7 +406,7 @@ int prism2mgmt_scan_results(wlandevice_t *wlandev, void *msgp) | |||
406 | /* SSID */ | 406 | /* SSID */ |
407 | req->ssid.status = P80211ENUM_msgitem_status_data_ok; | 407 | req->ssid.status = P80211ENUM_msgitem_status_data_ok; |
408 | req->ssid.data.len = le16_to_cpu(item->ssid.len); | 408 | req->ssid.data.len = le16_to_cpu(item->ssid.len); |
409 | req->ssid.data.len = min_t(u16, req->ssid.data.len, WLAN_BSSID_LEN); | 409 | req->ssid.data.len = min_t(u16, req->ssid.data.len, WLAN_SSID_MAXLEN); |
410 | memcpy(req->ssid.data.data, item->ssid.data, req->ssid.data.len); | 410 | memcpy(req->ssid.data.data, item->ssid.data, req->ssid.data.len); |
411 | 411 | ||
412 | /* supported rates */ | 412 | /* supported rates */ |
diff --git a/drivers/staging/zram/zram_drv.c b/drivers/staging/zram/zram_drv.c index fb4a7c94aed3..f2a73bd739fb 100644 --- a/drivers/staging/zram/zram_drv.c +++ b/drivers/staging/zram/zram_drv.c | |||
@@ -265,7 +265,7 @@ out_cleanup: | |||
265 | static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, | 265 | static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, |
266 | int offset) | 266 | int offset) |
267 | { | 267 | { |
268 | int ret; | 268 | int ret = 0; |
269 | size_t clen; | 269 | size_t clen; |
270 | unsigned long handle; | 270 | unsigned long handle; |
271 | struct page *page; | 271 | struct page *page; |
@@ -286,10 +286,8 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, | |||
286 | goto out; | 286 | goto out; |
287 | } | 287 | } |
288 | ret = zram_decompress_page(zram, uncmem, index); | 288 | ret = zram_decompress_page(zram, uncmem, index); |
289 | if (ret) { | 289 | if (ret) |
290 | kfree(uncmem); | ||
291 | goto out; | 290 | goto out; |
292 | } | ||
293 | } | 291 | } |
294 | 292 | ||
295 | /* | 293 | /* |
@@ -302,16 +300,18 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, | |||
302 | 300 | ||
303 | user_mem = kmap_atomic(page); | 301 | user_mem = kmap_atomic(page); |
304 | 302 | ||
305 | if (is_partial_io(bvec)) | 303 | if (is_partial_io(bvec)) { |
306 | memcpy(uncmem + offset, user_mem + bvec->bv_offset, | 304 | memcpy(uncmem + offset, user_mem + bvec->bv_offset, |
307 | bvec->bv_len); | 305 | bvec->bv_len); |
308 | else | 306 | kunmap_atomic(user_mem); |
307 | user_mem = NULL; | ||
308 | } else { | ||
309 | uncmem = user_mem; | 309 | uncmem = user_mem; |
310 | } | ||
310 | 311 | ||
311 | if (page_zero_filled(uncmem)) { | 312 | if (page_zero_filled(uncmem)) { |
312 | kunmap_atomic(user_mem); | 313 | if (!is_partial_io(bvec)) |
313 | if (is_partial_io(bvec)) | 314 | kunmap_atomic(user_mem); |
314 | kfree(uncmem); | ||
315 | zram_stat_inc(&zram->stats.pages_zero); | 315 | zram_stat_inc(&zram->stats.pages_zero); |
316 | zram_set_flag(zram, index, ZRAM_ZERO); | 316 | zram_set_flag(zram, index, ZRAM_ZERO); |
317 | ret = 0; | 317 | ret = 0; |
@@ -321,9 +321,11 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, | |||
321 | ret = lzo1x_1_compress(uncmem, PAGE_SIZE, src, &clen, | 321 | ret = lzo1x_1_compress(uncmem, PAGE_SIZE, src, &clen, |
322 | zram->compress_workmem); | 322 | zram->compress_workmem); |
323 | 323 | ||
324 | kunmap_atomic(user_mem); | 324 | if (!is_partial_io(bvec)) { |
325 | if (is_partial_io(bvec)) | 325 | kunmap_atomic(user_mem); |
326 | kfree(uncmem); | 326 | user_mem = NULL; |
327 | uncmem = NULL; | ||
328 | } | ||
327 | 329 | ||
328 | if (unlikely(ret != LZO_E_OK)) { | 330 | if (unlikely(ret != LZO_E_OK)) { |
329 | pr_err("Compression failed! err=%d\n", ret); | 331 | pr_err("Compression failed! err=%d\n", ret); |
@@ -332,8 +334,10 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, | |||
332 | 334 | ||
333 | if (unlikely(clen > max_zpage_size)) { | 335 | if (unlikely(clen > max_zpage_size)) { |
334 | zram_stat_inc(&zram->stats.bad_compress); | 336 | zram_stat_inc(&zram->stats.bad_compress); |
335 | src = uncmem; | ||
336 | clen = PAGE_SIZE; | 337 | clen = PAGE_SIZE; |
338 | src = NULL; | ||
339 | if (is_partial_io(bvec)) | ||
340 | src = uncmem; | ||
337 | } | 341 | } |
338 | 342 | ||
339 | handle = zs_malloc(zram->mem_pool, clen); | 343 | handle = zs_malloc(zram->mem_pool, clen); |
@@ -345,7 +349,11 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, | |||
345 | } | 349 | } |
346 | cmem = zs_map_object(zram->mem_pool, handle, ZS_MM_WO); | 350 | cmem = zs_map_object(zram->mem_pool, handle, ZS_MM_WO); |
347 | 351 | ||
352 | if ((clen == PAGE_SIZE) && !is_partial_io(bvec)) | ||
353 | src = kmap_atomic(page); | ||
348 | memcpy(cmem, src, clen); | 354 | memcpy(cmem, src, clen); |
355 | if ((clen == PAGE_SIZE) && !is_partial_io(bvec)) | ||
356 | kunmap_atomic(src); | ||
349 | 357 | ||
350 | zs_unmap_object(zram->mem_pool, handle); | 358 | zs_unmap_object(zram->mem_pool, handle); |
351 | 359 | ||
@@ -358,9 +366,10 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, | |||
358 | if (clen <= PAGE_SIZE / 2) | 366 | if (clen <= PAGE_SIZE / 2) |
359 | zram_stat_inc(&zram->stats.good_compress); | 367 | zram_stat_inc(&zram->stats.good_compress); |
360 | 368 | ||
361 | return 0; | ||
362 | |||
363 | out: | 369 | out: |
370 | if (is_partial_io(bvec)) | ||
371 | kfree(uncmem); | ||
372 | |||
364 | if (ret) | 373 | if (ret) |
365 | zram_stat64_inc(zram, &zram->stats.failed_writes); | 374 | zram_stat64_inc(zram, &zram->stats.failed_writes); |
366 | return ret; | 375 | return ret; |
diff --git a/drivers/target/iscsi/iscsi_target_erl2.c b/drivers/target/iscsi/iscsi_target_erl2.c index 9ac4c151eae4..ba6091bf93fc 100644 --- a/drivers/target/iscsi/iscsi_target_erl2.c +++ b/drivers/target/iscsi/iscsi_target_erl2.c | |||
@@ -372,7 +372,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn) | |||
372 | * made generic here. | 372 | * made generic here. |
373 | */ | 373 | */ |
374 | if (!(cmd->cmd_flags & ICF_OOO_CMDSN) && !cmd->immediate_cmd && | 374 | if (!(cmd->cmd_flags & ICF_OOO_CMDSN) && !cmd->immediate_cmd && |
375 | iscsi_sna_gte(cmd->stat_sn, conn->sess->exp_cmd_sn)) { | 375 | iscsi_sna_gte(cmd->cmd_sn, conn->sess->exp_cmd_sn)) { |
376 | list_del(&cmd->i_conn_node); | 376 | list_del(&cmd->i_conn_node); |
377 | spin_unlock_bh(&conn->cmd_lock); | 377 | spin_unlock_bh(&conn->cmd_lock); |
378 | iscsit_free_cmd(cmd); | 378 | iscsit_free_cmd(cmd); |
diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 85140f7dde1e..7d4ec02e29a9 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c | |||
@@ -212,7 +212,7 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd) | |||
212 | struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, *l_tg_pt_gp_mem; | 212 | struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, *l_tg_pt_gp_mem; |
213 | unsigned char *buf; | 213 | unsigned char *buf; |
214 | unsigned char *ptr; | 214 | unsigned char *ptr; |
215 | sense_reason_t rc; | 215 | sense_reason_t rc = TCM_NO_SENSE; |
216 | u32 len = 4; /* Skip over RESERVED area in header */ | 216 | u32 len = 4; /* Skip over RESERVED area in header */ |
217 | int alua_access_state, primary = 0; | 217 | int alua_access_state, primary = 0; |
218 | u16 tg_pt_id, rtpi; | 218 | u16 tg_pt_id, rtpi; |
diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index e35dbf85841f..8e0290b38e43 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c | |||
@@ -2053,7 +2053,7 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key, | |||
2053 | /* Used for APTPL metadata w/ UNREGISTER */ | 2053 | /* Used for APTPL metadata w/ UNREGISTER */ |
2054 | unsigned char *pr_aptpl_buf = NULL; | 2054 | unsigned char *pr_aptpl_buf = NULL; |
2055 | unsigned char isid_buf[PR_REG_ISID_LEN], *isid_ptr = NULL; | 2055 | unsigned char isid_buf[PR_REG_ISID_LEN], *isid_ptr = NULL; |
2056 | sense_reason_t ret; | 2056 | sense_reason_t ret = TCM_NO_SENSE; |
2057 | int pr_holder = 0, type; | 2057 | int pr_holder = 0, type; |
2058 | 2058 | ||
2059 | if (!se_sess || !se_lun) { | 2059 | if (!se_sess || !se_lun) { |
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index c23c76ccef65..bd587b70661a 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c | |||
@@ -541,9 +541,6 @@ static void transport_lun_remove_cmd(struct se_cmd *cmd) | |||
541 | 541 | ||
542 | void transport_cmd_finish_abort(struct se_cmd *cmd, int remove) | 542 | void transport_cmd_finish_abort(struct se_cmd *cmd, int remove) |
543 | { | 543 | { |
544 | if (!(cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)) | ||
545 | transport_lun_remove_cmd(cmd); | ||
546 | |||
547 | if (transport_cmd_check_stop_to_fabric(cmd)) | 544 | if (transport_cmd_check_stop_to_fabric(cmd)) |
548 | return; | 545 | return; |
549 | if (remove) | 546 | if (remove) |
@@ -1396,6 +1393,8 @@ static void target_complete_tmr_failure(struct work_struct *work) | |||
1396 | 1393 | ||
1397 | se_cmd->se_tmr_req->response = TMR_LUN_DOES_NOT_EXIST; | 1394 | se_cmd->se_tmr_req->response = TMR_LUN_DOES_NOT_EXIST; |
1398 | se_cmd->se_tfo->queue_tm_rsp(se_cmd); | 1395 | se_cmd->se_tfo->queue_tm_rsp(se_cmd); |
1396 | |||
1397 | transport_cmd_check_stop_to_fabric(se_cmd); | ||
1399 | } | 1398 | } |
1400 | 1399 | ||
1401 | /** | 1400 | /** |
@@ -1688,6 +1687,7 @@ void target_execute_cmd(struct se_cmd *cmd) | |||
1688 | } | 1687 | } |
1689 | 1688 | ||
1690 | cmd->t_state = TRANSPORT_PROCESSING; | 1689 | cmd->t_state = TRANSPORT_PROCESSING; |
1690 | cmd->transport_state |= CMD_T_ACTIVE; | ||
1691 | spin_unlock_irq(&cmd->t_state_lock); | 1691 | spin_unlock_irq(&cmd->t_state_lock); |
1692 | 1692 | ||
1693 | if (!target_handle_task_attr(cmd)) | 1693 | if (!target_handle_task_attr(cmd)) |
@@ -2597,6 +2597,16 @@ transport_send_check_condition_and_sense(struct se_cmd *cmd, | |||
2597 | * SENSE KEY values from include/scsi/scsi.h | 2597 | * SENSE KEY values from include/scsi/scsi.h |
2598 | */ | 2598 | */ |
2599 | switch (reason) { | 2599 | switch (reason) { |
2600 | case TCM_NO_SENSE: | ||
2601 | /* CURRENT ERROR */ | ||
2602 | buffer[0] = 0x70; | ||
2603 | buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; | ||
2604 | /* Not Ready */ | ||
2605 | buffer[SPC_SENSE_KEY_OFFSET] = NOT_READY; | ||
2606 | /* NO ADDITIONAL SENSE INFORMATION */ | ||
2607 | buffer[SPC_ASC_KEY_OFFSET] = 0; | ||
2608 | buffer[SPC_ASCQ_KEY_OFFSET] = 0; | ||
2609 | break; | ||
2600 | case TCM_NON_EXISTENT_LUN: | 2610 | case TCM_NON_EXISTENT_LUN: |
2601 | /* CURRENT ERROR */ | 2611 | /* CURRENT ERROR */ |
2602 | buffer[0] = 0x70; | 2612 | buffer[0] = 0x70; |
@@ -2743,7 +2753,7 @@ transport_send_check_condition_and_sense(struct se_cmd *cmd, | |||
2743 | /* ILLEGAL REQUEST */ | 2753 | /* ILLEGAL REQUEST */ |
2744 | buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; | 2754 | buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; |
2745 | /* LOGICAL UNIT COMMUNICATION FAILURE */ | 2755 | /* LOGICAL UNIT COMMUNICATION FAILURE */ |
2746 | buffer[SPC_ASC_KEY_OFFSET] = 0x80; | 2756 | buffer[SPC_ASC_KEY_OFFSET] = 0x08; |
2747 | break; | 2757 | break; |
2748 | } | 2758 | } |
2749 | /* | 2759 | /* |
@@ -2804,6 +2814,8 @@ void transport_send_task_abort(struct se_cmd *cmd) | |||
2804 | } | 2814 | } |
2805 | cmd->scsi_status = SAM_STAT_TASK_ABORTED; | 2815 | cmd->scsi_status = SAM_STAT_TASK_ABORTED; |
2806 | 2816 | ||
2817 | transport_lun_remove_cmd(cmd); | ||
2818 | |||
2807 | pr_debug("Setting SAM_STAT_TASK_ABORTED status for CDB: 0x%02x," | 2819 | pr_debug("Setting SAM_STAT_TASK_ABORTED status for CDB: 0x%02x," |
2808 | " ITT: 0x%08x\n", cmd->t_task_cdb[0], | 2820 | " ITT: 0x%08x\n", cmd->t_task_cdb[0], |
2809 | cmd->se_tfo->get_task_tag(cmd)); | 2821 | cmd->se_tfo->get_task_tag(cmd)); |
diff --git a/drivers/target/tcm_fc/tfc_sess.c b/drivers/target/tcm_fc/tfc_sess.c index 12d6fa21e5e1..6659dd36e806 100644 --- a/drivers/target/tcm_fc/tfc_sess.c +++ b/drivers/target/tcm_fc/tfc_sess.c | |||
@@ -355,11 +355,11 @@ static int ft_prli_locked(struct fc_rport_priv *rdata, u32 spp_len, | |||
355 | 355 | ||
356 | tport = ft_tport_create(rdata->local_port); | 356 | tport = ft_tport_create(rdata->local_port); |
357 | if (!tport) | 357 | if (!tport) |
358 | return 0; /* not a target for this local port */ | 358 | goto not_target; /* not a target for this local port */ |
359 | 359 | ||
360 | acl = ft_acl_get(tport->tpg, rdata); | 360 | acl = ft_acl_get(tport->tpg, rdata); |
361 | if (!acl) | 361 | if (!acl) |
362 | return 0; | 362 | goto not_target; /* no target for this remote */ |
363 | 363 | ||
364 | if (!rspp) | 364 | if (!rspp) |
365 | goto fill; | 365 | goto fill; |
@@ -396,12 +396,18 @@ static int ft_prli_locked(struct fc_rport_priv *rdata, u32 spp_len, | |||
396 | 396 | ||
397 | /* | 397 | /* |
398 | * OR in our service parameters with other provider (initiator), if any. | 398 | * OR in our service parameters with other provider (initiator), if any. |
399 | * TBD XXX - indicate RETRY capability? | ||
400 | */ | 399 | */ |
401 | fill: | 400 | fill: |
402 | fcp_parm = ntohl(spp->spp_params); | 401 | fcp_parm = ntohl(spp->spp_params); |
402 | fcp_parm &= ~FCP_SPPF_RETRY; | ||
403 | spp->spp_params = htonl(fcp_parm | FCP_SPPF_TARG_FCN); | 403 | spp->spp_params = htonl(fcp_parm | FCP_SPPF_TARG_FCN); |
404 | return FC_SPP_RESP_ACK; | 404 | return FC_SPP_RESP_ACK; |
405 | |||
406 | not_target: | ||
407 | fcp_parm = ntohl(spp->spp_params); | ||
408 | fcp_parm &= ~FCP_SPPF_TARG_FCN; | ||
409 | spp->spp_params = htonl(fcp_parm); | ||
410 | return 0; | ||
405 | } | 411 | } |
406 | 412 | ||
407 | /** | 413 | /** |
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index be6a373601b7..79ff3a5e925d 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c | |||
@@ -441,6 +441,8 @@ static int pty_bsd_ioctl(struct tty_struct *tty, | |||
441 | return pty_get_pktmode(tty, (int __user *)arg); | 441 | return pty_get_pktmode(tty, (int __user *)arg); |
442 | case TIOCSIG: /* Send signal to other side of pty */ | 442 | case TIOCSIG: /* Send signal to other side of pty */ |
443 | return pty_signal(tty, (int) arg); | 443 | return pty_signal(tty, (int) arg); |
444 | case TIOCGPTN: /* TTY returns ENOTTY, but glibc expects EINVAL here */ | ||
445 | return -EINVAL; | ||
444 | } | 446 | } |
445 | return -ENOIOCTLCMD; | 447 | return -ENOIOCTLCMD; |
446 | } | 448 | } |
diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c index d085e3a8ec06..f9320437a649 100644 --- a/drivers/tty/serial/8250/8250.c +++ b/drivers/tty/serial/8250/8250.c | |||
@@ -300,6 +300,12 @@ static const struct serial8250_config uart_config[] = { | |||
300 | UART_FCR_R_TRIG_00 | UART_FCR_T_TRIG_00, | 300 | UART_FCR_R_TRIG_00 | UART_FCR_T_TRIG_00, |
301 | .flags = UART_CAP_FIFO, | 301 | .flags = UART_CAP_FIFO, |
302 | }, | 302 | }, |
303 | [PORT_BRCM_TRUMANAGE] = { | ||
304 | .name = "TruManage", | ||
305 | .fifo_size = 1, | ||
306 | .tx_loadsz = 1024, | ||
307 | .flags = UART_CAP_HFIFO, | ||
308 | }, | ||
303 | [PORT_8250_CIR] = { | 309 | [PORT_8250_CIR] = { |
304 | .name = "CIR port" | 310 | .name = "CIR port" |
305 | } | 311 | } |
@@ -1490,6 +1496,11 @@ void serial8250_tx_chars(struct uart_8250_port *up) | |||
1490 | port->icount.tx++; | 1496 | port->icount.tx++; |
1491 | if (uart_circ_empty(xmit)) | 1497 | if (uart_circ_empty(xmit)) |
1492 | break; | 1498 | break; |
1499 | if (up->capabilities & UART_CAP_HFIFO) { | ||
1500 | if ((serial_port_in(port, UART_LSR) & BOTH_EMPTY) != | ||
1501 | BOTH_EMPTY) | ||
1502 | break; | ||
1503 | } | ||
1493 | } while (--count > 0); | 1504 | } while (--count > 0); |
1494 | 1505 | ||
1495 | if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) | 1506 | if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) |
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 3b4ea84898c2..12caa1292b75 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h | |||
@@ -40,6 +40,7 @@ struct serial8250_config { | |||
40 | #define UART_CAP_AFE (1 << 11) /* MCR-based hw flow control */ | 40 | #define UART_CAP_AFE (1 << 11) /* MCR-based hw flow control */ |
41 | #define UART_CAP_UUE (1 << 12) /* UART needs IER bit 6 set (Xscale) */ | 41 | #define UART_CAP_UUE (1 << 12) /* UART needs IER bit 6 set (Xscale) */ |
42 | #define UART_CAP_RTOIE (1 << 13) /* UART needs IER bit 4 set (Xscale, Tegra) */ | 42 | #define UART_CAP_RTOIE (1 << 13) /* UART needs IER bit 4 set (Xscale, Tegra) */ |
43 | #define UART_CAP_HFIFO (1 << 14) /* UART has a "hidden" FIFO */ | ||
43 | 44 | ||
44 | #define UART_BUG_QUOT (1 << 0) /* UART has buggy quot LSB */ | 45 | #define UART_BUG_QUOT (1 << 0) /* UART has buggy quot LSB */ |
45 | #define UART_BUG_TXEN (1 << 1) /* UART has buggy TX IIR status */ | 46 | #define UART_BUG_TXEN (1 << 1) /* UART has buggy TX IIR status */ |
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 1d0dba2d562d..096d2ef48b32 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c | |||
@@ -79,7 +79,7 @@ static int dw8250_handle_irq(struct uart_port *p) | |||
79 | } else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) { | 79 | } else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) { |
80 | /* Clear the USR and write the LCR again. */ | 80 | /* Clear the USR and write the LCR again. */ |
81 | (void)p->serial_in(p, UART_USR); | 81 | (void)p->serial_in(p, UART_USR); |
82 | p->serial_out(p, d->last_lcr, UART_LCR); | 82 | p->serial_out(p, UART_LCR, d->last_lcr); |
83 | 83 | ||
84 | return 1; | 84 | return 1; |
85 | } | 85 | } |
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 26b9dc012ed0..a27a98e1b066 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c | |||
@@ -1085,6 +1085,18 @@ pci_omegapci_setup(struct serial_private *priv, | |||
1085 | return setup_port(priv, port, 2, idx * 8, 0); | 1085 | return setup_port(priv, port, 2, idx * 8, 0); |
1086 | } | 1086 | } |
1087 | 1087 | ||
1088 | static int | ||
1089 | pci_brcm_trumanage_setup(struct serial_private *priv, | ||
1090 | const struct pciserial_board *board, | ||
1091 | struct uart_8250_port *port, int idx) | ||
1092 | { | ||
1093 | int ret = pci_default_setup(priv, board, port, idx); | ||
1094 | |||
1095 | port->port.type = PORT_BRCM_TRUMANAGE; | ||
1096 | port->port.flags = (port->port.flags | UPF_FIXED_PORT | UPF_FIXED_TYPE); | ||
1097 | return ret; | ||
1098 | } | ||
1099 | |||
1088 | static int skip_tx_en_setup(struct serial_private *priv, | 1100 | static int skip_tx_en_setup(struct serial_private *priv, |
1089 | const struct pciserial_board *board, | 1101 | const struct pciserial_board *board, |
1090 | struct uart_8250_port *port, int idx) | 1102 | struct uart_8250_port *port, int idx) |
@@ -1301,9 +1313,10 @@ pci_wch_ch353_setup(struct serial_private *priv, | |||
1301 | #define PCI_VENDOR_ID_AGESTAR 0x5372 | 1313 | #define PCI_VENDOR_ID_AGESTAR 0x5372 |
1302 | #define PCI_DEVICE_ID_AGESTAR_9375 0x6872 | 1314 | #define PCI_DEVICE_ID_AGESTAR_9375 0x6872 |
1303 | #define PCI_VENDOR_ID_ASIX 0x9710 | 1315 | #define PCI_VENDOR_ID_ASIX 0x9710 |
1304 | #define PCI_DEVICE_ID_COMMTECH_4222PCIE 0x0019 | ||
1305 | #define PCI_DEVICE_ID_COMMTECH_4224PCIE 0x0020 | 1316 | #define PCI_DEVICE_ID_COMMTECH_4224PCIE 0x0020 |
1306 | #define PCI_DEVICE_ID_COMMTECH_4228PCIE 0x0021 | 1317 | #define PCI_DEVICE_ID_COMMTECH_4228PCIE 0x0021 |
1318 | #define PCI_DEVICE_ID_COMMTECH_4222PCIE 0x0022 | ||
1319 | #define PCI_DEVICE_ID_BROADCOM_TRUMANAGE 0x160a | ||
1307 | 1320 | ||
1308 | 1321 | ||
1309 | /* Unknown vendors/cards - this should not be in linux/pci_ids.h */ | 1322 | /* Unknown vendors/cards - this should not be in linux/pci_ids.h */ |
@@ -1954,6 +1967,17 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { | |||
1954 | .setup = pci_xr17v35x_setup, | 1967 | .setup = pci_xr17v35x_setup, |
1955 | }, | 1968 | }, |
1956 | /* | 1969 | /* |
1970 | * Broadcom TruManage (NetXtreme) | ||
1971 | */ | ||
1972 | { | ||
1973 | .vendor = PCI_VENDOR_ID_BROADCOM, | ||
1974 | .device = PCI_DEVICE_ID_BROADCOM_TRUMANAGE, | ||
1975 | .subvendor = PCI_ANY_ID, | ||
1976 | .subdevice = PCI_ANY_ID, | ||
1977 | .setup = pci_brcm_trumanage_setup, | ||
1978 | }, | ||
1979 | |||
1980 | /* | ||
1957 | * Default "match everything" terminator entry | 1981 | * Default "match everything" terminator entry |
1958 | */ | 1982 | */ |
1959 | { | 1983 | { |
@@ -2148,6 +2172,7 @@ enum pci_board_num_t { | |||
2148 | pbn_ce4100_1_115200, | 2172 | pbn_ce4100_1_115200, |
2149 | pbn_omegapci, | 2173 | pbn_omegapci, |
2150 | pbn_NETMOS9900_2s_115200, | 2174 | pbn_NETMOS9900_2s_115200, |
2175 | pbn_brcm_trumanage, | ||
2151 | }; | 2176 | }; |
2152 | 2177 | ||
2153 | /* | 2178 | /* |
@@ -2246,7 +2271,7 @@ static struct pciserial_board pci_boards[] = { | |||
2246 | 2271 | ||
2247 | [pbn_b0_8_1152000_200] = { | 2272 | [pbn_b0_8_1152000_200] = { |
2248 | .flags = FL_BASE0, | 2273 | .flags = FL_BASE0, |
2249 | .num_ports = 2, | 2274 | .num_ports = 8, |
2250 | .base_baud = 1152000, | 2275 | .base_baud = 1152000, |
2251 | .uart_offset = 0x200, | 2276 | .uart_offset = 0x200, |
2252 | }, | 2277 | }, |
@@ -2892,6 +2917,12 @@ static struct pciserial_board pci_boards[] = { | |||
2892 | .num_ports = 2, | 2917 | .num_ports = 2, |
2893 | .base_baud = 115200, | 2918 | .base_baud = 115200, |
2894 | }, | 2919 | }, |
2920 | [pbn_brcm_trumanage] = { | ||
2921 | .flags = FL_BASE0, | ||
2922 | .num_ports = 1, | ||
2923 | .reg_shift = 2, | ||
2924 | .base_baud = 115200, | ||
2925 | }, | ||
2895 | }; | 2926 | }; |
2896 | 2927 | ||
2897 | static const struct pci_device_id blacklist[] = { | 2928 | static const struct pci_device_id blacklist[] = { |
@@ -4471,6 +4502,13 @@ static struct pci_device_id serial_pci_tbl[] = { | |||
4471 | pbn_omegapci }, | 4502 | pbn_omegapci }, |
4472 | 4503 | ||
4473 | /* | 4504 | /* |
4505 | * Broadcom TruManage | ||
4506 | */ | ||
4507 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BROADCOM_TRUMANAGE, | ||
4508 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, | ||
4509 | pbn_brcm_trumanage }, | ||
4510 | |||
4511 | /* | ||
4474 | * AgeStar as-prs2-009 | 4512 | * AgeStar as-prs2-009 |
4475 | */ | 4513 | */ |
4476 | { PCI_VENDOR_ID_AGESTAR, PCI_DEVICE_ID_AGESTAR_9375, | 4514 | { PCI_VENDOR_ID_AGESTAR, PCI_DEVICE_ID_AGESTAR_9375, |
diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c index 675d94ab0aff..8cb6d8d66a13 100644 --- a/drivers/tty/serial/ifx6x60.c +++ b/drivers/tty/serial/ifx6x60.c | |||
@@ -637,6 +637,7 @@ static void ifx_port_shutdown(struct tty_port *port) | |||
637 | 637 | ||
638 | clear_bit(IFX_SPI_STATE_IO_AVAILABLE, &ifx_dev->flags); | 638 | clear_bit(IFX_SPI_STATE_IO_AVAILABLE, &ifx_dev->flags); |
639 | mrdy_set_low(ifx_dev); | 639 | mrdy_set_low(ifx_dev); |
640 | del_timer(&ifx_dev->spi_timer); | ||
640 | clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags); | 641 | clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags); |
641 | tasklet_kill(&ifx_dev->io_work_tasklet); | 642 | tasklet_kill(&ifx_dev->io_work_tasklet); |
642 | } | 643 | } |
@@ -810,7 +811,8 @@ static void ifx_spi_io(unsigned long data) | |||
810 | ifx_dev->spi_xfer.cs_change = 0; | 811 | ifx_dev->spi_xfer.cs_change = 0; |
811 | ifx_dev->spi_xfer.speed_hz = ifx_dev->spi_dev->max_speed_hz; | 812 | ifx_dev->spi_xfer.speed_hz = ifx_dev->spi_dev->max_speed_hz; |
812 | /* ifx_dev->spi_xfer.speed_hz = 390625; */ | 813 | /* ifx_dev->spi_xfer.speed_hz = 390625; */ |
813 | ifx_dev->spi_xfer.bits_per_word = spi_bpw; | 814 | ifx_dev->spi_xfer.bits_per_word = |
815 | ifx_dev->spi_dev->bits_per_word; | ||
814 | 816 | ||
815 | ifx_dev->spi_xfer.tx_buf = ifx_dev->tx_buffer; | 817 | ifx_dev->spi_xfer.tx_buf = ifx_dev->tx_buffer; |
816 | ifx_dev->spi_xfer.rx_buf = ifx_dev->rx_buffer; | 818 | ifx_dev->spi_xfer.rx_buf = ifx_dev->rx_buffer; |
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index 6db23b035efe..e55615eb34ad 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c | |||
@@ -253,7 +253,7 @@ static void mxs_auart_tx_chars(struct mxs_auart_port *s) | |||
253 | struct circ_buf *xmit = &s->port.state->xmit; | 253 | struct circ_buf *xmit = &s->port.state->xmit; |
254 | 254 | ||
255 | if (auart_dma_enabled(s)) { | 255 | if (auart_dma_enabled(s)) { |
256 | int i = 0; | 256 | u32 i = 0; |
257 | int size; | 257 | int size; |
258 | void *buffer = s->tx_dma_buf; | 258 | void *buffer = s->tx_dma_buf; |
259 | 259 | ||
@@ -412,10 +412,12 @@ static void mxs_auart_set_mctrl(struct uart_port *u, unsigned mctrl) | |||
412 | 412 | ||
413 | u32 ctrl = readl(u->membase + AUART_CTRL2); | 413 | u32 ctrl = readl(u->membase + AUART_CTRL2); |
414 | 414 | ||
415 | ctrl &= ~AUART_CTRL2_RTSEN; | 415 | ctrl &= ~(AUART_CTRL2_RTSEN | AUART_CTRL2_RTS); |
416 | if (mctrl & TIOCM_RTS) { | 416 | if (mctrl & TIOCM_RTS) { |
417 | if (tty_port_cts_enabled(&u->state->port)) | 417 | if (tty_port_cts_enabled(&u->state->port)) |
418 | ctrl |= AUART_CTRL2_RTSEN; | 418 | ctrl |= AUART_CTRL2_RTSEN; |
419 | else | ||
420 | ctrl |= AUART_CTRL2_RTS; | ||
419 | } | 421 | } |
420 | 422 | ||
421 | s->ctrl = mctrl; | 423 | s->ctrl = mctrl; |
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index 12e5249d053e..e514b3a4dc57 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c | |||
@@ -1006,7 +1006,6 @@ static void s3c24xx_serial_resetport(struct uart_port *port, | |||
1006 | 1006 | ||
1007 | ucon &= ucon_mask; | 1007 | ucon &= ucon_mask; |
1008 | wr_regl(port, S3C2410_UCON, ucon | cfg->ucon); | 1008 | wr_regl(port, S3C2410_UCON, ucon | cfg->ucon); |
1009 | wr_regl(port, S3C2410_ULCON, cfg->ulcon); | ||
1010 | 1009 | ||
1011 | /* reset both fifos */ | 1010 | /* reset both fifos */ |
1012 | wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH); | 1011 | wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH); |
diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c index 8fd181436a6b..d5ed9f613005 100644 --- a/drivers/tty/serial/vt8500_serial.c +++ b/drivers/tty/serial/vt8500_serial.c | |||
@@ -604,7 +604,7 @@ static int vt8500_serial_probe(struct platform_device *pdev) | |||
604 | vt8500_port->uart.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF; | 604 | vt8500_port->uart.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF; |
605 | 605 | ||
606 | vt8500_port->clk = of_clk_get(pdev->dev.of_node, 0); | 606 | vt8500_port->clk = of_clk_get(pdev->dev.of_node, 0); |
607 | if (vt8500_port->clk) { | 607 | if (!IS_ERR(vt8500_port->clk)) { |
608 | vt8500_port->uart.uartclk = clk_get_rate(vt8500_port->clk); | 608 | vt8500_port->uart.uartclk = clk_get_rate(vt8500_port->clk); |
609 | } else { | 609 | } else { |
610 | /* use the default of 24Mhz if not specified and warn */ | 610 | /* use the default of 24Mhz if not specified and warn */ |
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 4c90b510d016..640ae6c6d2d2 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig | |||
@@ -37,6 +37,7 @@ config USB_ARCH_HAS_EHCI | |||
37 | default y if ARCH_W90X900 | 37 | default y if ARCH_W90X900 |
38 | default y if ARCH_AT91 | 38 | default y if ARCH_AT91 |
39 | default y if ARCH_MXC | 39 | default y if ARCH_MXC |
40 | default y if ARCH_MXS | ||
40 | default y if ARCH_OMAP3 | 41 | default y if ARCH_OMAP3 |
41 | default y if ARCH_CNS3XXX | 42 | default y if ARCH_CNS3XXX |
42 | default y if ARCH_VT8500 | 43 | default y if ARCH_VT8500 |
diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index caecad9213f5..8e9d31277c43 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c | |||
@@ -70,6 +70,9 @@ static int host_start(struct ci13xxx *ci) | |||
70 | else | 70 | else |
71 | ci->hcd = hcd; | 71 | ci->hcd = hcd; |
72 | 72 | ||
73 | if (ci->platdata->flags & CI13XXX_DISABLE_STREAMING) | ||
74 | hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS); | ||
75 | |||
73 | return ret; | 76 | return ret; |
74 | } | 77 | } |
75 | 78 | ||
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 8d809a811e16..2d92cce260d7 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c | |||
@@ -1602,6 +1602,9 @@ static const struct usb_device_id acm_ids[] = { | |||
1602 | { USB_DEVICE(0x0572, 0x1340), /* Conexant CX93010-2x UCMxx */ | 1602 | { USB_DEVICE(0x0572, 0x1340), /* Conexant CX93010-2x UCMxx */ |
1603 | .driver_info = NO_UNION_NORMAL, | 1603 | .driver_info = NO_UNION_NORMAL, |
1604 | }, | 1604 | }, |
1605 | { USB_DEVICE(0x05f9, 0x4002), /* PSC Scanning, Magellan 800i */ | ||
1606 | .driver_info = NO_UNION_NORMAL, | ||
1607 | }, | ||
1605 | { USB_DEVICE(0x1bbb, 0x0003), /* Alcatel OT-I650 */ | 1608 | { USB_DEVICE(0x1bbb, 0x0003), /* Alcatel OT-I650 */ |
1606 | .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */ | 1609 | .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */ |
1607 | }, | 1610 | }, |
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index a815fd2cc5e7..957ed2c41482 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c | |||
@@ -877,6 +877,60 @@ static int hub_hub_status(struct usb_hub *hub, | |||
877 | return ret; | 877 | return ret; |
878 | } | 878 | } |
879 | 879 | ||
880 | static int hub_set_port_link_state(struct usb_hub *hub, int port1, | ||
881 | unsigned int link_status) | ||
882 | { | ||
883 | return set_port_feature(hub->hdev, | ||
884 | port1 | (link_status << 3), | ||
885 | USB_PORT_FEAT_LINK_STATE); | ||
886 | } | ||
887 | |||
888 | /* | ||
889 | * If USB 3.0 ports are placed into the Disabled state, they will no longer | ||
890 | * detect any device connects or disconnects. This is generally not what the | ||
891 | * USB core wants, since it expects a disabled port to produce a port status | ||
892 | * change event when a new device connects. | ||
893 | * | ||
894 | * Instead, set the link state to Disabled, wait for the link to settle into | ||
895 | * that state, clear any change bits, and then put the port into the RxDetect | ||
896 | * state. | ||
897 | */ | ||
898 | static int hub_usb3_port_disable(struct usb_hub *hub, int port1) | ||
899 | { | ||
900 | int ret; | ||
901 | int total_time; | ||
902 | u16 portchange, portstatus; | ||
903 | |||
904 | if (!hub_is_superspeed(hub->hdev)) | ||
905 | return -EINVAL; | ||
906 | |||
907 | ret = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_SS_DISABLED); | ||
908 | if (ret) { | ||
909 | dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n", | ||
910 | port1, ret); | ||
911 | return ret; | ||
912 | } | ||
913 | |||
914 | /* Wait for the link to enter the disabled state. */ | ||
915 | for (total_time = 0; ; total_time += HUB_DEBOUNCE_STEP) { | ||
916 | ret = hub_port_status(hub, port1, &portstatus, &portchange); | ||
917 | if (ret < 0) | ||
918 | return ret; | ||
919 | |||
920 | if ((portstatus & USB_PORT_STAT_LINK_STATE) == | ||
921 | USB_SS_PORT_LS_SS_DISABLED) | ||
922 | break; | ||
923 | if (total_time >= HUB_DEBOUNCE_TIMEOUT) | ||
924 | break; | ||
925 | msleep(HUB_DEBOUNCE_STEP); | ||
926 | } | ||
927 | if (total_time >= HUB_DEBOUNCE_TIMEOUT) | ||
928 | dev_warn(hub->intfdev, "Could not disable port %d after %d ms\n", | ||
929 | port1, total_time); | ||
930 | |||
931 | return hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_RX_DETECT); | ||
932 | } | ||
933 | |||
880 | static int hub_port_disable(struct usb_hub *hub, int port1, int set_state) | 934 | static int hub_port_disable(struct usb_hub *hub, int port1, int set_state) |
881 | { | 935 | { |
882 | struct usb_device *hdev = hub->hdev; | 936 | struct usb_device *hdev = hub->hdev; |
@@ -885,8 +939,13 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state) | |||
885 | if (hub->ports[port1 - 1]->child && set_state) | 939 | if (hub->ports[port1 - 1]->child && set_state) |
886 | usb_set_device_state(hub->ports[port1 - 1]->child, | 940 | usb_set_device_state(hub->ports[port1 - 1]->child, |
887 | USB_STATE_NOTATTACHED); | 941 | USB_STATE_NOTATTACHED); |
888 | if (!hub->error && !hub_is_superspeed(hub->hdev)) | 942 | if (!hub->error) { |
889 | ret = clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE); | 943 | if (hub_is_superspeed(hub->hdev)) |
944 | ret = hub_usb3_port_disable(hub, port1); | ||
945 | else | ||
946 | ret = clear_port_feature(hdev, port1, | ||
947 | USB_PORT_FEAT_ENABLE); | ||
948 | } | ||
890 | if (ret) | 949 | if (ret) |
891 | dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n", | 950 | dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n", |
892 | port1, ret); | 951 | port1, ret); |
@@ -2440,7 +2499,7 @@ static unsigned hub_is_wusb(struct usb_hub *hub) | |||
2440 | #define HUB_SHORT_RESET_TIME 10 | 2499 | #define HUB_SHORT_RESET_TIME 10 |
2441 | #define HUB_BH_RESET_TIME 50 | 2500 | #define HUB_BH_RESET_TIME 50 |
2442 | #define HUB_LONG_RESET_TIME 200 | 2501 | #define HUB_LONG_RESET_TIME 200 |
2443 | #define HUB_RESET_TIMEOUT 500 | 2502 | #define HUB_RESET_TIMEOUT 800 |
2444 | 2503 | ||
2445 | static int hub_port_reset(struct usb_hub *hub, int port1, | 2504 | static int hub_port_reset(struct usb_hub *hub, int port1, |
2446 | struct usb_device *udev, unsigned int delay, bool warm); | 2505 | struct usb_device *udev, unsigned int delay, bool warm); |
@@ -2475,6 +2534,10 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1, | |||
2475 | if (ret < 0) | 2534 | if (ret < 0) |
2476 | return ret; | 2535 | return ret; |
2477 | 2536 | ||
2537 | /* The port state is unknown until the reset completes. */ | ||
2538 | if ((portstatus & USB_PORT_STAT_RESET)) | ||
2539 | goto delay; | ||
2540 | |||
2478 | /* | 2541 | /* |
2479 | * Some buggy devices require a warm reset to be issued even | 2542 | * Some buggy devices require a warm reset to be issued even |
2480 | * when the port appears not to be connected. | 2543 | * when the port appears not to be connected. |
@@ -2520,11 +2583,7 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1, | |||
2520 | if ((portchange & USB_PORT_STAT_C_CONNECTION)) | 2583 | if ((portchange & USB_PORT_STAT_C_CONNECTION)) |
2521 | return -ENOTCONN; | 2584 | return -ENOTCONN; |
2522 | 2585 | ||
2523 | /* if we`ve finished resetting, then break out of | 2586 | if ((portstatus & USB_PORT_STAT_ENABLE)) { |
2524 | * the loop | ||
2525 | */ | ||
2526 | if (!(portstatus & USB_PORT_STAT_RESET) && | ||
2527 | (portstatus & USB_PORT_STAT_ENABLE)) { | ||
2528 | if (hub_is_wusb(hub)) | 2587 | if (hub_is_wusb(hub)) |
2529 | udev->speed = USB_SPEED_WIRELESS; | 2588 | udev->speed = USB_SPEED_WIRELESS; |
2530 | else if (hub_is_superspeed(hub->hdev)) | 2589 | else if (hub_is_superspeed(hub->hdev)) |
@@ -2538,10 +2597,15 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1, | |||
2538 | return 0; | 2597 | return 0; |
2539 | } | 2598 | } |
2540 | } else { | 2599 | } else { |
2541 | if (portchange & USB_PORT_STAT_C_BH_RESET) | 2600 | if (!(portstatus & USB_PORT_STAT_CONNECTION) || |
2542 | return 0; | 2601 | hub_port_warm_reset_required(hub, |
2602 | portstatus)) | ||
2603 | return -ENOTCONN; | ||
2604 | |||
2605 | return 0; | ||
2543 | } | 2606 | } |
2544 | 2607 | ||
2608 | delay: | ||
2545 | /* switch to the long delay after two short delay failures */ | 2609 | /* switch to the long delay after two short delay failures */ |
2546 | if (delay_time >= 2 * HUB_SHORT_RESET_TIME) | 2610 | if (delay_time >= 2 * HUB_SHORT_RESET_TIME) |
2547 | delay = HUB_LONG_RESET_TIME; | 2611 | delay = HUB_LONG_RESET_TIME; |
@@ -2565,14 +2629,11 @@ static void hub_port_finish_reset(struct usb_hub *hub, int port1, | |||
2565 | msleep(10 + 40); | 2629 | msleep(10 + 40); |
2566 | update_devnum(udev, 0); | 2630 | update_devnum(udev, 0); |
2567 | hcd = bus_to_hcd(udev->bus); | 2631 | hcd = bus_to_hcd(udev->bus); |
2568 | if (hcd->driver->reset_device) { | 2632 | /* The xHC may think the device is already reset, |
2569 | *status = hcd->driver->reset_device(hcd, udev); | 2633 | * so ignore the status. |
2570 | if (*status < 0) { | 2634 | */ |
2571 | dev_err(&udev->dev, "Cannot reset " | 2635 | if (hcd->driver->reset_device) |
2572 | "HCD device state\n"); | 2636 | hcd->driver->reset_device(hcd, udev); |
2573 | break; | ||
2574 | } | ||
2575 | } | ||
2576 | } | 2637 | } |
2577 | /* FALL THROUGH */ | 2638 | /* FALL THROUGH */ |
2578 | case -ENOTCONN: | 2639 | case -ENOTCONN: |
@@ -2580,16 +2641,16 @@ static void hub_port_finish_reset(struct usb_hub *hub, int port1, | |||
2580 | clear_port_feature(hub->hdev, | 2641 | clear_port_feature(hub->hdev, |
2581 | port1, USB_PORT_FEAT_C_RESET); | 2642 | port1, USB_PORT_FEAT_C_RESET); |
2582 | /* FIXME need disconnect() for NOTATTACHED device */ | 2643 | /* FIXME need disconnect() for NOTATTACHED device */ |
2583 | if (warm) { | 2644 | if (hub_is_superspeed(hub->hdev)) { |
2584 | clear_port_feature(hub->hdev, port1, | 2645 | clear_port_feature(hub->hdev, port1, |
2585 | USB_PORT_FEAT_C_BH_PORT_RESET); | 2646 | USB_PORT_FEAT_C_BH_PORT_RESET); |
2586 | clear_port_feature(hub->hdev, port1, | 2647 | clear_port_feature(hub->hdev, port1, |
2587 | USB_PORT_FEAT_C_PORT_LINK_STATE); | 2648 | USB_PORT_FEAT_C_PORT_LINK_STATE); |
2588 | } else { | 2649 | } |
2650 | if (!warm) | ||
2589 | usb_set_device_state(udev, *status | 2651 | usb_set_device_state(udev, *status |
2590 | ? USB_STATE_NOTATTACHED | 2652 | ? USB_STATE_NOTATTACHED |
2591 | : USB_STATE_DEFAULT); | 2653 | : USB_STATE_DEFAULT); |
2592 | } | ||
2593 | break; | 2654 | break; |
2594 | } | 2655 | } |
2595 | } | 2656 | } |
@@ -2939,7 +3000,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) | |||
2939 | static int finish_port_resume(struct usb_device *udev) | 3000 | static int finish_port_resume(struct usb_device *udev) |
2940 | { | 3001 | { |
2941 | int status = 0; | 3002 | int status = 0; |
2942 | u16 devstatus; | 3003 | u16 devstatus = 0; |
2943 | 3004 | ||
2944 | /* caller owns the udev device lock */ | 3005 | /* caller owns the udev device lock */ |
2945 | dev_dbg(&udev->dev, "%s\n", | 3006 | dev_dbg(&udev->dev, "%s\n", |
@@ -2984,7 +3045,13 @@ static int finish_port_resume(struct usb_device *udev) | |||
2984 | if (status) { | 3045 | if (status) { |
2985 | dev_dbg(&udev->dev, "gone after usb resume? status %d\n", | 3046 | dev_dbg(&udev->dev, "gone after usb resume? status %d\n", |
2986 | status); | 3047 | status); |
2987 | } else if (udev->actconfig) { | 3048 | /* |
3049 | * There are a few quirky devices which violate the standard | ||
3050 | * by claiming to have remote wakeup enabled after a reset, | ||
3051 | * which crash if the feature is cleared, hence check for | ||
3052 | * udev->reset_resume | ||
3053 | */ | ||
3054 | } else if (udev->actconfig && !udev->reset_resume) { | ||
2988 | le16_to_cpus(&devstatus); | 3055 | le16_to_cpus(&devstatus); |
2989 | if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) { | 3056 | if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) { |
2990 | status = usb_control_msg(udev, | 3057 | status = usb_control_msg(udev, |
@@ -4638,9 +4705,14 @@ static void hub_events(void) | |||
4638 | * SS.Inactive state. | 4705 | * SS.Inactive state. |
4639 | */ | 4706 | */ |
4640 | if (hub_port_warm_reset_required(hub, portstatus)) { | 4707 | if (hub_port_warm_reset_required(hub, portstatus)) { |
4708 | int status; | ||
4709 | |||
4641 | dev_dbg(hub_dev, "warm reset port %d\n", i); | 4710 | dev_dbg(hub_dev, "warm reset port %d\n", i); |
4642 | hub_port_reset(hub, i, NULL, | 4711 | status = hub_port_reset(hub, i, NULL, |
4643 | HUB_BH_RESET_TIME, true); | 4712 | HUB_BH_RESET_TIME, true); |
4713 | if (status < 0) | ||
4714 | hub_port_disable(hub, i, 1); | ||
4715 | connect_change = 0; | ||
4644 | } | 4716 | } |
4645 | 4717 | ||
4646 | if (connect_change) | 4718 | if (connect_change) |
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index fdefd9c7f7af..3113c1d71442 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c | |||
@@ -43,6 +43,9 @@ static const struct usb_device_id usb_quirk_list[] = { | |||
43 | /* Creative SB Audigy 2 NX */ | 43 | /* Creative SB Audigy 2 NX */ |
44 | { USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME }, | 44 | { USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME }, |
45 | 45 | ||
46 | /* Microsoft LifeCam-VX700 v2.0 */ | ||
47 | { USB_DEVICE(0x045e, 0x0770), .driver_info = USB_QUIRK_RESET_RESUME }, | ||
48 | |||
46 | /* Logitech Quickcam Fusion */ | 49 | /* Logitech Quickcam Fusion */ |
47 | { USB_DEVICE(0x046d, 0x08c1), .driver_info = USB_QUIRK_RESET_RESUME }, | 50 | { USB_DEVICE(0x046d, 0x08c1), .driver_info = USB_QUIRK_RESET_RESUME }, |
48 | 51 | ||
diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c index 92604b4f9712..5945aadaa1c9 100644 --- a/drivers/usb/dwc3/debugfs.c +++ b/drivers/usb/dwc3/debugfs.c | |||
@@ -56,7 +56,7 @@ | |||
56 | #define dump_register(nm) \ | 56 | #define dump_register(nm) \ |
57 | { \ | 57 | { \ |
58 | .name = __stringify(nm), \ | 58 | .name = __stringify(nm), \ |
59 | .offset = DWC3_ ##nm, \ | 59 | .offset = DWC3_ ##nm - DWC3_GLOBALS_REGS_START, \ |
60 | } | 60 | } |
61 | 61 | ||
62 | static const struct debugfs_reg32 dwc3_regs[] = { | 62 | static const struct debugfs_reg32 dwc3_regs[] = { |
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 2e43b332aae8..2fdd767f8fe8 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c | |||
@@ -1605,6 +1605,7 @@ static int dwc3_gadget_init_endpoints(struct dwc3 *dwc) | |||
1605 | 1605 | ||
1606 | if (epnum == 0 || epnum == 1) { | 1606 | if (epnum == 0 || epnum == 1) { |
1607 | dep->endpoint.maxpacket = 512; | 1607 | dep->endpoint.maxpacket = 512; |
1608 | dep->endpoint.maxburst = 1; | ||
1608 | dep->endpoint.ops = &dwc3_gadget_ep0_ops; | 1609 | dep->endpoint.ops = &dwc3_gadget_ep0_ops; |
1609 | if (!epnum) | 1610 | if (!epnum) |
1610 | dwc->gadget.ep0 = &dep->endpoint; | 1611 | dwc->gadget.ep0 = &dep->endpoint; |
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index fc0ec5e0d58e..d9f6b9372491 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c | |||
@@ -3231,7 +3231,7 @@ static int udc_pci_probe( | |||
3231 | } | 3231 | } |
3232 | 3232 | ||
3233 | if (!pdev->irq) { | 3233 | if (!pdev->irq) { |
3234 | dev_err(&dev->pdev->dev, "irq not set\n"); | 3234 | dev_err(&pdev->dev, "irq not set\n"); |
3235 | kfree(dev); | 3235 | kfree(dev); |
3236 | dev = NULL; | 3236 | dev = NULL; |
3237 | retval = -ENODEV; | 3237 | retval = -ENODEV; |
@@ -3250,7 +3250,7 @@ static int udc_pci_probe( | |||
3250 | dev->txfifo = (u32 __iomem *)(dev->virt_addr + UDC_TXFIFO_ADDR); | 3250 | dev->txfifo = (u32 __iomem *)(dev->virt_addr + UDC_TXFIFO_ADDR); |
3251 | 3251 | ||
3252 | if (request_irq(pdev->irq, udc_irq, IRQF_SHARED, name, dev) != 0) { | 3252 | if (request_irq(pdev->irq, udc_irq, IRQF_SHARED, name, dev) != 0) { |
3253 | dev_dbg(&dev->pdev->dev, "request_irq(%d) fail\n", pdev->irq); | 3253 | dev_dbg(&pdev->dev, "request_irq(%d) fail\n", pdev->irq); |
3254 | kfree(dev); | 3254 | kfree(dev); |
3255 | dev = NULL; | 3255 | dev = NULL; |
3256 | retval = -EBUSY; | 3256 | retval = -EBUSY; |
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 95d584dbed13..8cf0c0f6fa1f 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c | |||
@@ -130,10 +130,7 @@ static const char ep0name[] = "ep0"; | |||
130 | static const char *const ep_name[] = { | 130 | static const char *const ep_name[] = { |
131 | ep0name, /* everyone has ep0 */ | 131 | ep0name, /* everyone has ep0 */ |
132 | 132 | ||
133 | /* act like a net2280: high speed, six configurable endpoints */ | 133 | /* act like a pxa250: fifteen fixed function endpoints */ |
134 | "ep-a", "ep-b", "ep-c", "ep-d", "ep-e", "ep-f", | ||
135 | |||
136 | /* or like pxa250: fifteen fixed function endpoints */ | ||
137 | "ep1in-bulk", "ep2out-bulk", "ep3in-iso", "ep4out-iso", "ep5in-int", | 134 | "ep1in-bulk", "ep2out-bulk", "ep3in-iso", "ep4out-iso", "ep5in-int", |
138 | "ep6in-bulk", "ep7out-bulk", "ep8in-iso", "ep9out-iso", "ep10in-int", | 135 | "ep6in-bulk", "ep7out-bulk", "ep8in-iso", "ep9out-iso", "ep10in-int", |
139 | "ep11in-bulk", "ep12out-bulk", "ep13in-iso", "ep14out-iso", | 136 | "ep11in-bulk", "ep12out-bulk", "ep13in-iso", "ep14out-iso", |
@@ -141,6 +138,10 @@ static const char *const ep_name[] = { | |||
141 | 138 | ||
142 | /* or like sa1100: two fixed function endpoints */ | 139 | /* or like sa1100: two fixed function endpoints */ |
143 | "ep1out-bulk", "ep2in-bulk", | 140 | "ep1out-bulk", "ep2in-bulk", |
141 | |||
142 | /* and now some generic EPs so we have enough in multi config */ | ||
143 | "ep3out", "ep4in", "ep5out", "ep6out", "ep7in", "ep8out", "ep9in", | ||
144 | "ep10out", "ep11out", "ep12in", "ep13out", "ep14in", "ep15out", | ||
144 | }; | 145 | }; |
145 | #define DUMMY_ENDPOINTS ARRAY_SIZE(ep_name) | 146 | #define DUMMY_ENDPOINTS ARRAY_SIZE(ep_name) |
146 | 147 | ||
diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index 4a6961c517f2..8c2f25121149 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c | |||
@@ -1153,15 +1153,15 @@ static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts) | |||
1153 | pr_err("%s: unmapped value: %lu\n", opts, value); | 1153 | pr_err("%s: unmapped value: %lu\n", opts, value); |
1154 | return -EINVAL; | 1154 | return -EINVAL; |
1155 | } | 1155 | } |
1156 | } | 1156 | } else if (!memcmp(opts, "gid", 3)) { |
1157 | else if (!memcmp(opts, "gid", 3)) | ||
1158 | data->perms.gid = make_kgid(current_user_ns(), value); | 1157 | data->perms.gid = make_kgid(current_user_ns(), value); |
1159 | if (!gid_valid(data->perms.gid)) { | 1158 | if (!gid_valid(data->perms.gid)) { |
1160 | pr_err("%s: unmapped value: %lu\n", opts, value); | 1159 | pr_err("%s: unmapped value: %lu\n", opts, value); |
1161 | return -EINVAL; | 1160 | return -EINVAL; |
1162 | } | 1161 | } |
1163 | else | 1162 | } else { |
1164 | goto invalid; | 1163 | goto invalid; |
1164 | } | ||
1165 | break; | 1165 | break; |
1166 | 1166 | ||
1167 | default: | 1167 | default: |
diff --git a/drivers/usb/gadget/fsl_mxc_udc.c b/drivers/usb/gadget/fsl_mxc_udc.c index 1b0f086426bd..d3bd7b095ba3 100644 --- a/drivers/usb/gadget/fsl_mxc_udc.c +++ b/drivers/usb/gadget/fsl_mxc_udc.c | |||
@@ -18,14 +18,13 @@ | |||
18 | #include <linux/platform_device.h> | 18 | #include <linux/platform_device.h> |
19 | #include <linux/io.h> | 19 | #include <linux/io.h> |
20 | 20 | ||
21 | #include <mach/hardware.h> | ||
22 | |||
23 | static struct clk *mxc_ahb_clk; | 21 | static struct clk *mxc_ahb_clk; |
24 | static struct clk *mxc_per_clk; | 22 | static struct clk *mxc_per_clk; |
25 | static struct clk *mxc_ipg_clk; | 23 | static struct clk *mxc_ipg_clk; |
26 | 24 | ||
27 | /* workaround ENGcm09152 for i.MX35 */ | 25 | /* workaround ENGcm09152 for i.MX35 */ |
28 | #define USBPHYCTRL_OTGBASE_OFFSET 0x608 | 26 | #define MX35_USBPHYCTRL_OFFSET 0x600 |
27 | #define USBPHYCTRL_OTGBASE_OFFSET 0x8 | ||
29 | #define USBPHYCTRL_EVDO (1 << 23) | 28 | #define USBPHYCTRL_EVDO (1 << 23) |
30 | 29 | ||
31 | int fsl_udc_clk_init(struct platform_device *pdev) | 30 | int fsl_udc_clk_init(struct platform_device *pdev) |
@@ -59,7 +58,7 @@ int fsl_udc_clk_init(struct platform_device *pdev) | |||
59 | clk_prepare_enable(mxc_per_clk); | 58 | clk_prepare_enable(mxc_per_clk); |
60 | 59 | ||
61 | /* make sure USB_CLK is running at 60 MHz +/- 1000 Hz */ | 60 | /* make sure USB_CLK is running at 60 MHz +/- 1000 Hz */ |
62 | if (!cpu_is_mx51()) { | 61 | if (!strcmp(pdev->id_entry->name, "imx-udc-mx27")) { |
63 | freq = clk_get_rate(mxc_per_clk); | 62 | freq = clk_get_rate(mxc_per_clk); |
64 | if (pdata->phy_mode != FSL_USB2_PHY_ULPI && | 63 | if (pdata->phy_mode != FSL_USB2_PHY_ULPI && |
65 | (freq < 59999000 || freq > 60001000)) { | 64 | (freq < 59999000 || freq > 60001000)) { |
@@ -79,27 +78,40 @@ eclkrate: | |||
79 | return ret; | 78 | return ret; |
80 | } | 79 | } |
81 | 80 | ||
82 | void fsl_udc_clk_finalize(struct platform_device *pdev) | 81 | int fsl_udc_clk_finalize(struct platform_device *pdev) |
83 | { | 82 | { |
84 | struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; | 83 | struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; |
85 | if (cpu_is_mx35()) { | 84 | int ret = 0; |
86 | unsigned int v; | ||
87 | 85 | ||
88 | /* workaround ENGcm09152 for i.MX35 */ | 86 | /* workaround ENGcm09152 for i.MX35 */ |
89 | if (pdata->workaround & FLS_USB2_WORKAROUND_ENGCM09152) { | 87 | if (pdata->workaround & FLS_USB2_WORKAROUND_ENGCM09152) { |
90 | v = readl(MX35_IO_ADDRESS(MX35_USB_BASE_ADDR + | 88 | unsigned int v; |
91 | USBPHYCTRL_OTGBASE_OFFSET)); | 89 | struct resource *res = platform_get_resource |
92 | writel(v | USBPHYCTRL_EVDO, | 90 | (pdev, IORESOURCE_MEM, 0); |
93 | MX35_IO_ADDRESS(MX35_USB_BASE_ADDR + | 91 | void __iomem *phy_regs = ioremap(res->start + |
94 | USBPHYCTRL_OTGBASE_OFFSET)); | 92 | MX35_USBPHYCTRL_OFFSET, 512); |
93 | if (!phy_regs) { | ||
94 | dev_err(&pdev->dev, "ioremap for phy address fails\n"); | ||
95 | ret = -EINVAL; | ||
96 | goto ioremap_err; | ||
95 | } | 97 | } |
98 | |||
99 | v = readl(phy_regs + USBPHYCTRL_OTGBASE_OFFSET); | ||
100 | writel(v | USBPHYCTRL_EVDO, | ||
101 | phy_regs + USBPHYCTRL_OTGBASE_OFFSET); | ||
102 | |||
103 | iounmap(phy_regs); | ||
96 | } | 104 | } |
97 | 105 | ||
106 | |||
107 | ioremap_err: | ||
98 | /* ULPI transceivers don't need usbpll */ | 108 | /* ULPI transceivers don't need usbpll */ |
99 | if (pdata->phy_mode == FSL_USB2_PHY_ULPI) { | 109 | if (pdata->phy_mode == FSL_USB2_PHY_ULPI) { |
100 | clk_disable_unprepare(mxc_per_clk); | 110 | clk_disable_unprepare(mxc_per_clk); |
101 | mxc_per_clk = NULL; | 111 | mxc_per_clk = NULL; |
102 | } | 112 | } |
113 | |||
114 | return ret; | ||
103 | } | 115 | } |
104 | 116 | ||
105 | void fsl_udc_clk_release(void) | 117 | void fsl_udc_clk_release(void) |
diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index c19f7f13790b..667275cb7bad 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <linux/fsl_devices.h> | 41 | #include <linux/fsl_devices.h> |
42 | #include <linux/dmapool.h> | 42 | #include <linux/dmapool.h> |
43 | #include <linux/delay.h> | 43 | #include <linux/delay.h> |
44 | #include <linux/of_device.h> | ||
44 | 45 | ||
45 | #include <asm/byteorder.h> | 46 | #include <asm/byteorder.h> |
46 | #include <asm/io.h> | 47 | #include <asm/io.h> |
@@ -2438,11 +2439,6 @@ static int __init fsl_udc_probe(struct platform_device *pdev) | |||
2438 | unsigned int i; | 2439 | unsigned int i; |
2439 | u32 dccparams; | 2440 | u32 dccparams; |
2440 | 2441 | ||
2441 | if (strcmp(pdev->name, driver_name)) { | ||
2442 | VDBG("Wrong device"); | ||
2443 | return -ENODEV; | ||
2444 | } | ||
2445 | |||
2446 | udc_controller = kzalloc(sizeof(struct fsl_udc), GFP_KERNEL); | 2442 | udc_controller = kzalloc(sizeof(struct fsl_udc), GFP_KERNEL); |
2447 | if (udc_controller == NULL) { | 2443 | if (udc_controller == NULL) { |
2448 | ERR("malloc udc failed\n"); | 2444 | ERR("malloc udc failed\n"); |
@@ -2547,7 +2543,9 @@ static int __init fsl_udc_probe(struct platform_device *pdev) | |||
2547 | dr_controller_setup(udc_controller); | 2543 | dr_controller_setup(udc_controller); |
2548 | } | 2544 | } |
2549 | 2545 | ||
2550 | fsl_udc_clk_finalize(pdev); | 2546 | ret = fsl_udc_clk_finalize(pdev); |
2547 | if (ret) | ||
2548 | goto err_free_irq; | ||
2551 | 2549 | ||
2552 | /* Setup gadget structure */ | 2550 | /* Setup gadget structure */ |
2553 | udc_controller->gadget.ops = &fsl_gadget_ops; | 2551 | udc_controller->gadget.ops = &fsl_gadget_ops; |
@@ -2756,22 +2754,32 @@ static int fsl_udc_otg_resume(struct device *dev) | |||
2756 | 2754 | ||
2757 | return fsl_udc_resume(NULL); | 2755 | return fsl_udc_resume(NULL); |
2758 | } | 2756 | } |
2759 | |||
2760 | /*------------------------------------------------------------------------- | 2757 | /*------------------------------------------------------------------------- |
2761 | Register entry point for the peripheral controller driver | 2758 | Register entry point for the peripheral controller driver |
2762 | --------------------------------------------------------------------------*/ | 2759 | --------------------------------------------------------------------------*/ |
2763 | 2760 | static const struct platform_device_id fsl_udc_devtype[] = { | |
2761 | { | ||
2762 | .name = "imx-udc-mx27", | ||
2763 | }, { | ||
2764 | .name = "imx-udc-mx51", | ||
2765 | }, { | ||
2766 | /* sentinel */ | ||
2767 | } | ||
2768 | }; | ||
2769 | MODULE_DEVICE_TABLE(platform, fsl_udc_devtype); | ||
2764 | static struct platform_driver udc_driver = { | 2770 | static struct platform_driver udc_driver = { |
2765 | .remove = __exit_p(fsl_udc_remove), | 2771 | .remove = __exit_p(fsl_udc_remove), |
2772 | /* Just for FSL i.mx SoC currently */ | ||
2773 | .id_table = fsl_udc_devtype, | ||
2766 | /* these suspend and resume are not usb suspend and resume */ | 2774 | /* these suspend and resume are not usb suspend and resume */ |
2767 | .suspend = fsl_udc_suspend, | 2775 | .suspend = fsl_udc_suspend, |
2768 | .resume = fsl_udc_resume, | 2776 | .resume = fsl_udc_resume, |
2769 | .driver = { | 2777 | .driver = { |
2770 | .name = (char *)driver_name, | 2778 | .name = (char *)driver_name, |
2771 | .owner = THIS_MODULE, | 2779 | .owner = THIS_MODULE, |
2772 | /* udc suspend/resume called from OTG driver */ | 2780 | /* udc suspend/resume called from OTG driver */ |
2773 | .suspend = fsl_udc_otg_suspend, | 2781 | .suspend = fsl_udc_otg_suspend, |
2774 | .resume = fsl_udc_otg_resume, | 2782 | .resume = fsl_udc_otg_resume, |
2775 | }, | 2783 | }, |
2776 | }; | 2784 | }; |
2777 | 2785 | ||
diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h index f61a967f7082..c6703bb07b23 100644 --- a/drivers/usb/gadget/fsl_usb2_udc.h +++ b/drivers/usb/gadget/fsl_usb2_udc.h | |||
@@ -592,15 +592,16 @@ static inline struct ep_queue_head *get_qh_by_ep(struct fsl_ep *ep) | |||
592 | struct platform_device; | 592 | struct platform_device; |
593 | #ifdef CONFIG_ARCH_MXC | 593 | #ifdef CONFIG_ARCH_MXC |
594 | int fsl_udc_clk_init(struct platform_device *pdev); | 594 | int fsl_udc_clk_init(struct platform_device *pdev); |
595 | void fsl_udc_clk_finalize(struct platform_device *pdev); | 595 | int fsl_udc_clk_finalize(struct platform_device *pdev); |
596 | void fsl_udc_clk_release(void); | 596 | void fsl_udc_clk_release(void); |
597 | #else | 597 | #else |
598 | static inline int fsl_udc_clk_init(struct platform_device *pdev) | 598 | static inline int fsl_udc_clk_init(struct platform_device *pdev) |
599 | { | 599 | { |
600 | return 0; | 600 | return 0; |
601 | } | 601 | } |
602 | static inline void fsl_udc_clk_finalize(struct platform_device *pdev) | 602 | static inline int fsl_udc_clk_finalize(struct platform_device *pdev) |
603 | { | 603 | { |
604 | return 0; | ||
604 | } | 605 | } |
605 | static inline void fsl_udc_clk_release(void) | 606 | static inline void fsl_udc_clk_release(void) |
606 | { | 607 | { |
diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index 379aac7b82fc..6e8b1272ebce 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c | |||
@@ -1012,7 +1012,7 @@ static void udc_clock_enable(struct mv_udc *udc) | |||
1012 | unsigned int i; | 1012 | unsigned int i; |
1013 | 1013 | ||
1014 | for (i = 0; i < udc->clknum; i++) | 1014 | for (i = 0; i < udc->clknum; i++) |
1015 | clk_enable(udc->clk[i]); | 1015 | clk_prepare_enable(udc->clk[i]); |
1016 | } | 1016 | } |
1017 | 1017 | ||
1018 | static void udc_clock_disable(struct mv_udc *udc) | 1018 | static void udc_clock_disable(struct mv_udc *udc) |
@@ -1020,7 +1020,7 @@ static void udc_clock_disable(struct mv_udc *udc) | |||
1020 | unsigned int i; | 1020 | unsigned int i; |
1021 | 1021 | ||
1022 | for (i = 0; i < udc->clknum; i++) | 1022 | for (i = 0; i < udc->clknum; i++) |
1023 | clk_disable(udc->clk[i]); | 1023 | clk_disable_unprepare(udc->clk[i]); |
1024 | } | 1024 | } |
1025 | 1025 | ||
1026 | static void udc_stop(struct mv_udc *udc) | 1026 | static void udc_stop(struct mv_udc *udc) |
diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 141971d9051e..439c3f972f8c 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c | |||
@@ -3477,12 +3477,11 @@ static void s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg) | |||
3477 | /** | 3477 | /** |
3478 | * s3c_hsotg_release - release callback for hsotg device | 3478 | * s3c_hsotg_release - release callback for hsotg device |
3479 | * @dev: Device to for which release is called | 3479 | * @dev: Device to for which release is called |
3480 | * | ||
3481 | * Nothing to do as the resource is allocated using devm_ API. | ||
3480 | */ | 3482 | */ |
3481 | static void s3c_hsotg_release(struct device *dev) | 3483 | static void s3c_hsotg_release(struct device *dev) |
3482 | { | 3484 | { |
3483 | struct s3c_hsotg *hsotg = dev_get_drvdata(dev); | ||
3484 | |||
3485 | kfree(hsotg); | ||
3486 | } | 3485 | } |
3487 | 3486 | ||
3488 | /** | 3487 | /** |
diff --git a/drivers/usb/gadget/tcm_usb_gadget.c b/drivers/usb/gadget/tcm_usb_gadget.c index 4f7f76f00c74..7cacd6ae818e 100644 --- a/drivers/usb/gadget/tcm_usb_gadget.c +++ b/drivers/usb/gadget/tcm_usb_gadget.c | |||
@@ -1794,9 +1794,10 @@ static int tcm_usbg_drop_nexus(struct usbg_tpg *tpg) | |||
1794 | tpg->tpg_nexus = NULL; | 1794 | tpg->tpg_nexus = NULL; |
1795 | 1795 | ||
1796 | kfree(tv_nexus); | 1796 | kfree(tv_nexus); |
1797 | ret = 0; | ||
1797 | out: | 1798 | out: |
1798 | mutex_unlock(&tpg->tpg_mutex); | 1799 | mutex_unlock(&tpg->tpg_mutex); |
1799 | return 0; | 1800 | return ret; |
1800 | } | 1801 | } |
1801 | 1802 | ||
1802 | static ssize_t tcm_usbg_tpg_store_nexus( | 1803 | static ssize_t tcm_usbg_tpg_store_nexus( |
diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c index d0f95482f40e..598dcc1212f0 100644 --- a/drivers/usb/gadget/u_serial.c +++ b/drivers/usb/gadget/u_serial.c | |||
@@ -887,7 +887,7 @@ static void gs_close(struct tty_struct *tty, struct file *file) | |||
887 | pr_debug("gs_close: ttyGS%d (%p,%p) done!\n", | 887 | pr_debug("gs_close: ttyGS%d (%p,%p) done!\n", |
888 | port->port_num, tty, file); | 888 | port->port_num, tty, file); |
889 | 889 | ||
890 | wake_up_interruptible(&port->port.close_wait); | 890 | wake_up(&port->port.close_wait); |
891 | exit: | 891 | exit: |
892 | spin_unlock_irq(&port->port_lock); | 892 | spin_unlock_irq(&port->port_lock); |
893 | } | 893 | } |
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index d6bb128ce21e..3a21c5d683c0 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig | |||
@@ -148,7 +148,7 @@ config USB_EHCI_FSL | |||
148 | Variation of ARC USB block used in some Freescale chips. | 148 | Variation of ARC USB block used in some Freescale chips. |
149 | 149 | ||
150 | config USB_EHCI_MXC | 150 | config USB_EHCI_MXC |
151 | bool "Support for Freescale i.MX on-chip EHCI USB controller" | 151 | tristate "Support for Freescale i.MX on-chip EHCI USB controller" |
152 | depends on USB_EHCI_HCD && ARCH_MXC | 152 | depends on USB_EHCI_HCD && ARCH_MXC |
153 | select USB_EHCI_ROOT_HUB_TT | 153 | select USB_EHCI_ROOT_HUB_TT |
154 | ---help--- | 154 | ---help--- |
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 1eb4c3006e9e..001fbff2fdef 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile | |||
@@ -26,6 +26,7 @@ obj-$(CONFIG_PCI) += pci-quirks.o | |||
26 | obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o | 26 | obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o |
27 | obj-$(CONFIG_USB_EHCI_PCI) += ehci-pci.o | 27 | obj-$(CONFIG_USB_EHCI_PCI) += ehci-pci.o |
28 | obj-$(CONFIG_USB_EHCI_HCD_PLATFORM) += ehci-platform.o | 28 | obj-$(CONFIG_USB_EHCI_HCD_PLATFORM) += ehci-platform.o |
29 | obj-$(CONFIG_USB_EHCI_MXC) += ehci-mxc.o | ||
29 | 30 | ||
30 | obj-$(CONFIG_USB_OXU210HP_HCD) += oxu210hp-hcd.o | 31 | obj-$(CONFIG_USB_OXU210HP_HCD) += oxu210hp-hcd.o |
31 | obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o | 32 | obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o |
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index fd9b5424b860..d81d2fcbff18 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c | |||
@@ -230,7 +230,7 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, | |||
230 | 230 | ||
231 | switch (phy_mode) { | 231 | switch (phy_mode) { |
232 | case FSL_USB2_PHY_ULPI: | 232 | case FSL_USB2_PHY_ULPI: |
233 | if (pdata->controller_ver) { | 233 | if (pdata->have_sysif_regs && pdata->controller_ver) { |
234 | /* controller version 1.6 or above */ | 234 | /* controller version 1.6 or above */ |
235 | setbits32(non_ehci + FSL_SOC_USB_CTRL, | 235 | setbits32(non_ehci + FSL_SOC_USB_CTRL, |
236 | ULPI_PHY_CLK_SEL); | 236 | ULPI_PHY_CLK_SEL); |
@@ -251,7 +251,7 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, | |||
251 | portsc |= PORT_PTS_PTW; | 251 | portsc |= PORT_PTS_PTW; |
252 | /* fall through */ | 252 | /* fall through */ |
253 | case FSL_USB2_PHY_UTMI: | 253 | case FSL_USB2_PHY_UTMI: |
254 | if (pdata->controller_ver) { | 254 | if (pdata->have_sysif_regs && pdata->controller_ver) { |
255 | /* controller version 1.6 or above */ | 255 | /* controller version 1.6 or above */ |
256 | setbits32(non_ehci + FSL_SOC_USB_CTRL, UTMI_PHY_EN); | 256 | setbits32(non_ehci + FSL_SOC_USB_CTRL, UTMI_PHY_EN); |
257 | mdelay(FSL_UTMI_PHY_DLY); /* Delay for UTMI PHY CLK to | 257 | mdelay(FSL_UTMI_PHY_DLY); /* Delay for UTMI PHY CLK to |
@@ -267,7 +267,8 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, | |||
267 | break; | 267 | break; |
268 | } | 268 | } |
269 | 269 | ||
270 | if (pdata->controller_ver && (phy_mode == FSL_USB2_PHY_ULPI)) { | 270 | if (pdata->have_sysif_regs && pdata->controller_ver && |
271 | (phy_mode == FSL_USB2_PHY_ULPI)) { | ||
271 | /* check PHY_CLK_VALID to get phy clk valid */ | 272 | /* check PHY_CLK_VALID to get phy clk valid */ |
272 | if (!spin_event_timeout(in_be32(non_ehci + FSL_SOC_USB_CTRL) & | 273 | if (!spin_event_timeout(in_be32(non_ehci + FSL_SOC_USB_CTRL) & |
273 | PHY_CLK_VALID, FSL_USB_PHY_CLK_TIMEOUT, 0)) { | 274 | PHY_CLK_VALID, FSL_USB_PHY_CLK_TIMEOUT, 0)) { |
@@ -278,7 +279,7 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, | |||
278 | 279 | ||
279 | ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]); | 280 | ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]); |
280 | 281 | ||
281 | if (phy_mode != FSL_USB2_PHY_ULPI) | 282 | if (phy_mode != FSL_USB2_PHY_ULPI && pdata->have_sysif_regs) |
282 | setbits32(non_ehci + FSL_SOC_USB_CTRL, USB_CTRL_USB_EN); | 283 | setbits32(non_ehci + FSL_SOC_USB_CTRL, USB_CTRL_USB_EN); |
283 | 284 | ||
284 | return 0; | 285 | return 0; |
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index c97503bb0b0e..09537b2f1002 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c | |||
@@ -74,10 +74,6 @@ static const char hcd_name [] = "ehci_hcd"; | |||
74 | #undef VERBOSE_DEBUG | 74 | #undef VERBOSE_DEBUG |
75 | #undef EHCI_URB_TRACE | 75 | #undef EHCI_URB_TRACE |
76 | 76 | ||
77 | #ifdef DEBUG | ||
78 | #define EHCI_STATS | ||
79 | #endif | ||
80 | |||
81 | /* magic numbers that can affect system performance */ | 77 | /* magic numbers that can affect system performance */ |
82 | #define EHCI_TUNE_CERR 3 /* 0-3 qtd retries; 0 == don't stop */ | 78 | #define EHCI_TUNE_CERR 3 /* 0-3 qtd retries; 0 == don't stop */ |
83 | #define EHCI_TUNE_RL_HS 4 /* nak throttle; see 4.9 */ | 79 | #define EHCI_TUNE_RL_HS 4 /* nak throttle; see 4.9 */ |
@@ -1250,11 +1246,6 @@ MODULE_LICENSE ("GPL"); | |||
1250 | #define PLATFORM_DRIVER ehci_fsl_driver | 1246 | #define PLATFORM_DRIVER ehci_fsl_driver |
1251 | #endif | 1247 | #endif |
1252 | 1248 | ||
1253 | #ifdef CONFIG_USB_EHCI_MXC | ||
1254 | #include "ehci-mxc.c" | ||
1255 | #define PLATFORM_DRIVER ehci_mxc_driver | ||
1256 | #endif | ||
1257 | |||
1258 | #ifdef CONFIG_USB_EHCI_SH | 1249 | #ifdef CONFIG_USB_EHCI_SH |
1259 | #include "ehci-sh.c" | 1250 | #include "ehci-sh.c" |
1260 | #define PLATFORM_DRIVER ehci_hcd_sh_driver | 1251 | #define PLATFORM_DRIVER ehci_hcd_sh_driver |
@@ -1352,7 +1343,8 @@ MODULE_LICENSE ("GPL"); | |||
1352 | 1343 | ||
1353 | #if !IS_ENABLED(CONFIG_USB_EHCI_PCI) && \ | 1344 | #if !IS_ENABLED(CONFIG_USB_EHCI_PCI) && \ |
1354 | !IS_ENABLED(CONFIG_USB_EHCI_HCD_PLATFORM) && \ | 1345 | !IS_ENABLED(CONFIG_USB_EHCI_HCD_PLATFORM) && \ |
1355 | !defined(CONFIG_USB_CHIPIDEA_HOST) && \ | 1346 | !IS_ENABLED(CONFIG_USB_CHIPIDEA_HOST) && \ |
1347 | !IS_ENABLED(CONFIG_USB_EHCI_MXC) && \ | ||
1356 | !defined(PLATFORM_DRIVER) && \ | 1348 | !defined(PLATFORM_DRIVER) && \ |
1357 | !defined(PS3_SYSTEM_BUS_DRIVER) && \ | 1349 | !defined(PS3_SYSTEM_BUS_DRIVER) && \ |
1358 | !defined(OF_PLATFORM_DRIVER) && \ | 1350 | !defined(OF_PLATFORM_DRIVER) && \ |
diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c index f7bfc0b898b9..6c56297ea16b 100644 --- a/drivers/usb/host/ehci-mv.c +++ b/drivers/usb/host/ehci-mv.c | |||
@@ -43,7 +43,7 @@ static void ehci_clock_enable(struct ehci_hcd_mv *ehci_mv) | |||
43 | unsigned int i; | 43 | unsigned int i; |
44 | 44 | ||
45 | for (i = 0; i < ehci_mv->clknum; i++) | 45 | for (i = 0; i < ehci_mv->clknum; i++) |
46 | clk_enable(ehci_mv->clk[i]); | 46 | clk_prepare_enable(ehci_mv->clk[i]); |
47 | } | 47 | } |
48 | 48 | ||
49 | static void ehci_clock_disable(struct ehci_hcd_mv *ehci_mv) | 49 | static void ehci_clock_disable(struct ehci_hcd_mv *ehci_mv) |
@@ -51,7 +51,7 @@ static void ehci_clock_disable(struct ehci_hcd_mv *ehci_mv) | |||
51 | unsigned int i; | 51 | unsigned int i; |
52 | 52 | ||
53 | for (i = 0; i < ehci_mv->clknum; i++) | 53 | for (i = 0; i < ehci_mv->clknum; i++) |
54 | clk_disable(ehci_mv->clk[i]); | 54 | clk_disable_unprepare(ehci_mv->clk[i]); |
55 | } | 55 | } |
56 | 56 | ||
57 | static int mv_ehci_enable(struct ehci_hcd_mv *ehci_mv) | 57 | static int mv_ehci_enable(struct ehci_hcd_mv *ehci_mv) |
diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c index ec7f5d2c90de..dedb80bb8d40 100644 --- a/drivers/usb/host/ehci-mxc.c +++ b/drivers/usb/host/ehci-mxc.c | |||
@@ -17,75 +17,38 @@ | |||
17 | * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 17 | * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/io.h> | ||
20 | #include <linux/platform_device.h> | 23 | #include <linux/platform_device.h> |
21 | #include <linux/clk.h> | 24 | #include <linux/clk.h> |
22 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
23 | #include <linux/usb/otg.h> | 26 | #include <linux/usb/otg.h> |
24 | #include <linux/usb/ulpi.h> | 27 | #include <linux/usb/ulpi.h> |
25 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
29 | #include <linux/usb.h> | ||
30 | #include <linux/usb/hcd.h> | ||
26 | 31 | ||
27 | #include <linux/platform_data/usb-ehci-mxc.h> | 32 | #include <linux/platform_data/usb-ehci-mxc.h> |
28 | 33 | ||
29 | #include <asm/mach-types.h> | 34 | #include <asm/mach-types.h> |
30 | 35 | ||
36 | #include "ehci.h" | ||
37 | |||
38 | #define DRIVER_DESC "Freescale On-Chip EHCI Host driver" | ||
39 | |||
40 | static const char hcd_name[] = "ehci-mxc"; | ||
41 | |||
31 | #define ULPI_VIEWPORT_OFFSET 0x170 | 42 | #define ULPI_VIEWPORT_OFFSET 0x170 |
32 | 43 | ||
33 | struct ehci_mxc_priv { | 44 | struct ehci_mxc_priv { |
34 | struct clk *usbclk, *ahbclk, *phyclk; | 45 | struct clk *usbclk, *ahbclk, *phyclk; |
35 | struct usb_hcd *hcd; | ||
36 | }; | 46 | }; |
37 | 47 | ||
38 | /* called during probe() after chip reset completes */ | 48 | static struct hc_driver __read_mostly ehci_mxc_hc_driver; |
39 | static int ehci_mxc_setup(struct usb_hcd *hcd) | ||
40 | { | ||
41 | hcd->has_tt = 1; | ||
42 | |||
43 | return ehci_setup(hcd); | ||
44 | } | ||
45 | 49 | ||
46 | static const struct hc_driver ehci_mxc_hc_driver = { | 50 | static const struct ehci_driver_overrides ehci_mxc_overrides __initdata = { |
47 | .description = hcd_name, | 51 | .extra_priv_size = sizeof(struct ehci_mxc_priv), |
48 | .product_desc = "Freescale On-Chip EHCI Host Controller", | ||
49 | .hcd_priv_size = sizeof(struct ehci_hcd), | ||
50 | |||
51 | /* | ||
52 | * generic hardware linkage | ||
53 | */ | ||
54 | .irq = ehci_irq, | ||
55 | .flags = HCD_USB2 | HCD_MEMORY, | ||
56 | |||
57 | /* | ||
58 | * basic lifecycle operations | ||
59 | */ | ||
60 | .reset = ehci_mxc_setup, | ||
61 | .start = ehci_run, | ||
62 | .stop = ehci_stop, | ||
63 | .shutdown = ehci_shutdown, | ||
64 | |||
65 | /* | ||
66 | * managing i/o requests and associated device resources | ||
67 | */ | ||
68 | .urb_enqueue = ehci_urb_enqueue, | ||
69 | .urb_dequeue = ehci_urb_dequeue, | ||
70 | .endpoint_disable = ehci_endpoint_disable, | ||
71 | .endpoint_reset = ehci_endpoint_reset, | ||
72 | |||
73 | /* | ||
74 | * scheduling support | ||
75 | */ | ||
76 | .get_frame_number = ehci_get_frame, | ||
77 | |||
78 | /* | ||
79 | * root hub support | ||
80 | */ | ||
81 | .hub_status_data = ehci_hub_status_data, | ||
82 | .hub_control = ehci_hub_control, | ||
83 | .bus_suspend = ehci_bus_suspend, | ||
84 | .bus_resume = ehci_bus_resume, | ||
85 | .relinquish_port = ehci_relinquish_port, | ||
86 | .port_handed_over = ehci_port_handed_over, | ||
87 | |||
88 | .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, | ||
89 | }; | 52 | }; |
90 | 53 | ||
91 | static int ehci_mxc_drv_probe(struct platform_device *pdev) | 54 | static int ehci_mxc_drv_probe(struct platform_device *pdev) |
@@ -112,12 +75,6 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev) | |||
112 | if (!hcd) | 75 | if (!hcd) |
113 | return -ENOMEM; | 76 | return -ENOMEM; |
114 | 77 | ||
115 | priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); | ||
116 | if (!priv) { | ||
117 | ret = -ENOMEM; | ||
118 | goto err_alloc; | ||
119 | } | ||
120 | |||
121 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 78 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
122 | if (!res) { | 79 | if (!res) { |
123 | dev_err(dev, "Found HC with no register addr. Check setup!\n"); | 80 | dev_err(dev, "Found HC with no register addr. Check setup!\n"); |
@@ -135,6 +92,10 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev) | |||
135 | goto err_alloc; | 92 | goto err_alloc; |
136 | } | 93 | } |
137 | 94 | ||
95 | hcd->has_tt = 1; | ||
96 | ehci = hcd_to_ehci(hcd); | ||
97 | priv = (struct ehci_mxc_priv *) ehci->priv; | ||
98 | |||
138 | /* enable clocks */ | 99 | /* enable clocks */ |
139 | priv->usbclk = devm_clk_get(&pdev->dev, "ipg"); | 100 | priv->usbclk = devm_clk_get(&pdev->dev, "ipg"); |
140 | if (IS_ERR(priv->usbclk)) { | 101 | if (IS_ERR(priv->usbclk)) { |
@@ -169,8 +130,6 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev) | |||
169 | mdelay(10); | 130 | mdelay(10); |
170 | } | 131 | } |
171 | 132 | ||
172 | ehci = hcd_to_ehci(hcd); | ||
173 | |||
174 | /* EHCI registers start at offset 0x100 */ | 133 | /* EHCI registers start at offset 0x100 */ |
175 | ehci->caps = hcd->regs + 0x100; | 134 | ehci->caps = hcd->regs + 0x100; |
176 | ehci->regs = hcd->regs + 0x100 + | 135 | ehci->regs = hcd->regs + 0x100 + |
@@ -198,8 +157,7 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev) | |||
198 | } | 157 | } |
199 | } | 158 | } |
200 | 159 | ||
201 | priv->hcd = hcd; | 160 | platform_set_drvdata(pdev, hcd); |
202 | platform_set_drvdata(pdev, priv); | ||
203 | 161 | ||
204 | ret = usb_add_hcd(hcd, irq, IRQF_SHARED); | 162 | ret = usb_add_hcd(hcd, irq, IRQF_SHARED); |
205 | if (ret) | 163 | if (ret) |
@@ -244,8 +202,11 @@ err_alloc: | |||
244 | static int __exit ehci_mxc_drv_remove(struct platform_device *pdev) | 202 | static int __exit ehci_mxc_drv_remove(struct platform_device *pdev) |
245 | { | 203 | { |
246 | struct mxc_usbh_platform_data *pdata = pdev->dev.platform_data; | 204 | struct mxc_usbh_platform_data *pdata = pdev->dev.platform_data; |
247 | struct ehci_mxc_priv *priv = platform_get_drvdata(pdev); | 205 | struct usb_hcd *hcd = platform_get_drvdata(pdev); |
248 | struct usb_hcd *hcd = priv->hcd; | 206 | struct ehci_hcd *ehci = hcd_to_ehci(hcd); |
207 | struct ehci_mxc_priv *priv = (struct ehci_mxc_priv *) ehci->priv; | ||
208 | |||
209 | usb_remove_hcd(hcd); | ||
249 | 210 | ||
250 | if (pdata && pdata->exit) | 211 | if (pdata && pdata->exit) |
251 | pdata->exit(pdev); | 212 | pdata->exit(pdev); |
@@ -253,23 +214,20 @@ static int __exit ehci_mxc_drv_remove(struct platform_device *pdev) | |||
253 | if (pdata->otg) | 214 | if (pdata->otg) |
254 | usb_phy_shutdown(pdata->otg); | 215 | usb_phy_shutdown(pdata->otg); |
255 | 216 | ||
256 | usb_remove_hcd(hcd); | ||
257 | usb_put_hcd(hcd); | ||
258 | platform_set_drvdata(pdev, NULL); | ||
259 | |||
260 | clk_disable_unprepare(priv->usbclk); | 217 | clk_disable_unprepare(priv->usbclk); |
261 | clk_disable_unprepare(priv->ahbclk); | 218 | clk_disable_unprepare(priv->ahbclk); |
262 | 219 | ||
263 | if (priv->phyclk) | 220 | if (priv->phyclk) |
264 | clk_disable_unprepare(priv->phyclk); | 221 | clk_disable_unprepare(priv->phyclk); |
265 | 222 | ||
223 | usb_put_hcd(hcd); | ||
224 | platform_set_drvdata(pdev, NULL); | ||
266 | return 0; | 225 | return 0; |
267 | } | 226 | } |
268 | 227 | ||
269 | static void ehci_mxc_drv_shutdown(struct platform_device *pdev) | 228 | static void ehci_mxc_drv_shutdown(struct platform_device *pdev) |
270 | { | 229 | { |
271 | struct ehci_mxc_priv *priv = platform_get_drvdata(pdev); | 230 | struct usb_hcd *hcd = platform_get_drvdata(pdev); |
272 | struct usb_hcd *hcd = priv->hcd; | ||
273 | 231 | ||
274 | if (hcd->driver->shutdown) | 232 | if (hcd->driver->shutdown) |
275 | hcd->driver->shutdown(hcd); | 233 | hcd->driver->shutdown(hcd); |
@@ -279,9 +237,31 @@ MODULE_ALIAS("platform:mxc-ehci"); | |||
279 | 237 | ||
280 | static struct platform_driver ehci_mxc_driver = { | 238 | static struct platform_driver ehci_mxc_driver = { |
281 | .probe = ehci_mxc_drv_probe, | 239 | .probe = ehci_mxc_drv_probe, |
282 | .remove = __exit_p(ehci_mxc_drv_remove), | 240 | .remove = ehci_mxc_drv_remove, |
283 | .shutdown = ehci_mxc_drv_shutdown, | 241 | .shutdown = ehci_mxc_drv_shutdown, |
284 | .driver = { | 242 | .driver = { |
285 | .name = "mxc-ehci", | 243 | .name = "mxc-ehci", |
286 | }, | 244 | }, |
287 | }; | 245 | }; |
246 | |||
247 | static int __init ehci_mxc_init(void) | ||
248 | { | ||
249 | if (usb_disabled()) | ||
250 | return -ENODEV; | ||
251 | |||
252 | pr_info("%s: " DRIVER_DESC "\n", hcd_name); | ||
253 | |||
254 | ehci_init_driver(&ehci_mxc_hc_driver, &ehci_mxc_overrides); | ||
255 | return platform_driver_register(&ehci_mxc_driver); | ||
256 | } | ||
257 | module_init(ehci_mxc_init); | ||
258 | |||
259 | static void __exit ehci_mxc_cleanup(void) | ||
260 | { | ||
261 | platform_driver_unregister(&ehci_mxc_driver); | ||
262 | } | ||
263 | module_exit(ehci_mxc_cleanup); | ||
264 | |||
265 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
266 | MODULE_AUTHOR("Sascha Hauer"); | ||
267 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index dabb20494826..170b9399e09f 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c | |||
@@ -200,6 +200,26 @@ static int ehci_pci_setup(struct usb_hcd *hcd) | |||
200 | break; | 200 | break; |
201 | } | 201 | } |
202 | 202 | ||
203 | /* optional debug port, normally in the first BAR */ | ||
204 | temp = pci_find_capability(pdev, PCI_CAP_ID_DBG); | ||
205 | if (temp) { | ||
206 | pci_read_config_dword(pdev, temp, &temp); | ||
207 | temp >>= 16; | ||
208 | if (((temp >> 13) & 7) == 1) { | ||
209 | u32 hcs_params = ehci_readl(ehci, | ||
210 | &ehci->caps->hcs_params); | ||
211 | |||
212 | temp &= 0x1fff; | ||
213 | ehci->debug = hcd->regs + temp; | ||
214 | temp = ehci_readl(ehci, &ehci->debug->control); | ||
215 | ehci_info(ehci, "debug port %d%s\n", | ||
216 | HCS_DEBUG_PORT(hcs_params), | ||
217 | (temp & DBGP_ENABLED) ? " IN USE" : ""); | ||
218 | if (!(temp & DBGP_ENABLED)) | ||
219 | ehci->debug = NULL; | ||
220 | } | ||
221 | } | ||
222 | |||
203 | retval = ehci_setup(hcd); | 223 | retval = ehci_setup(hcd); |
204 | if (retval) | 224 | if (retval) |
205 | return retval; | 225 | return retval; |
@@ -228,25 +248,6 @@ static int ehci_pci_setup(struct usb_hcd *hcd) | |||
228 | break; | 248 | break; |
229 | } | 249 | } |
230 | 250 | ||
231 | /* optional debug port, normally in the first BAR */ | ||
232 | temp = pci_find_capability(pdev, 0x0a); | ||
233 | if (temp) { | ||
234 | pci_read_config_dword(pdev, temp, &temp); | ||
235 | temp >>= 16; | ||
236 | if ((temp & (3 << 13)) == (1 << 13)) { | ||
237 | temp &= 0x1fff; | ||
238 | ehci->debug = hcd->regs + temp; | ||
239 | temp = ehci_readl(ehci, &ehci->debug->control); | ||
240 | ehci_info(ehci, "debug port %d%s\n", | ||
241 | HCS_DEBUG_PORT(ehci->hcs_params), | ||
242 | (temp & DBGP_ENABLED) | ||
243 | ? " IN USE" | ||
244 | : ""); | ||
245 | if (!(temp & DBGP_ENABLED)) | ||
246 | ehci->debug = NULL; | ||
247 | } | ||
248 | } | ||
249 | |||
250 | /* at least the Genesys GL880S needs fixup here */ | 251 | /* at least the Genesys GL880S needs fixup here */ |
251 | temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params); | 252 | temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params); |
252 | temp &= 0x0f; | 253 | temp &= 0x0f; |
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 9dadc7118d68..36c3a8210595 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h | |||
@@ -38,6 +38,10 @@ typedef __u16 __bitwise __hc16; | |||
38 | #endif | 38 | #endif |
39 | 39 | ||
40 | /* statistics can be kept for tuning/monitoring */ | 40 | /* statistics can be kept for tuning/monitoring */ |
41 | #ifdef DEBUG | ||
42 | #define EHCI_STATS | ||
43 | #endif | ||
44 | |||
41 | struct ehci_stats { | 45 | struct ehci_stats { |
42 | /* irq usage */ | 46 | /* irq usage */ |
43 | unsigned long normal; | 47 | unsigned long normal; |
@@ -221,6 +225,9 @@ struct ehci_hcd { /* one per controller */ | |||
221 | #ifdef DEBUG | 225 | #ifdef DEBUG |
222 | struct dentry *debug_dir; | 226 | struct dentry *debug_dir; |
223 | #endif | 227 | #endif |
228 | |||
229 | /* platform-specific data -- must come last */ | ||
230 | unsigned long priv[0] __aligned(sizeof(s64)); | ||
224 | }; | 231 | }; |
225 | 232 | ||
226 | /* convert between an HCD pointer and the corresponding EHCI_HCD */ | 233 | /* convert between an HCD pointer and the corresponding EHCI_HCD */ |
diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c index 5105127c1d4b..11e0b79ff9d5 100644 --- a/drivers/usb/host/fsl-mph-dr-of.c +++ b/drivers/usb/host/fsl-mph-dr-of.c | |||
@@ -142,6 +142,9 @@ static int usb_get_ver_info(struct device_node *np) | |||
142 | return ver; | 142 | return ver; |
143 | } | 143 | } |
144 | 144 | ||
145 | if (of_device_is_compatible(np, "fsl,mpc5121-usb2-dr")) | ||
146 | return FSL_USB_VER_OLD; | ||
147 | |||
145 | if (of_device_is_compatible(np, "fsl-usb2-mph")) { | 148 | if (of_device_is_compatible(np, "fsl-usb2-mph")) { |
146 | if (of_device_is_compatible(np, "fsl-usb2-mph-v1.6")) | 149 | if (of_device_is_compatible(np, "fsl-usb2-mph-v1.6")) |
147 | ver = FSL_USB_VER_1_6; | 150 | ver = FSL_USB_VER_1_6; |
diff --git a/drivers/usb/host/imx21-hcd.c b/drivers/usb/host/imx21-hcd.c index bd6a7447ccc9..f0ebe8e7c58b 100644 --- a/drivers/usb/host/imx21-hcd.c +++ b/drivers/usb/host/imx21-hcd.c | |||
@@ -58,6 +58,7 @@ | |||
58 | #include <linux/usb.h> | 58 | #include <linux/usb.h> |
59 | #include <linux/usb/hcd.h> | 59 | #include <linux/usb/hcd.h> |
60 | #include <linux/dma-mapping.h> | 60 | #include <linux/dma-mapping.h> |
61 | #include <linux/module.h> | ||
61 | 62 | ||
62 | #include "imx21-hcd.h" | 63 | #include "imx21-hcd.h" |
63 | 64 | ||
diff --git a/drivers/usb/host/ohci-tmio.c b/drivers/usb/host/ohci-tmio.c index d370245a4ee2..5e3a6deb62b1 100644 --- a/drivers/usb/host/ohci-tmio.c +++ b/drivers/usb/host/ohci-tmio.c | |||
@@ -128,7 +128,8 @@ static void tmio_start_hc(struct platform_device *dev) | |||
128 | tmio_iowrite8(2, tmio->ccr + CCR_INTC); | 128 | tmio_iowrite8(2, tmio->ccr + CCR_INTC); |
129 | 129 | ||
130 | dev_info(&dev->dev, "revision %d @ 0x%08llx, irq %d\n", | 130 | dev_info(&dev->dev, "revision %d @ 0x%08llx, irq %d\n", |
131 | tmio_ioread8(tmio->ccr + CCR_REVID), hcd->rsrc_start, hcd->irq); | 131 | tmio_ioread8(tmio->ccr + CCR_REVID), |
132 | (u64) hcd->rsrc_start, hcd->irq); | ||
132 | } | 133 | } |
133 | 134 | ||
134 | static int ohci_tmio_start(struct usb_hcd *hcd) | 135 | static int ohci_tmio_start(struct usb_hcd *hcd) |
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 4b9e9aba2665..4f64d24eebc8 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c | |||
@@ -447,6 +447,10 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd) | |||
447 | return IRQ_NONE; | 447 | return IRQ_NONE; |
448 | uhci_writew(uhci, status, USBSTS); /* Clear it */ | 448 | uhci_writew(uhci, status, USBSTS); /* Clear it */ |
449 | 449 | ||
450 | spin_lock(&uhci->lock); | ||
451 | if (unlikely(!uhci->is_initialized)) /* not yet configured */ | ||
452 | goto done; | ||
453 | |||
450 | if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) { | 454 | if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) { |
451 | if (status & USBSTS_HSE) | 455 | if (status & USBSTS_HSE) |
452 | dev_err(uhci_dev(uhci), "host system error, " | 456 | dev_err(uhci_dev(uhci), "host system error, " |
@@ -455,7 +459,6 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd) | |||
455 | dev_err(uhci_dev(uhci), "host controller process " | 459 | dev_err(uhci_dev(uhci), "host controller process " |
456 | "error, something bad happened!\n"); | 460 | "error, something bad happened!\n"); |
457 | if (status & USBSTS_HCH) { | 461 | if (status & USBSTS_HCH) { |
458 | spin_lock(&uhci->lock); | ||
459 | if (uhci->rh_state >= UHCI_RH_RUNNING) { | 462 | if (uhci->rh_state >= UHCI_RH_RUNNING) { |
460 | dev_err(uhci_dev(uhci), | 463 | dev_err(uhci_dev(uhci), |
461 | "host controller halted, " | 464 | "host controller halted, " |
@@ -473,15 +476,15 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd) | |||
473 | * pending unlinks */ | 476 | * pending unlinks */ |
474 | mod_timer(&hcd->rh_timer, jiffies); | 477 | mod_timer(&hcd->rh_timer, jiffies); |
475 | } | 478 | } |
476 | spin_unlock(&uhci->lock); | ||
477 | } | 479 | } |
478 | } | 480 | } |
479 | 481 | ||
480 | if (status & USBSTS_RD) | 482 | if (status & USBSTS_RD) { |
483 | spin_unlock(&uhci->lock); | ||
481 | usb_hcd_poll_rh_status(hcd); | 484 | usb_hcd_poll_rh_status(hcd); |
482 | else { | 485 | } else { |
483 | spin_lock(&uhci->lock); | ||
484 | uhci_scan_schedule(uhci); | 486 | uhci_scan_schedule(uhci); |
487 | done: | ||
485 | spin_unlock(&uhci->lock); | 488 | spin_unlock(&uhci->lock); |
486 | } | 489 | } |
487 | 490 | ||
@@ -662,9 +665,9 @@ static int uhci_start(struct usb_hcd *hcd) | |||
662 | */ | 665 | */ |
663 | mb(); | 666 | mb(); |
664 | 667 | ||
668 | spin_lock_irq(&uhci->lock); | ||
665 | configure_hc(uhci); | 669 | configure_hc(uhci); |
666 | uhci->is_initialized = 1; | 670 | uhci->is_initialized = 1; |
667 | spin_lock_irq(&uhci->lock); | ||
668 | start_rh(uhci); | 671 | start_rh(uhci); |
669 | spin_unlock_irq(&uhci->lock); | 672 | spin_unlock_irq(&uhci->lock); |
670 | return 0; | 673 | return 0; |
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index a686cf4905bb..68914429482f 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c | |||
@@ -761,12 +761,39 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
761 | break; | 761 | break; |
762 | case USB_PORT_FEAT_LINK_STATE: | 762 | case USB_PORT_FEAT_LINK_STATE: |
763 | temp = xhci_readl(xhci, port_array[wIndex]); | 763 | temp = xhci_readl(xhci, port_array[wIndex]); |
764 | |||
765 | /* Disable port */ | ||
766 | if (link_state == USB_SS_PORT_LS_SS_DISABLED) { | ||
767 | xhci_dbg(xhci, "Disable port %d\n", wIndex); | ||
768 | temp = xhci_port_state_to_neutral(temp); | ||
769 | /* | ||
770 | * Clear all change bits, so that we get a new | ||
771 | * connection event. | ||
772 | */ | ||
773 | temp |= PORT_CSC | PORT_PEC | PORT_WRC | | ||
774 | PORT_OCC | PORT_RC | PORT_PLC | | ||
775 | PORT_CEC; | ||
776 | xhci_writel(xhci, temp | PORT_PE, | ||
777 | port_array[wIndex]); | ||
778 | temp = xhci_readl(xhci, port_array[wIndex]); | ||
779 | break; | ||
780 | } | ||
781 | |||
782 | /* Put link in RxDetect (enable port) */ | ||
783 | if (link_state == USB_SS_PORT_LS_RX_DETECT) { | ||
784 | xhci_dbg(xhci, "Enable port %d\n", wIndex); | ||
785 | xhci_set_link_state(xhci, port_array, wIndex, | ||
786 | link_state); | ||
787 | temp = xhci_readl(xhci, port_array[wIndex]); | ||
788 | break; | ||
789 | } | ||
790 | |||
764 | /* Software should not attempt to set | 791 | /* Software should not attempt to set |
765 | * port link state above '5' (Rx.Detect) and the port | 792 | * port link state above '3' (U3) and the port |
766 | * must be enabled. | 793 | * must be enabled. |
767 | */ | 794 | */ |
768 | if ((temp & PORT_PE) == 0 || | 795 | if ((temp & PORT_PE) == 0 || |
769 | (link_state > USB_SS_PORT_LS_RX_DETECT)) { | 796 | (link_state > USB_SS_PORT_LS_U3)) { |
770 | xhci_warn(xhci, "Cannot set link state.\n"); | 797 | xhci_warn(xhci, "Cannot set link state.\n"); |
771 | goto error; | 798 | goto error; |
772 | } | 799 | } |
@@ -957,6 +984,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) | |||
957 | int max_ports; | 984 | int max_ports; |
958 | __le32 __iomem **port_array; | 985 | __le32 __iomem **port_array; |
959 | struct xhci_bus_state *bus_state; | 986 | struct xhci_bus_state *bus_state; |
987 | bool reset_change = false; | ||
960 | 988 | ||
961 | max_ports = xhci_get_ports(hcd, &port_array); | 989 | max_ports = xhci_get_ports(hcd, &port_array); |
962 | bus_state = &xhci->bus_state[hcd_index(hcd)]; | 990 | bus_state = &xhci->bus_state[hcd_index(hcd)]; |
@@ -988,6 +1016,12 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) | |||
988 | buf[(i + 1) / 8] |= 1 << (i + 1) % 8; | 1016 | buf[(i + 1) / 8] |= 1 << (i + 1) % 8; |
989 | status = 1; | 1017 | status = 1; |
990 | } | 1018 | } |
1019 | if ((temp & PORT_RC)) | ||
1020 | reset_change = true; | ||
1021 | } | ||
1022 | if (!status && !reset_change) { | ||
1023 | xhci_dbg(xhci, "%s: stopping port polling.\n", __func__); | ||
1024 | clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); | ||
991 | } | 1025 | } |
992 | spin_unlock_irqrestore(&xhci->lock, flags); | 1026 | spin_unlock_irqrestore(&xhci->lock, flags); |
993 | return status ? retval : 0; | 1027 | return status ? retval : 0; |
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index fb51c7085ad0..35616ffbe3ae 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c | |||
@@ -1250,6 +1250,8 @@ static unsigned int xhci_microframes_to_exponent(struct usb_device *udev, | |||
1250 | static unsigned int xhci_parse_microframe_interval(struct usb_device *udev, | 1250 | static unsigned int xhci_parse_microframe_interval(struct usb_device *udev, |
1251 | struct usb_host_endpoint *ep) | 1251 | struct usb_host_endpoint *ep) |
1252 | { | 1252 | { |
1253 | if (ep->desc.bInterval == 0) | ||
1254 | return 0; | ||
1253 | return xhci_microframes_to_exponent(udev, ep, | 1255 | return xhci_microframes_to_exponent(udev, ep, |
1254 | ep->desc.bInterval, 0, 15); | 1256 | ep->desc.bInterval, 0, 15); |
1255 | } | 1257 | } |
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index cbb44b7b9d65..59fb5c677dbe 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c | |||
@@ -1725,6 +1725,15 @@ cleanup: | |||
1725 | if (bogus_port_status) | 1725 | if (bogus_port_status) |
1726 | return; | 1726 | return; |
1727 | 1727 | ||
1728 | /* | ||
1729 | * xHCI port-status-change events occur when the "or" of all the | ||
1730 | * status-change bits in the portsc register changes from 0 to 1. | ||
1731 | * New status changes won't cause an event if any other change | ||
1732 | * bits are still set. When an event occurs, switch over to | ||
1733 | * polling to avoid losing status changes. | ||
1734 | */ | ||
1735 | xhci_dbg(xhci, "%s: starting port polling.\n", __func__); | ||
1736 | set_bit(HCD_FLAG_POLL_RH, &hcd->flags); | ||
1728 | spin_unlock(&xhci->lock); | 1737 | spin_unlock(&xhci->lock); |
1729 | /* Pass this up to the core */ | 1738 | /* Pass this up to the core */ |
1730 | usb_hcd_poll_rh_status(hcd); | 1739 | usb_hcd_poll_rh_status(hcd); |
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 5c72c431bab1..f1f01a834ba7 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c | |||
@@ -884,6 +884,11 @@ int xhci_suspend(struct xhci_hcd *xhci) | |||
884 | xhci->shared_hcd->state != HC_STATE_SUSPENDED) | 884 | xhci->shared_hcd->state != HC_STATE_SUSPENDED) |
885 | return -EINVAL; | 885 | return -EINVAL; |
886 | 886 | ||
887 | /* Don't poll the roothubs on bus suspend. */ | ||
888 | xhci_dbg(xhci, "%s: stopping port polling.\n", __func__); | ||
889 | clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); | ||
890 | del_timer_sync(&hcd->rh_timer); | ||
891 | |||
887 | spin_lock_irq(&xhci->lock); | 892 | spin_lock_irq(&xhci->lock); |
888 | clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); | 893 | clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); |
889 | clear_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags); | 894 | clear_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags); |
@@ -1069,6 +1074,11 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) | |||
1069 | if (xhci->quirks & XHCI_COMP_MODE_QUIRK) | 1074 | if (xhci->quirks & XHCI_COMP_MODE_QUIRK) |
1070 | compliance_mode_recovery_timer_init(xhci); | 1075 | compliance_mode_recovery_timer_init(xhci); |
1071 | 1076 | ||
1077 | /* Re-enable port polling. */ | ||
1078 | xhci_dbg(xhci, "%s: starting port polling.\n", __func__); | ||
1079 | set_bit(HCD_FLAG_POLL_RH, &hcd->flags); | ||
1080 | usb_hcd_poll_rh_status(hcd); | ||
1081 | |||
1072 | return retval; | 1082 | return retval; |
1073 | } | 1083 | } |
1074 | #endif /* CONFIG_PM */ | 1084 | #endif /* CONFIG_PM */ |
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index 7667b12f2ff5..268148de9714 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c | |||
@@ -2179,7 +2179,7 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf) | |||
2179 | if (dev->out_pipe == 0 || !param->length || param->sglen < 4) | 2179 | if (dev->out_pipe == 0 || !param->length || param->sglen < 4) |
2180 | break; | 2180 | break; |
2181 | retval = 0; | 2181 | retval = 0; |
2182 | dev_info(&intf->dev, "TEST 17: unlink from %d queues of " | 2182 | dev_info(&intf->dev, "TEST 24: unlink from %d queues of " |
2183 | "%d %d-byte writes\n", | 2183 | "%d %d-byte writes\n", |
2184 | param->iterations, param->sglen, param->length); | 2184 | param->iterations, param->sglen, param->length); |
2185 | for (i = param->iterations; retval == 0 && i > 0; --i) { | 2185 | for (i = param->iterations; retval == 0 && i > 0; --i) { |
diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c index 0968dd7a859d..f522000e8f06 100644 --- a/drivers/usb/musb/cppi_dma.c +++ b/drivers/usb/musb/cppi_dma.c | |||
@@ -105,7 +105,7 @@ static void cppi_reset_tx(struct cppi_tx_stateram __iomem *tx, u32 ptr) | |||
105 | musb_writel(&tx->tx_complete, 0, ptr); | 105 | musb_writel(&tx->tx_complete, 0, ptr); |
106 | } | 106 | } |
107 | 107 | ||
108 | static void __init cppi_pool_init(struct cppi *cppi, struct cppi_channel *c) | 108 | static void cppi_pool_init(struct cppi *cppi, struct cppi_channel *c) |
109 | { | 109 | { |
110 | int j; | 110 | int j; |
111 | 111 | ||
@@ -150,7 +150,7 @@ static void cppi_pool_free(struct cppi_channel *c) | |||
150 | c->last_processed = NULL; | 150 | c->last_processed = NULL; |
151 | } | 151 | } |
152 | 152 | ||
153 | static int __init cppi_controller_start(struct dma_controller *c) | 153 | static int cppi_controller_start(struct dma_controller *c) |
154 | { | 154 | { |
155 | struct cppi *controller; | 155 | struct cppi *controller; |
156 | void __iomem *tibase; | 156 | void __iomem *tibase; |
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index f1c6c5470b92..fd3486745e64 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c | |||
@@ -2298,10 +2298,7 @@ static int __init musb_init(void) | |||
2298 | if (usb_disabled()) | 2298 | if (usb_disabled()) |
2299 | return 0; | 2299 | return 0; |
2300 | 2300 | ||
2301 | pr_info("%s: version " MUSB_VERSION ", " | 2301 | pr_info("%s: version " MUSB_VERSION ", ?dma?, otg (peripheral+host)\n", |
2302 | "?dma?" | ||
2303 | ", " | ||
2304 | "otg (peripheral+host)", | ||
2305 | musb_driver_name); | 2302 | musb_driver_name); |
2306 | return platform_driver_register(&musb_driver); | 2303 | return platform_driver_register(&musb_driver); |
2307 | } | 2304 | } |
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index e6f2ae8368bb..f7d764de6fda 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c | |||
@@ -134,6 +134,11 @@ static const resource_size_t dsps_control_module_phys[] = { | |||
134 | DSPS_AM33XX_CONTROL_MODULE_PHYS_1, | 134 | DSPS_AM33XX_CONTROL_MODULE_PHYS_1, |
135 | }; | 135 | }; |
136 | 136 | ||
137 | #define USBPHY_CM_PWRDN (1 << 0) | ||
138 | #define USBPHY_OTG_PWRDN (1 << 1) | ||
139 | #define USBPHY_OTGVDET_EN (1 << 19) | ||
140 | #define USBPHY_OTGSESSEND_EN (1 << 20) | ||
141 | |||
137 | /** | 142 | /** |
138 | * musb_dsps_phy_control - phy on/off | 143 | * musb_dsps_phy_control - phy on/off |
139 | * @glue: struct dsps_glue * | 144 | * @glue: struct dsps_glue * |
diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig index 6223062d5d1b..37962c99ff1e 100644 --- a/drivers/usb/otg/Kconfig +++ b/drivers/usb/otg/Kconfig | |||
@@ -110,7 +110,7 @@ config AB8500_USB | |||
110 | 110 | ||
111 | config FSL_USB2_OTG | 111 | config FSL_USB2_OTG |
112 | bool "Freescale USB OTG Transceiver Driver" | 112 | bool "Freescale USB OTG Transceiver Driver" |
113 | depends on USB_EHCI_FSL && USB_GADGET_FSL_USB2 && USB_SUSPEND | 113 | depends on USB_EHCI_FSL && USB_FSL_USB2 && USB_SUSPEND |
114 | select USB_OTG | 114 | select USB_OTG |
115 | select USB_OTG_UTILS | 115 | select USB_OTG_UTILS |
116 | help | 116 | help |
diff --git a/drivers/usb/otg/mv_otg.c b/drivers/usb/otg/mv_otg.c index 1dd57504186d..eace975991a8 100644 --- a/drivers/usb/otg/mv_otg.c +++ b/drivers/usb/otg/mv_otg.c | |||
@@ -240,7 +240,7 @@ static void otg_clock_enable(struct mv_otg *mvotg) | |||
240 | unsigned int i; | 240 | unsigned int i; |
241 | 241 | ||
242 | for (i = 0; i < mvotg->clknum; i++) | 242 | for (i = 0; i < mvotg->clknum; i++) |
243 | clk_enable(mvotg->clk[i]); | 243 | clk_prepare_enable(mvotg->clk[i]); |
244 | } | 244 | } |
245 | 245 | ||
246 | static void otg_clock_disable(struct mv_otg *mvotg) | 246 | static void otg_clock_disable(struct mv_otg *mvotg) |
@@ -248,7 +248,7 @@ static void otg_clock_disable(struct mv_otg *mvotg) | |||
248 | unsigned int i; | 248 | unsigned int i; |
249 | 249 | ||
250 | for (i = 0; i < mvotg->clknum; i++) | 250 | for (i = 0; i < mvotg->clknum; i++) |
251 | clk_disable(mvotg->clk[i]); | 251 | clk_disable_unprepare(mvotg->clk[i]); |
252 | } | 252 | } |
253 | 253 | ||
254 | static int mv_otg_enable_internal(struct mv_otg *mvotg) | 254 | static int mv_otg_enable_internal(struct mv_otg *mvotg) |
diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index dd41f61893ef..f2985cd88021 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c | |||
@@ -545,15 +545,6 @@ static int usbhsg_pipe_disable(struct usbhsg_uep *uep) | |||
545 | return 0; | 545 | return 0; |
546 | } | 546 | } |
547 | 547 | ||
548 | static void usbhsg_uep_init(struct usbhsg_gpriv *gpriv) | ||
549 | { | ||
550 | int i; | ||
551 | struct usbhsg_uep *uep; | ||
552 | |||
553 | usbhsg_for_each_uep_with_dcp(uep, gpriv, i) | ||
554 | uep->pipe = NULL; | ||
555 | } | ||
556 | |||
557 | /* | 548 | /* |
558 | * | 549 | * |
559 | * usb_ep_ops | 550 | * usb_ep_ops |
@@ -610,7 +601,12 @@ static int usbhsg_ep_disable(struct usb_ep *ep) | |||
610 | { | 601 | { |
611 | struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep); | 602 | struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep); |
612 | 603 | ||
613 | return usbhsg_pipe_disable(uep); | 604 | usbhsg_pipe_disable(uep); |
605 | |||
606 | uep->pipe->mod_private = NULL; | ||
607 | uep->pipe = NULL; | ||
608 | |||
609 | return 0; | ||
614 | } | 610 | } |
615 | 611 | ||
616 | static struct usb_request *usbhsg_ep_alloc_request(struct usb_ep *ep, | 612 | static struct usb_request *usbhsg_ep_alloc_request(struct usb_ep *ep, |
@@ -761,9 +757,8 @@ static int usbhsg_try_start(struct usbhs_priv *priv, u32 status) | |||
761 | usbhs_pipe_init(priv, | 757 | usbhs_pipe_init(priv, |
762 | usbhsg_dma_map_ctrl); | 758 | usbhsg_dma_map_ctrl); |
763 | usbhs_fifo_init(priv); | 759 | usbhs_fifo_init(priv); |
764 | usbhsg_uep_init(gpriv); | ||
765 | 760 | ||
766 | /* dcp init */ | 761 | /* dcp init instead of usbhsg_ep_enable() */ |
767 | dcp->pipe = usbhs_dcp_malloc(priv); | 762 | dcp->pipe = usbhs_dcp_malloc(priv); |
768 | dcp->pipe->mod_private = dcp; | 763 | dcp->pipe->mod_private = dcp; |
769 | usbhs_pipe_config_update(dcp->pipe, 0, 0, 64); | 764 | usbhs_pipe_config_update(dcp->pipe, 0, 0, 64); |
@@ -825,7 +820,7 @@ static int usbhsg_try_stop(struct usbhs_priv *priv, u32 status) | |||
825 | usbhs_sys_set_test_mode(priv, 0); | 820 | usbhs_sys_set_test_mode(priv, 0); |
826 | usbhs_sys_function_ctrl(priv, 0); | 821 | usbhs_sys_function_ctrl(priv, 0); |
827 | 822 | ||
828 | usbhsg_pipe_disable(dcp); | 823 | usbhsg_ep_disable(&dcp->ep); |
829 | 824 | ||
830 | dev_dbg(dev, "stop gadget\n"); | 825 | dev_dbg(dev, "stop gadget\n"); |
831 | 826 | ||
@@ -998,6 +993,7 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv) | |||
998 | */ | 993 | */ |
999 | usbhsg_for_each_uep_with_dcp(uep, gpriv, i) { | 994 | usbhsg_for_each_uep_with_dcp(uep, gpriv, i) { |
1000 | uep->gpriv = gpriv; | 995 | uep->gpriv = gpriv; |
996 | uep->pipe = NULL; | ||
1001 | snprintf(uep->ep_name, EP_NAME_SIZE, "ep%d", i); | 997 | snprintf(uep->ep_name, EP_NAME_SIZE, "ep%d", i); |
1002 | 998 | ||
1003 | uep->ep.name = uep->ep_name; | 999 | uep->ep.name = uep->ep_name; |
diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index 3d3cd6ca2689..b86815421c8d 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c | |||
@@ -661,9 +661,10 @@ static void usbhsh_queue_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt) | |||
661 | status = -ESHUTDOWN; | 661 | status = -ESHUTDOWN; |
662 | 662 | ||
663 | urb->actual_length = pkt->actual; | 663 | urb->actual_length = pkt->actual; |
664 | usbhsh_ureq_free(hpriv, ureq); | ||
665 | 664 | ||
666 | usbhsh_endpoint_sequence_save(hpriv, urb, pkt); | 665 | usbhsh_endpoint_sequence_save(hpriv, urb, pkt); |
666 | usbhsh_ureq_free(hpriv, ureq); | ||
667 | |||
667 | usbhsh_pipe_detach(hpriv, usbhsh_ep_to_uep(urb->ep)); | 668 | usbhsh_pipe_detach(hpriv, usbhsh_ep_to_uep(urb->ep)); |
668 | 669 | ||
669 | usb_hcd_unlink_urb_from_ep(hcd, urb); | 670 | usb_hcd_unlink_urb_from_ep(hcd, urb); |
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 0a373b3ae96a..ba68835d06a6 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c | |||
@@ -875,6 +875,8 @@ static struct usb_device_id id_table_combined [] = { | |||
875 | { USB_DEVICE(FTDI_VID, FTDI_DISTORTEC_JTAG_LOCK_PICK_PID), | 875 | { USB_DEVICE(FTDI_VID, FTDI_DISTORTEC_JTAG_LOCK_PICK_PID), |
876 | .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, | 876 | .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, |
877 | { USB_DEVICE(FTDI_VID, FTDI_LUMEL_PD12_PID) }, | 877 | { USB_DEVICE(FTDI_VID, FTDI_LUMEL_PD12_PID) }, |
878 | /* Crucible Devices */ | ||
879 | { USB_DEVICE(FTDI_VID, FTDI_CT_COMET_PID) }, | ||
878 | { }, /* Optional parameter entry */ | 880 | { }, /* Optional parameter entry */ |
879 | { } /* Terminating entry */ | 881 | { } /* Terminating entry */ |
880 | }; | 882 | }; |
diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 049b6e715fa4..fa5d56038276 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h | |||
@@ -1259,3 +1259,9 @@ | |||
1259 | * ATI command output: Cinterion MC55i | 1259 | * ATI command output: Cinterion MC55i |
1260 | */ | 1260 | */ |
1261 | #define FTDI_CINTERION_MC55I_PID 0xA951 | 1261 | #define FTDI_CINTERION_MC55I_PID 0xA951 |
1262 | |||
1263 | /* | ||
1264 | * Product: Comet Caller ID decoder | ||
1265 | * Manufacturer: Crucible Technologies | ||
1266 | */ | ||
1267 | #define FTDI_CT_COMET_PID 0x8e08 | ||
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 58184f3de686..82afc4d6a327 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c | |||
@@ -530,6 +530,9 @@ static void chase_port(struct edgeport_port *port, unsigned long timeout, | |||
530 | wait_queue_t wait; | 530 | wait_queue_t wait; |
531 | unsigned long flags; | 531 | unsigned long flags; |
532 | 532 | ||
533 | if (!tty) | ||
534 | return; | ||
535 | |||
533 | if (!timeout) | 536 | if (!timeout) |
534 | timeout = (HZ * EDGE_CLOSING_WAIT)/100; | 537 | timeout = (HZ * EDGE_CLOSING_WAIT)/100; |
535 | 538 | ||
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index e6f87b76c715..0d9dac9e7f93 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c | |||
@@ -288,6 +288,7 @@ static void option_instat_callback(struct urb *urb); | |||
288 | #define ALCATEL_VENDOR_ID 0x1bbb | 288 | #define ALCATEL_VENDOR_ID 0x1bbb |
289 | #define ALCATEL_PRODUCT_X060S_X200 0x0000 | 289 | #define ALCATEL_PRODUCT_X060S_X200 0x0000 |
290 | #define ALCATEL_PRODUCT_X220_X500D 0x0017 | 290 | #define ALCATEL_PRODUCT_X220_X500D 0x0017 |
291 | #define ALCATEL_PRODUCT_L100V 0x011e | ||
291 | 292 | ||
292 | #define PIRELLI_VENDOR_ID 0x1266 | 293 | #define PIRELLI_VENDOR_ID 0x1266 |
293 | #define PIRELLI_PRODUCT_C100_1 0x1002 | 294 | #define PIRELLI_PRODUCT_C100_1 0x1002 |
@@ -429,9 +430,12 @@ static void option_instat_callback(struct urb *urb); | |||
429 | #define MEDIATEK_VENDOR_ID 0x0e8d | 430 | #define MEDIATEK_VENDOR_ID 0x0e8d |
430 | #define MEDIATEK_PRODUCT_DC_1COM 0x00a0 | 431 | #define MEDIATEK_PRODUCT_DC_1COM 0x00a0 |
431 | #define MEDIATEK_PRODUCT_DC_4COM 0x00a5 | 432 | #define MEDIATEK_PRODUCT_DC_4COM 0x00a5 |
433 | #define MEDIATEK_PRODUCT_DC_4COM2 0x00a7 | ||
432 | #define MEDIATEK_PRODUCT_DC_5COM 0x00a4 | 434 | #define MEDIATEK_PRODUCT_DC_5COM 0x00a4 |
433 | #define MEDIATEK_PRODUCT_7208_1COM 0x7101 | 435 | #define MEDIATEK_PRODUCT_7208_1COM 0x7101 |
434 | #define MEDIATEK_PRODUCT_7208_2COM 0x7102 | 436 | #define MEDIATEK_PRODUCT_7208_2COM 0x7102 |
437 | #define MEDIATEK_PRODUCT_7103_2COM 0x7103 | ||
438 | #define MEDIATEK_PRODUCT_7106_2COM 0x7106 | ||
435 | #define MEDIATEK_PRODUCT_FP_1COM 0x0003 | 439 | #define MEDIATEK_PRODUCT_FP_1COM 0x0003 |
436 | #define MEDIATEK_PRODUCT_FP_2COM 0x0023 | 440 | #define MEDIATEK_PRODUCT_FP_2COM 0x0023 |
437 | #define MEDIATEK_PRODUCT_FPDC_1COM 0x0043 | 441 | #define MEDIATEK_PRODUCT_FPDC_1COM 0x0043 |
@@ -441,6 +445,14 @@ static void option_instat_callback(struct urb *urb); | |||
441 | #define CELLIENT_VENDOR_ID 0x2692 | 445 | #define CELLIENT_VENDOR_ID 0x2692 |
442 | #define CELLIENT_PRODUCT_MEN200 0x9005 | 446 | #define CELLIENT_PRODUCT_MEN200 0x9005 |
443 | 447 | ||
448 | /* Hyundai Petatel Inc. products */ | ||
449 | #define PETATEL_VENDOR_ID 0x1ff4 | ||
450 | #define PETATEL_PRODUCT_NP10T 0x600e | ||
451 | |||
452 | /* TP-LINK Incorporated products */ | ||
453 | #define TPLINK_VENDOR_ID 0x2357 | ||
454 | #define TPLINK_PRODUCT_MA180 0x0201 | ||
455 | |||
444 | /* some devices interfaces need special handling due to a number of reasons */ | 456 | /* some devices interfaces need special handling due to a number of reasons */ |
445 | enum option_blacklist_reason { | 457 | enum option_blacklist_reason { |
446 | OPTION_BLACKLIST_NONE = 0, | 458 | OPTION_BLACKLIST_NONE = 0, |
@@ -922,8 +934,10 @@ static const struct usb_device_id option_ids[] = { | |||
922 | { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0254, 0xff, 0xff, 0xff) }, | 934 | { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0254, 0xff, 0xff, 0xff) }, |
923 | { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0257, 0xff, 0xff, 0xff), /* ZTE MF821 */ | 935 | { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0257, 0xff, 0xff, 0xff), /* ZTE MF821 */ |
924 | .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, | 936 | .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, |
925 | { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0265, 0xff, 0xff, 0xff) }, | 937 | { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0265, 0xff, 0xff, 0xff), /* ONDA MT8205 */ |
926 | { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0284, 0xff, 0xff, 0xff) }, | 938 | .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, |
939 | { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0284, 0xff, 0xff, 0xff), /* ZTE MF880 */ | ||
940 | .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, | ||
927 | { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0317, 0xff, 0xff, 0xff) }, | 941 | { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0317, 0xff, 0xff, 0xff) }, |
928 | { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0326, 0xff, 0xff, 0xff), | 942 | { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0326, 0xff, 0xff, 0xff), |
929 | .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, | 943 | .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, |
@@ -1190,6 +1204,8 @@ static const struct usb_device_id option_ids[] = { | |||
1190 | .driver_info = (kernel_ulong_t)&alcatel_x200_blacklist | 1204 | .driver_info = (kernel_ulong_t)&alcatel_x200_blacklist |
1191 | }, | 1205 | }, |
1192 | { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X220_X500D) }, | 1206 | { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X220_X500D) }, |
1207 | { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_L100V), | ||
1208 | .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, | ||
1193 | { USB_DEVICE(AIRPLUS_VENDOR_ID, AIRPLUS_PRODUCT_MCD650) }, | 1209 | { USB_DEVICE(AIRPLUS_VENDOR_ID, AIRPLUS_PRODUCT_MCD650) }, |
1194 | { USB_DEVICE(TLAYTECH_VENDOR_ID, TLAYTECH_PRODUCT_TEU800) }, | 1210 | { USB_DEVICE(TLAYTECH_VENDOR_ID, TLAYTECH_PRODUCT_TEU800) }, |
1195 | { USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W14), | 1211 | { USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W14), |
@@ -1294,7 +1310,14 @@ static const struct usb_device_id option_ids[] = { | |||
1294 | { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FP_2COM, 0x0a, 0x00, 0x00) }, | 1310 | { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FP_2COM, 0x0a, 0x00, 0x00) }, |
1295 | { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FPDC_1COM, 0x0a, 0x00, 0x00) }, | 1311 | { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FPDC_1COM, 0x0a, 0x00, 0x00) }, |
1296 | { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FPDC_2COM, 0x0a, 0x00, 0x00) }, | 1312 | { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FPDC_2COM, 0x0a, 0x00, 0x00) }, |
1313 | { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_7103_2COM, 0xff, 0x00, 0x00) }, | ||
1314 | { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_7106_2COM, 0x02, 0x02, 0x01) }, | ||
1315 | { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM2, 0xff, 0x02, 0x01) }, | ||
1316 | { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM2, 0xff, 0x00, 0x00) }, | ||
1297 | { USB_DEVICE(CELLIENT_VENDOR_ID, CELLIENT_PRODUCT_MEN200) }, | 1317 | { USB_DEVICE(CELLIENT_VENDOR_ID, CELLIENT_PRODUCT_MEN200) }, |
1318 | { USB_DEVICE(PETATEL_VENDOR_ID, PETATEL_PRODUCT_NP10T) }, | ||
1319 | { USB_DEVICE(TPLINK_VENDOR_ID, TPLINK_PRODUCT_MA180), | ||
1320 | .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, | ||
1298 | { } /* Terminating entry */ | 1321 | { } /* Terminating entry */ |
1299 | }; | 1322 | }; |
1300 | MODULE_DEVICE_TABLE(usb, option_ids); | 1323 | MODULE_DEVICE_TABLE(usb, option_ids); |
diff --git a/drivers/vfio/pci/vfio_pci_rdwr.c b/drivers/vfio/pci/vfio_pci_rdwr.c index 4362d9e7baa3..f72323ef618f 100644 --- a/drivers/vfio/pci/vfio_pci_rdwr.c +++ b/drivers/vfio/pci/vfio_pci_rdwr.c | |||
@@ -240,17 +240,17 @@ ssize_t vfio_pci_mem_readwrite(struct vfio_pci_device *vdev, char __user *buf, | |||
240 | filled = 1; | 240 | filled = 1; |
241 | } else { | 241 | } else { |
242 | /* Drop writes, fill reads with FF */ | 242 | /* Drop writes, fill reads with FF */ |
243 | filled = min((size_t)(x_end - pos), count); | ||
243 | if (!iswrite) { | 244 | if (!iswrite) { |
244 | char val = 0xFF; | 245 | char val = 0xFF; |
245 | size_t i; | 246 | size_t i; |
246 | 247 | ||
247 | for (i = 0; i < x_end - pos; i++) { | 248 | for (i = 0; i < filled; i++) { |
248 | if (put_user(val, buf + i)) | 249 | if (put_user(val, buf + i)) |
249 | goto out; | 250 | goto out; |
250 | } | 251 | } |
251 | } | 252 | } |
252 | 253 | ||
253 | filled = x_end - pos; | ||
254 | } | 254 | } |
255 | 255 | ||
256 | count -= filled; | 256 | count -= filled; |
diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index 12526787a7c7..0abf2bf20836 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c | |||
@@ -139,6 +139,7 @@ struct imxfb_info { | |||
139 | struct clk *clk_ahb; | 139 | struct clk *clk_ahb; |
140 | struct clk *clk_per; | 140 | struct clk *clk_per; |
141 | enum imxfb_type devtype; | 141 | enum imxfb_type devtype; |
142 | bool enabled; | ||
142 | 143 | ||
143 | /* | 144 | /* |
144 | * These are the addresses we mapped | 145 | * These are the addresses we mapped |
@@ -536,6 +537,10 @@ static void imxfb_exit_backlight(struct imxfb_info *fbi) | |||
536 | 537 | ||
537 | static void imxfb_enable_controller(struct imxfb_info *fbi) | 538 | static void imxfb_enable_controller(struct imxfb_info *fbi) |
538 | { | 539 | { |
540 | |||
541 | if (fbi->enabled) | ||
542 | return; | ||
543 | |||
539 | pr_debug("Enabling LCD controller\n"); | 544 | pr_debug("Enabling LCD controller\n"); |
540 | 545 | ||
541 | writel(fbi->screen_dma, fbi->regs + LCDC_SSA); | 546 | writel(fbi->screen_dma, fbi->regs + LCDC_SSA); |
@@ -556,6 +561,7 @@ static void imxfb_enable_controller(struct imxfb_info *fbi) | |||
556 | clk_prepare_enable(fbi->clk_ipg); | 561 | clk_prepare_enable(fbi->clk_ipg); |
557 | clk_prepare_enable(fbi->clk_ahb); | 562 | clk_prepare_enable(fbi->clk_ahb); |
558 | clk_prepare_enable(fbi->clk_per); | 563 | clk_prepare_enable(fbi->clk_per); |
564 | fbi->enabled = true; | ||
559 | 565 | ||
560 | if (fbi->backlight_power) | 566 | if (fbi->backlight_power) |
561 | fbi->backlight_power(1); | 567 | fbi->backlight_power(1); |
@@ -565,6 +571,9 @@ static void imxfb_enable_controller(struct imxfb_info *fbi) | |||
565 | 571 | ||
566 | static void imxfb_disable_controller(struct imxfb_info *fbi) | 572 | static void imxfb_disable_controller(struct imxfb_info *fbi) |
567 | { | 573 | { |
574 | if (!fbi->enabled) | ||
575 | return; | ||
576 | |||
568 | pr_debug("Disabling LCD controller\n"); | 577 | pr_debug("Disabling LCD controller\n"); |
569 | 578 | ||
570 | if (fbi->backlight_power) | 579 | if (fbi->backlight_power) |
@@ -575,6 +584,7 @@ static void imxfb_disable_controller(struct imxfb_info *fbi) | |||
575 | clk_disable_unprepare(fbi->clk_per); | 584 | clk_disable_unprepare(fbi->clk_per); |
576 | clk_disable_unprepare(fbi->clk_ipg); | 585 | clk_disable_unprepare(fbi->clk_ipg); |
577 | clk_disable_unprepare(fbi->clk_ahb); | 586 | clk_disable_unprepare(fbi->clk_ahb); |
587 | fbi->enabled = false; | ||
578 | 588 | ||
579 | writel(0, fbi->regs + LCDC_RMCR); | 589 | writel(0, fbi->regs + LCDC_RMCR); |
580 | } | 590 | } |
@@ -729,6 +739,8 @@ static int __init imxfb_init_fbinfo(struct platform_device *pdev) | |||
729 | 739 | ||
730 | memset(fbi, 0, sizeof(struct imxfb_info)); | 740 | memset(fbi, 0, sizeof(struct imxfb_info)); |
731 | 741 | ||
742 | fbi->devtype = pdev->id_entry->driver_data; | ||
743 | |||
732 | strlcpy(info->fix.id, IMX_NAME, sizeof(info->fix.id)); | 744 | strlcpy(info->fix.id, IMX_NAME, sizeof(info->fix.id)); |
733 | 745 | ||
734 | info->fix.type = FB_TYPE_PACKED_PIXELS; | 746 | info->fix.type = FB_TYPE_PACKED_PIXELS; |
@@ -789,7 +801,6 @@ static int __init imxfb_probe(struct platform_device *pdev) | |||
789 | return -ENOMEM; | 801 | return -ENOMEM; |
790 | 802 | ||
791 | fbi = info->par; | 803 | fbi = info->par; |
792 | fbi->devtype = pdev->id_entry->driver_data; | ||
793 | 804 | ||
794 | if (!fb_mode) | 805 | if (!fb_mode) |
795 | fb_mode = pdata->mode[0].mode.name; | 806 | fb_mode = pdata->mode[0].mode.name; |
diff --git a/drivers/video/ssd1307fb.c b/drivers/video/ssd1307fb.c index 4d99dd7a6831..395cb6a8d8f3 100644 --- a/drivers/video/ssd1307fb.c +++ b/drivers/video/ssd1307fb.c | |||
@@ -145,8 +145,8 @@ static void ssd1307fb_update_display(struct ssd1307fb_par *par) | |||
145 | u32 page_length = SSD1307FB_WIDTH * i; | 145 | u32 page_length = SSD1307FB_WIDTH * i; |
146 | u32 index = page_length + (SSD1307FB_WIDTH * k + j) / 8; | 146 | u32 index = page_length + (SSD1307FB_WIDTH * k + j) / 8; |
147 | u8 byte = *(vmem + index); | 147 | u8 byte = *(vmem + index); |
148 | u8 bit = byte & (1 << (7 - (j % 8))); | 148 | u8 bit = byte & (1 << (j % 8)); |
149 | bit = bit >> (7 - (j % 8)); | 149 | bit = bit >> (j % 8); |
150 | buf |= bit << k; | 150 | buf |= bit << k; |
151 | } | 151 | } |
152 | ssd1307fb_write_data(par->client, buf); | 152 | ssd1307fb_write_data(par->client, buf); |
diff --git a/drivers/xen/cpu_hotplug.c b/drivers/xen/cpu_hotplug.c index 4dcfced107f5..084041d42c9a 100644 --- a/drivers/xen/cpu_hotplug.c +++ b/drivers/xen/cpu_hotplug.c | |||
@@ -25,10 +25,10 @@ static void disable_hotplug_cpu(int cpu) | |||
25 | static int vcpu_online(unsigned int cpu) | 25 | static int vcpu_online(unsigned int cpu) |
26 | { | 26 | { |
27 | int err; | 27 | int err; |
28 | char dir[32], state[32]; | 28 | char dir[16], state[16]; |
29 | 29 | ||
30 | sprintf(dir, "cpu/%u", cpu); | 30 | sprintf(dir, "cpu/%u", cpu); |
31 | err = xenbus_scanf(XBT_NIL, dir, "availability", "%s", state); | 31 | err = xenbus_scanf(XBT_NIL, dir, "availability", "%15s", state); |
32 | if (err != 1) { | 32 | if (err != 1) { |
33 | if (!xen_initial_domain()) | 33 | if (!xen_initial_domain()) |
34 | printk(KERN_ERR "XENBUS: Unable to read cpu state\n"); | 34 | printk(KERN_ERR "XENBUS: Unable to read cpu state\n"); |
diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index 2e22df2f7a3f..3c8803feba26 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c | |||
@@ -56,10 +56,15 @@ MODULE_PARM_DESC(limit, "Maximum number of grants that may be mapped by " | |||
56 | static atomic_t pages_mapped = ATOMIC_INIT(0); | 56 | static atomic_t pages_mapped = ATOMIC_INIT(0); |
57 | 57 | ||
58 | static int use_ptemod; | 58 | static int use_ptemod; |
59 | #define populate_freeable_maps use_ptemod | ||
59 | 60 | ||
60 | struct gntdev_priv { | 61 | struct gntdev_priv { |
62 | /* maps with visible offsets in the file descriptor */ | ||
61 | struct list_head maps; | 63 | struct list_head maps; |
62 | /* lock protects maps from concurrent changes */ | 64 | /* maps that are not visible; will be freed on munmap. |
65 | * Only populated if populate_freeable_maps == 1 */ | ||
66 | struct list_head freeable_maps; | ||
67 | /* lock protects maps and freeable_maps */ | ||
63 | spinlock_t lock; | 68 | spinlock_t lock; |
64 | struct mm_struct *mm; | 69 | struct mm_struct *mm; |
65 | struct mmu_notifier mn; | 70 | struct mmu_notifier mn; |
@@ -193,7 +198,7 @@ static struct grant_map *gntdev_find_map_index(struct gntdev_priv *priv, | |||
193 | return NULL; | 198 | return NULL; |
194 | } | 199 | } |
195 | 200 | ||
196 | static void gntdev_put_map(struct grant_map *map) | 201 | static void gntdev_put_map(struct gntdev_priv *priv, struct grant_map *map) |
197 | { | 202 | { |
198 | if (!map) | 203 | if (!map) |
199 | return; | 204 | return; |
@@ -208,6 +213,12 @@ static void gntdev_put_map(struct grant_map *map) | |||
208 | evtchn_put(map->notify.event); | 213 | evtchn_put(map->notify.event); |
209 | } | 214 | } |
210 | 215 | ||
216 | if (populate_freeable_maps && priv) { | ||
217 | spin_lock(&priv->lock); | ||
218 | list_del(&map->next); | ||
219 | spin_unlock(&priv->lock); | ||
220 | } | ||
221 | |||
211 | if (map->pages && !use_ptemod) | 222 | if (map->pages && !use_ptemod) |
212 | unmap_grant_pages(map, 0, map->count); | 223 | unmap_grant_pages(map, 0, map->count); |
213 | gntdev_free_map(map); | 224 | gntdev_free_map(map); |
@@ -301,17 +312,10 @@ static int __unmap_grant_pages(struct grant_map *map, int offset, int pages) | |||
301 | 312 | ||
302 | if (map->notify.flags & UNMAP_NOTIFY_CLEAR_BYTE) { | 313 | if (map->notify.flags & UNMAP_NOTIFY_CLEAR_BYTE) { |
303 | int pgno = (map->notify.addr >> PAGE_SHIFT); | 314 | int pgno = (map->notify.addr >> PAGE_SHIFT); |
304 | if (pgno >= offset && pgno < offset + pages && use_ptemod) { | 315 | if (pgno >= offset && pgno < offset + pages) { |
305 | void __user *tmp = (void __user *) | 316 | /* No need for kmap, pages are in lowmem */ |
306 | map->vma->vm_start + map->notify.addr; | 317 | uint8_t *tmp = pfn_to_kaddr(page_to_pfn(map->pages[pgno])); |
307 | err = copy_to_user(tmp, &err, 1); | ||
308 | if (err) | ||
309 | return -EFAULT; | ||
310 | map->notify.flags &= ~UNMAP_NOTIFY_CLEAR_BYTE; | ||
311 | } else if (pgno >= offset && pgno < offset + pages) { | ||
312 | uint8_t *tmp = kmap(map->pages[pgno]); | ||
313 | tmp[map->notify.addr & (PAGE_SIZE-1)] = 0; | 318 | tmp[map->notify.addr & (PAGE_SIZE-1)] = 0; |
314 | kunmap(map->pages[pgno]); | ||
315 | map->notify.flags &= ~UNMAP_NOTIFY_CLEAR_BYTE; | 319 | map->notify.flags &= ~UNMAP_NOTIFY_CLEAR_BYTE; |
316 | } | 320 | } |
317 | } | 321 | } |
@@ -376,11 +380,24 @@ static void gntdev_vma_open(struct vm_area_struct *vma) | |||
376 | static void gntdev_vma_close(struct vm_area_struct *vma) | 380 | static void gntdev_vma_close(struct vm_area_struct *vma) |
377 | { | 381 | { |
378 | struct grant_map *map = vma->vm_private_data; | 382 | struct grant_map *map = vma->vm_private_data; |
383 | struct file *file = vma->vm_file; | ||
384 | struct gntdev_priv *priv = file->private_data; | ||
379 | 385 | ||
380 | pr_debug("gntdev_vma_close %p\n", vma); | 386 | pr_debug("gntdev_vma_close %p\n", vma); |
381 | map->vma = NULL; | 387 | if (use_ptemod) { |
388 | /* It is possible that an mmu notifier could be running | ||
389 | * concurrently, so take priv->lock to ensure that the vma won't | ||
390 | * vanishing during the unmap_grant_pages call, since we will | ||
391 | * spin here until that completes. Such a concurrent call will | ||
392 | * not do any unmapping, since that has been done prior to | ||
393 | * closing the vma, but it may still iterate the unmap_ops list. | ||
394 | */ | ||
395 | spin_lock(&priv->lock); | ||
396 | map->vma = NULL; | ||
397 | spin_unlock(&priv->lock); | ||
398 | } | ||
382 | vma->vm_private_data = NULL; | 399 | vma->vm_private_data = NULL; |
383 | gntdev_put_map(map); | 400 | gntdev_put_map(priv, map); |
384 | } | 401 | } |
385 | 402 | ||
386 | static struct vm_operations_struct gntdev_vmops = { | 403 | static struct vm_operations_struct gntdev_vmops = { |
@@ -390,33 +407,43 @@ static struct vm_operations_struct gntdev_vmops = { | |||
390 | 407 | ||
391 | /* ------------------------------------------------------------------ */ | 408 | /* ------------------------------------------------------------------ */ |
392 | 409 | ||
410 | static void unmap_if_in_range(struct grant_map *map, | ||
411 | unsigned long start, unsigned long end) | ||
412 | { | ||
413 | unsigned long mstart, mend; | ||
414 | int err; | ||
415 | |||
416 | if (!map->vma) | ||
417 | return; | ||
418 | if (map->vma->vm_start >= end) | ||
419 | return; | ||
420 | if (map->vma->vm_end <= start) | ||
421 | return; | ||
422 | mstart = max(start, map->vma->vm_start); | ||
423 | mend = min(end, map->vma->vm_end); | ||
424 | pr_debug("map %d+%d (%lx %lx), range %lx %lx, mrange %lx %lx\n", | ||
425 | map->index, map->count, | ||
426 | map->vma->vm_start, map->vma->vm_end, | ||
427 | start, end, mstart, mend); | ||
428 | err = unmap_grant_pages(map, | ||
429 | (mstart - map->vma->vm_start) >> PAGE_SHIFT, | ||
430 | (mend - mstart) >> PAGE_SHIFT); | ||
431 | WARN_ON(err); | ||
432 | } | ||
433 | |||
393 | static void mn_invl_range_start(struct mmu_notifier *mn, | 434 | static void mn_invl_range_start(struct mmu_notifier *mn, |
394 | struct mm_struct *mm, | 435 | struct mm_struct *mm, |
395 | unsigned long start, unsigned long end) | 436 | unsigned long start, unsigned long end) |
396 | { | 437 | { |
397 | struct gntdev_priv *priv = container_of(mn, struct gntdev_priv, mn); | 438 | struct gntdev_priv *priv = container_of(mn, struct gntdev_priv, mn); |
398 | struct grant_map *map; | 439 | struct grant_map *map; |
399 | unsigned long mstart, mend; | ||
400 | int err; | ||
401 | 440 | ||
402 | spin_lock(&priv->lock); | 441 | spin_lock(&priv->lock); |
403 | list_for_each_entry(map, &priv->maps, next) { | 442 | list_for_each_entry(map, &priv->maps, next) { |
404 | if (!map->vma) | 443 | unmap_if_in_range(map, start, end); |
405 | continue; | 444 | } |
406 | if (map->vma->vm_start >= end) | 445 | list_for_each_entry(map, &priv->freeable_maps, next) { |
407 | continue; | 446 | unmap_if_in_range(map, start, end); |
408 | if (map->vma->vm_end <= start) | ||
409 | continue; | ||
410 | mstart = max(start, map->vma->vm_start); | ||
411 | mend = min(end, map->vma->vm_end); | ||
412 | pr_debug("map %d+%d (%lx %lx), range %lx %lx, mrange %lx %lx\n", | ||
413 | map->index, map->count, | ||
414 | map->vma->vm_start, map->vma->vm_end, | ||
415 | start, end, mstart, mend); | ||
416 | err = unmap_grant_pages(map, | ||
417 | (mstart - map->vma->vm_start) >> PAGE_SHIFT, | ||
418 | (mend - mstart) >> PAGE_SHIFT); | ||
419 | WARN_ON(err); | ||
420 | } | 447 | } |
421 | spin_unlock(&priv->lock); | 448 | spin_unlock(&priv->lock); |
422 | } | 449 | } |
@@ -445,6 +472,15 @@ static void mn_release(struct mmu_notifier *mn, | |||
445 | err = unmap_grant_pages(map, /* offset */ 0, map->count); | 472 | err = unmap_grant_pages(map, /* offset */ 0, map->count); |
446 | WARN_ON(err); | 473 | WARN_ON(err); |
447 | } | 474 | } |
475 | list_for_each_entry(map, &priv->freeable_maps, next) { | ||
476 | if (!map->vma) | ||
477 | continue; | ||
478 | pr_debug("map %d+%d (%lx %lx)\n", | ||
479 | map->index, map->count, | ||
480 | map->vma->vm_start, map->vma->vm_end); | ||
481 | err = unmap_grant_pages(map, /* offset */ 0, map->count); | ||
482 | WARN_ON(err); | ||
483 | } | ||
448 | spin_unlock(&priv->lock); | 484 | spin_unlock(&priv->lock); |
449 | } | 485 | } |
450 | 486 | ||
@@ -466,6 +502,7 @@ static int gntdev_open(struct inode *inode, struct file *flip) | |||
466 | return -ENOMEM; | 502 | return -ENOMEM; |
467 | 503 | ||
468 | INIT_LIST_HEAD(&priv->maps); | 504 | INIT_LIST_HEAD(&priv->maps); |
505 | INIT_LIST_HEAD(&priv->freeable_maps); | ||
469 | spin_lock_init(&priv->lock); | 506 | spin_lock_init(&priv->lock); |
470 | 507 | ||
471 | if (use_ptemod) { | 508 | if (use_ptemod) { |
@@ -500,8 +537,9 @@ static int gntdev_release(struct inode *inode, struct file *flip) | |||
500 | while (!list_empty(&priv->maps)) { | 537 | while (!list_empty(&priv->maps)) { |
501 | map = list_entry(priv->maps.next, struct grant_map, next); | 538 | map = list_entry(priv->maps.next, struct grant_map, next); |
502 | list_del(&map->next); | 539 | list_del(&map->next); |
503 | gntdev_put_map(map); | 540 | gntdev_put_map(NULL /* already removed */, map); |
504 | } | 541 | } |
542 | WARN_ON(!list_empty(&priv->freeable_maps)); | ||
505 | 543 | ||
506 | if (use_ptemod) | 544 | if (use_ptemod) |
507 | mmu_notifier_unregister(&priv->mn, priv->mm); | 545 | mmu_notifier_unregister(&priv->mn, priv->mm); |
@@ -529,14 +567,14 @@ static long gntdev_ioctl_map_grant_ref(struct gntdev_priv *priv, | |||
529 | 567 | ||
530 | if (unlikely(atomic_add_return(op.count, &pages_mapped) > limit)) { | 568 | if (unlikely(atomic_add_return(op.count, &pages_mapped) > limit)) { |
531 | pr_debug("can't map: over limit\n"); | 569 | pr_debug("can't map: over limit\n"); |
532 | gntdev_put_map(map); | 570 | gntdev_put_map(NULL, map); |
533 | return err; | 571 | return err; |
534 | } | 572 | } |
535 | 573 | ||
536 | if (copy_from_user(map->grants, &u->refs, | 574 | if (copy_from_user(map->grants, &u->refs, |
537 | sizeof(map->grants[0]) * op.count) != 0) { | 575 | sizeof(map->grants[0]) * op.count) != 0) { |
538 | gntdev_put_map(map); | 576 | gntdev_put_map(NULL, map); |
539 | return err; | 577 | return -EFAULT; |
540 | } | 578 | } |
541 | 579 | ||
542 | spin_lock(&priv->lock); | 580 | spin_lock(&priv->lock); |
@@ -565,11 +603,13 @@ static long gntdev_ioctl_unmap_grant_ref(struct gntdev_priv *priv, | |||
565 | map = gntdev_find_map_index(priv, op.index >> PAGE_SHIFT, op.count); | 603 | map = gntdev_find_map_index(priv, op.index >> PAGE_SHIFT, op.count); |
566 | if (map) { | 604 | if (map) { |
567 | list_del(&map->next); | 605 | list_del(&map->next); |
606 | if (populate_freeable_maps) | ||
607 | list_add_tail(&map->next, &priv->freeable_maps); | ||
568 | err = 0; | 608 | err = 0; |
569 | } | 609 | } |
570 | spin_unlock(&priv->lock); | 610 | spin_unlock(&priv->lock); |
571 | if (map) | 611 | if (map) |
572 | gntdev_put_map(map); | 612 | gntdev_put_map(priv, map); |
573 | return err; | 613 | return err; |
574 | } | 614 | } |
575 | 615 | ||
@@ -579,25 +619,31 @@ static long gntdev_ioctl_get_offset_for_vaddr(struct gntdev_priv *priv, | |||
579 | struct ioctl_gntdev_get_offset_for_vaddr op; | 619 | struct ioctl_gntdev_get_offset_for_vaddr op; |
580 | struct vm_area_struct *vma; | 620 | struct vm_area_struct *vma; |
581 | struct grant_map *map; | 621 | struct grant_map *map; |
622 | int rv = -EINVAL; | ||
582 | 623 | ||
583 | if (copy_from_user(&op, u, sizeof(op)) != 0) | 624 | if (copy_from_user(&op, u, sizeof(op)) != 0) |
584 | return -EFAULT; | 625 | return -EFAULT; |
585 | pr_debug("priv %p, offset for vaddr %lx\n", priv, (unsigned long)op.vaddr); | 626 | pr_debug("priv %p, offset for vaddr %lx\n", priv, (unsigned long)op.vaddr); |
586 | 627 | ||
628 | down_read(¤t->mm->mmap_sem); | ||
587 | vma = find_vma(current->mm, op.vaddr); | 629 | vma = find_vma(current->mm, op.vaddr); |
588 | if (!vma || vma->vm_ops != &gntdev_vmops) | 630 | if (!vma || vma->vm_ops != &gntdev_vmops) |
589 | return -EINVAL; | 631 | goto out_unlock; |
590 | 632 | ||
591 | map = vma->vm_private_data; | 633 | map = vma->vm_private_data; |
592 | if (!map) | 634 | if (!map) |
593 | return -EINVAL; | 635 | goto out_unlock; |
594 | 636 | ||
595 | op.offset = map->index << PAGE_SHIFT; | 637 | op.offset = map->index << PAGE_SHIFT; |
596 | op.count = map->count; | 638 | op.count = map->count; |
639 | rv = 0; | ||
597 | 640 | ||
598 | if (copy_to_user(u, &op, sizeof(op)) != 0) | 641 | out_unlock: |
642 | up_read(¤t->mm->mmap_sem); | ||
643 | |||
644 | if (rv == 0 && copy_to_user(u, &op, sizeof(op)) != 0) | ||
599 | return -EFAULT; | 645 | return -EFAULT; |
600 | return 0; | 646 | return rv; |
601 | } | 647 | } |
602 | 648 | ||
603 | static long gntdev_ioctl_notify(struct gntdev_priv *priv, void __user *u) | 649 | static long gntdev_ioctl_notify(struct gntdev_priv *priv, void __user *u) |
@@ -778,7 +824,7 @@ out_unlock_put: | |||
778 | out_put_map: | 824 | out_put_map: |
779 | if (use_ptemod) | 825 | if (use_ptemod) |
780 | map->vma = NULL; | 826 | map->vma = NULL; |
781 | gntdev_put_map(map); | 827 | gntdev_put_map(priv, map); |
782 | return err; | 828 | return err; |
783 | } | 829 | } |
784 | 830 | ||
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c index 7038de53652b..157c0ccda3ef 100644 --- a/drivers/xen/grant-table.c +++ b/drivers/xen/grant-table.c | |||
@@ -56,10 +56,6 @@ | |||
56 | /* External tools reserve first few grant table entries. */ | 56 | /* External tools reserve first few grant table entries. */ |
57 | #define NR_RESERVED_ENTRIES 8 | 57 | #define NR_RESERVED_ENTRIES 8 |
58 | #define GNTTAB_LIST_END 0xffffffff | 58 | #define GNTTAB_LIST_END 0xffffffff |
59 | #define GREFS_PER_GRANT_FRAME \ | ||
60 | (grant_table_version == 1 ? \ | ||
61 | (PAGE_SIZE / sizeof(struct grant_entry_v1)) : \ | ||
62 | (PAGE_SIZE / sizeof(union grant_entry_v2))) | ||
63 | 59 | ||
64 | static grant_ref_t **gnttab_list; | 60 | static grant_ref_t **gnttab_list; |
65 | static unsigned int nr_grant_frames; | 61 | static unsigned int nr_grant_frames; |
@@ -154,6 +150,7 @@ static struct gnttab_ops *gnttab_interface; | |||
154 | static grant_status_t *grstatus; | 150 | static grant_status_t *grstatus; |
155 | 151 | ||
156 | static int grant_table_version; | 152 | static int grant_table_version; |
153 | static int grefs_per_grant_frame; | ||
157 | 154 | ||
158 | static struct gnttab_free_callback *gnttab_free_callback_list; | 155 | static struct gnttab_free_callback *gnttab_free_callback_list; |
159 | 156 | ||
@@ -767,12 +764,14 @@ static int grow_gnttab_list(unsigned int more_frames) | |||
767 | unsigned int new_nr_grant_frames, extra_entries, i; | 764 | unsigned int new_nr_grant_frames, extra_entries, i; |
768 | unsigned int nr_glist_frames, new_nr_glist_frames; | 765 | unsigned int nr_glist_frames, new_nr_glist_frames; |
769 | 766 | ||
767 | BUG_ON(grefs_per_grant_frame == 0); | ||
768 | |||
770 | new_nr_grant_frames = nr_grant_frames + more_frames; | 769 | new_nr_grant_frames = nr_grant_frames + more_frames; |
771 | extra_entries = more_frames * GREFS_PER_GRANT_FRAME; | 770 | extra_entries = more_frames * grefs_per_grant_frame; |
772 | 771 | ||
773 | nr_glist_frames = (nr_grant_frames * GREFS_PER_GRANT_FRAME + RPP - 1) / RPP; | 772 | nr_glist_frames = (nr_grant_frames * grefs_per_grant_frame + RPP - 1) / RPP; |
774 | new_nr_glist_frames = | 773 | new_nr_glist_frames = |
775 | (new_nr_grant_frames * GREFS_PER_GRANT_FRAME + RPP - 1) / RPP; | 774 | (new_nr_grant_frames * grefs_per_grant_frame + RPP - 1) / RPP; |
776 | for (i = nr_glist_frames; i < new_nr_glist_frames; i++) { | 775 | for (i = nr_glist_frames; i < new_nr_glist_frames; i++) { |
777 | gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_ATOMIC); | 776 | gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_ATOMIC); |
778 | if (!gnttab_list[i]) | 777 | if (!gnttab_list[i]) |
@@ -780,12 +779,12 @@ static int grow_gnttab_list(unsigned int more_frames) | |||
780 | } | 779 | } |
781 | 780 | ||
782 | 781 | ||
783 | for (i = GREFS_PER_GRANT_FRAME * nr_grant_frames; | 782 | for (i = grefs_per_grant_frame * nr_grant_frames; |
784 | i < GREFS_PER_GRANT_FRAME * new_nr_grant_frames - 1; i++) | 783 | i < grefs_per_grant_frame * new_nr_grant_frames - 1; i++) |
785 | gnttab_entry(i) = i + 1; | 784 | gnttab_entry(i) = i + 1; |
786 | 785 | ||
787 | gnttab_entry(i) = gnttab_free_head; | 786 | gnttab_entry(i) = gnttab_free_head; |
788 | gnttab_free_head = GREFS_PER_GRANT_FRAME * nr_grant_frames; | 787 | gnttab_free_head = grefs_per_grant_frame * nr_grant_frames; |
789 | gnttab_free_count += extra_entries; | 788 | gnttab_free_count += extra_entries; |
790 | 789 | ||
791 | nr_grant_frames = new_nr_grant_frames; | 790 | nr_grant_frames = new_nr_grant_frames; |
@@ -957,7 +956,8 @@ EXPORT_SYMBOL_GPL(gnttab_unmap_refs); | |||
957 | 956 | ||
958 | static unsigned nr_status_frames(unsigned nr_grant_frames) | 957 | static unsigned nr_status_frames(unsigned nr_grant_frames) |
959 | { | 958 | { |
960 | return (nr_grant_frames * GREFS_PER_GRANT_FRAME + SPP - 1) / SPP; | 959 | BUG_ON(grefs_per_grant_frame == 0); |
960 | return (nr_grant_frames * grefs_per_grant_frame + SPP - 1) / SPP; | ||
961 | } | 961 | } |
962 | 962 | ||
963 | static int gnttab_map_frames_v1(xen_pfn_t *frames, unsigned int nr_gframes) | 963 | static int gnttab_map_frames_v1(xen_pfn_t *frames, unsigned int nr_gframes) |
@@ -1115,6 +1115,7 @@ static void gnttab_request_version(void) | |||
1115 | rc = HYPERVISOR_grant_table_op(GNTTABOP_set_version, &gsv, 1); | 1115 | rc = HYPERVISOR_grant_table_op(GNTTABOP_set_version, &gsv, 1); |
1116 | if (rc == 0 && gsv.version == 2) { | 1116 | if (rc == 0 && gsv.version == 2) { |
1117 | grant_table_version = 2; | 1117 | grant_table_version = 2; |
1118 | grefs_per_grant_frame = PAGE_SIZE / sizeof(union grant_entry_v2); | ||
1118 | gnttab_interface = &gnttab_v2_ops; | 1119 | gnttab_interface = &gnttab_v2_ops; |
1119 | } else if (grant_table_version == 2) { | 1120 | } else if (grant_table_version == 2) { |
1120 | /* | 1121 | /* |
@@ -1127,17 +1128,17 @@ static void gnttab_request_version(void) | |||
1127 | panic("we need grant tables version 2, but only version 1 is available"); | 1128 | panic("we need grant tables version 2, but only version 1 is available"); |
1128 | } else { | 1129 | } else { |
1129 | grant_table_version = 1; | 1130 | grant_table_version = 1; |
1131 | grefs_per_grant_frame = PAGE_SIZE / sizeof(struct grant_entry_v1); | ||
1130 | gnttab_interface = &gnttab_v1_ops; | 1132 | gnttab_interface = &gnttab_v1_ops; |
1131 | } | 1133 | } |
1132 | printk(KERN_INFO "Grant tables using version %d layout.\n", | 1134 | printk(KERN_INFO "Grant tables using version %d layout.\n", |
1133 | grant_table_version); | 1135 | grant_table_version); |
1134 | } | 1136 | } |
1135 | 1137 | ||
1136 | int gnttab_resume(void) | 1138 | static int gnttab_setup(void) |
1137 | { | 1139 | { |
1138 | unsigned int max_nr_gframes; | 1140 | unsigned int max_nr_gframes; |
1139 | 1141 | ||
1140 | gnttab_request_version(); | ||
1141 | max_nr_gframes = gnttab_max_grant_frames(); | 1142 | max_nr_gframes = gnttab_max_grant_frames(); |
1142 | if (max_nr_gframes < nr_grant_frames) | 1143 | if (max_nr_gframes < nr_grant_frames) |
1143 | return -ENOSYS; | 1144 | return -ENOSYS; |
@@ -1160,6 +1161,12 @@ int gnttab_resume(void) | |||
1160 | return 0; | 1161 | return 0; |
1161 | } | 1162 | } |
1162 | 1163 | ||
1164 | int gnttab_resume(void) | ||
1165 | { | ||
1166 | gnttab_request_version(); | ||
1167 | return gnttab_setup(); | ||
1168 | } | ||
1169 | |||
1163 | int gnttab_suspend(void) | 1170 | int gnttab_suspend(void) |
1164 | { | 1171 | { |
1165 | gnttab_interface->unmap_frames(); | 1172 | gnttab_interface->unmap_frames(); |
@@ -1171,9 +1178,10 @@ static int gnttab_expand(unsigned int req_entries) | |||
1171 | int rc; | 1178 | int rc; |
1172 | unsigned int cur, extra; | 1179 | unsigned int cur, extra; |
1173 | 1180 | ||
1181 | BUG_ON(grefs_per_grant_frame == 0); | ||
1174 | cur = nr_grant_frames; | 1182 | cur = nr_grant_frames; |
1175 | extra = ((req_entries + (GREFS_PER_GRANT_FRAME-1)) / | 1183 | extra = ((req_entries + (grefs_per_grant_frame-1)) / |
1176 | GREFS_PER_GRANT_FRAME); | 1184 | grefs_per_grant_frame); |
1177 | if (cur + extra > gnttab_max_grant_frames()) | 1185 | if (cur + extra > gnttab_max_grant_frames()) |
1178 | return -ENOSPC; | 1186 | return -ENOSPC; |
1179 | 1187 | ||
@@ -1191,21 +1199,23 @@ int gnttab_init(void) | |||
1191 | unsigned int nr_init_grefs; | 1199 | unsigned int nr_init_grefs; |
1192 | int ret; | 1200 | int ret; |
1193 | 1201 | ||
1202 | gnttab_request_version(); | ||
1194 | nr_grant_frames = 1; | 1203 | nr_grant_frames = 1; |
1195 | boot_max_nr_grant_frames = __max_nr_grant_frames(); | 1204 | boot_max_nr_grant_frames = __max_nr_grant_frames(); |
1196 | 1205 | ||
1197 | /* Determine the maximum number of frames required for the | 1206 | /* Determine the maximum number of frames required for the |
1198 | * grant reference free list on the current hypervisor. | 1207 | * grant reference free list on the current hypervisor. |
1199 | */ | 1208 | */ |
1209 | BUG_ON(grefs_per_grant_frame == 0); | ||
1200 | max_nr_glist_frames = (boot_max_nr_grant_frames * | 1210 | max_nr_glist_frames = (boot_max_nr_grant_frames * |
1201 | GREFS_PER_GRANT_FRAME / RPP); | 1211 | grefs_per_grant_frame / RPP); |
1202 | 1212 | ||
1203 | gnttab_list = kmalloc(max_nr_glist_frames * sizeof(grant_ref_t *), | 1213 | gnttab_list = kmalloc(max_nr_glist_frames * sizeof(grant_ref_t *), |
1204 | GFP_KERNEL); | 1214 | GFP_KERNEL); |
1205 | if (gnttab_list == NULL) | 1215 | if (gnttab_list == NULL) |
1206 | return -ENOMEM; | 1216 | return -ENOMEM; |
1207 | 1217 | ||
1208 | nr_glist_frames = (nr_grant_frames * GREFS_PER_GRANT_FRAME + RPP - 1) / RPP; | 1218 | nr_glist_frames = (nr_grant_frames * grefs_per_grant_frame + RPP - 1) / RPP; |
1209 | for (i = 0; i < nr_glist_frames; i++) { | 1219 | for (i = 0; i < nr_glist_frames; i++) { |
1210 | gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_KERNEL); | 1220 | gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_KERNEL); |
1211 | if (gnttab_list[i] == NULL) { | 1221 | if (gnttab_list[i] == NULL) { |
@@ -1214,12 +1224,12 @@ int gnttab_init(void) | |||
1214 | } | 1224 | } |
1215 | } | 1225 | } |
1216 | 1226 | ||
1217 | if (gnttab_resume() < 0) { | 1227 | if (gnttab_setup() < 0) { |
1218 | ret = -ENODEV; | 1228 | ret = -ENODEV; |
1219 | goto ini_nomem; | 1229 | goto ini_nomem; |
1220 | } | 1230 | } |
1221 | 1231 | ||
1222 | nr_init_grefs = nr_grant_frames * GREFS_PER_GRANT_FRAME; | 1232 | nr_init_grefs = nr_grant_frames * grefs_per_grant_frame; |
1223 | 1233 | ||
1224 | for (i = NR_RESERVED_ENTRIES; i < nr_init_grefs - 1; i++) | 1234 | for (i = NR_RESERVED_ENTRIES; i < nr_init_grefs - 1; i++) |
1225 | gnttab_entry(i) = i + 1; | 1235 | gnttab_entry(i) = i + 1; |
diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c index 0bbbccbb1f12..ca2b00e9d558 100644 --- a/drivers/xen/privcmd.c +++ b/drivers/xen/privcmd.c | |||
@@ -199,9 +199,6 @@ static long privcmd_ioctl_mmap(void __user *udata) | |||
199 | LIST_HEAD(pagelist); | 199 | LIST_HEAD(pagelist); |
200 | struct mmap_mfn_state state; | 200 | struct mmap_mfn_state state; |
201 | 201 | ||
202 | if (!xen_initial_domain()) | ||
203 | return -EPERM; | ||
204 | |||
205 | /* We only support privcmd_ioctl_mmap_batch for auto translated. */ | 202 | /* We only support privcmd_ioctl_mmap_batch for auto translated. */ |
206 | if (xen_feature(XENFEAT_auto_translated_physmap)) | 203 | if (xen_feature(XENFEAT_auto_translated_physmap)) |
207 | return -ENOSYS; | 204 | return -ENOSYS; |
@@ -261,11 +258,12 @@ struct mmap_batch_state { | |||
261 | * -ENOENT if at least 1 -ENOENT has happened. | 258 | * -ENOENT if at least 1 -ENOENT has happened. |
262 | */ | 259 | */ |
263 | int global_error; | 260 | int global_error; |
264 | /* An array for individual errors */ | 261 | int version; |
265 | int *err; | ||
266 | 262 | ||
267 | /* User-space mfn array to store errors in the second pass for V1. */ | 263 | /* User-space mfn array to store errors in the second pass for V1. */ |
268 | xen_pfn_t __user *user_mfn; | 264 | xen_pfn_t __user *user_mfn; |
265 | /* User-space int array to store errors in the second pass for V2. */ | ||
266 | int __user *user_err; | ||
269 | }; | 267 | }; |
270 | 268 | ||
271 | /* auto translated dom0 note: if domU being created is PV, then mfn is | 269 | /* auto translated dom0 note: if domU being created is PV, then mfn is |
@@ -288,7 +286,19 @@ static int mmap_batch_fn(void *data, void *state) | |||
288 | &cur_page); | 286 | &cur_page); |
289 | 287 | ||
290 | /* Store error code for second pass. */ | 288 | /* Store error code for second pass. */ |
291 | *(st->err++) = ret; | 289 | if (st->version == 1) { |
290 | if (ret < 0) { | ||
291 | /* | ||
292 | * V1 encodes the error codes in the 32bit top nibble of the | ||
293 | * mfn (with its known limitations vis-a-vis 64 bit callers). | ||
294 | */ | ||
295 | *mfnp |= (ret == -ENOENT) ? | ||
296 | PRIVCMD_MMAPBATCH_PAGED_ERROR : | ||
297 | PRIVCMD_MMAPBATCH_MFN_ERROR; | ||
298 | } | ||
299 | } else { /* st->version == 2 */ | ||
300 | *((int *) mfnp) = ret; | ||
301 | } | ||
292 | 302 | ||
293 | /* And see if it affects the global_error. */ | 303 | /* And see if it affects the global_error. */ |
294 | if (ret < 0) { | 304 | if (ret < 0) { |
@@ -305,20 +315,25 @@ static int mmap_batch_fn(void *data, void *state) | |||
305 | return 0; | 315 | return 0; |
306 | } | 316 | } |
307 | 317 | ||
308 | static int mmap_return_errors_v1(void *data, void *state) | 318 | static int mmap_return_errors(void *data, void *state) |
309 | { | 319 | { |
310 | xen_pfn_t *mfnp = data; | ||
311 | struct mmap_batch_state *st = state; | 320 | struct mmap_batch_state *st = state; |
312 | int err = *(st->err++); | ||
313 | 321 | ||
314 | /* | 322 | if (st->version == 1) { |
315 | * V1 encodes the error codes in the 32bit top nibble of the | 323 | xen_pfn_t mfnp = *((xen_pfn_t *) data); |
316 | * mfn (with its known limitations vis-a-vis 64 bit callers). | 324 | if (mfnp & PRIVCMD_MMAPBATCH_MFN_ERROR) |
317 | */ | 325 | return __put_user(mfnp, st->user_mfn++); |
318 | *mfnp |= (err == -ENOENT) ? | 326 | else |
319 | PRIVCMD_MMAPBATCH_PAGED_ERROR : | 327 | st->user_mfn++; |
320 | PRIVCMD_MMAPBATCH_MFN_ERROR; | 328 | } else { /* st->version == 2 */ |
321 | return __put_user(*mfnp, st->user_mfn++); | 329 | int err = *((int *) data); |
330 | if (err) | ||
331 | return __put_user(err, st->user_err++); | ||
332 | else | ||
333 | st->user_err++; | ||
334 | } | ||
335 | |||
336 | return 0; | ||
322 | } | 337 | } |
323 | 338 | ||
324 | /* Allocate pfns that are then mapped with gmfns from foreign domid. Update | 339 | /* Allocate pfns that are then mapped with gmfns from foreign domid. Update |
@@ -357,12 +372,8 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version) | |||
357 | struct vm_area_struct *vma; | 372 | struct vm_area_struct *vma; |
358 | unsigned long nr_pages; | 373 | unsigned long nr_pages; |
359 | LIST_HEAD(pagelist); | 374 | LIST_HEAD(pagelist); |
360 | int *err_array = NULL; | ||
361 | struct mmap_batch_state state; | 375 | struct mmap_batch_state state; |
362 | 376 | ||
363 | if (!xen_initial_domain()) | ||
364 | return -EPERM; | ||
365 | |||
366 | switch (version) { | 377 | switch (version) { |
367 | case 1: | 378 | case 1: |
368 | if (copy_from_user(&m, udata, sizeof(struct privcmd_mmapbatch))) | 379 | if (copy_from_user(&m, udata, sizeof(struct privcmd_mmapbatch))) |
@@ -396,10 +407,12 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version) | |||
396 | goto out; | 407 | goto out; |
397 | } | 408 | } |
398 | 409 | ||
399 | err_array = kcalloc(m.num, sizeof(int), GFP_KERNEL); | 410 | if (version == 2) { |
400 | if (err_array == NULL) { | 411 | /* Zero error array now to only copy back actual errors. */ |
401 | ret = -ENOMEM; | 412 | if (clear_user(m.err, sizeof(int) * m.num)) { |
402 | goto out; | 413 | ret = -EFAULT; |
414 | goto out; | ||
415 | } | ||
403 | } | 416 | } |
404 | 417 | ||
405 | down_write(&mm->mmap_sem); | 418 | down_write(&mm->mmap_sem); |
@@ -427,7 +440,7 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version) | |||
427 | state.va = m.addr; | 440 | state.va = m.addr; |
428 | state.index = 0; | 441 | state.index = 0; |
429 | state.global_error = 0; | 442 | state.global_error = 0; |
430 | state.err = err_array; | 443 | state.version = version; |
431 | 444 | ||
432 | /* mmap_batch_fn guarantees ret == 0 */ | 445 | /* mmap_batch_fn guarantees ret == 0 */ |
433 | BUG_ON(traverse_pages(m.num, sizeof(xen_pfn_t), | 446 | BUG_ON(traverse_pages(m.num, sizeof(xen_pfn_t), |
@@ -435,21 +448,14 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version) | |||
435 | 448 | ||
436 | up_write(&mm->mmap_sem); | 449 | up_write(&mm->mmap_sem); |
437 | 450 | ||
438 | if (version == 1) { | 451 | if (state.global_error) { |
439 | if (state.global_error) { | 452 | /* Write back errors in second pass. */ |
440 | /* Write back errors in second pass. */ | 453 | state.user_mfn = (xen_pfn_t *)m.arr; |
441 | state.user_mfn = (xen_pfn_t *)m.arr; | 454 | state.user_err = m.err; |
442 | state.err = err_array; | 455 | ret = traverse_pages(m.num, sizeof(xen_pfn_t), |
443 | ret = traverse_pages(m.num, sizeof(xen_pfn_t), | 456 | &pagelist, mmap_return_errors, &state); |
444 | &pagelist, mmap_return_errors_v1, &state); | 457 | } else |
445 | } else | 458 | ret = 0; |
446 | ret = 0; | ||
447 | |||
448 | } else if (version == 2) { | ||
449 | ret = __copy_to_user(m.err, err_array, m.num * sizeof(int)); | ||
450 | if (ret) | ||
451 | ret = -EFAULT; | ||
452 | } | ||
453 | 459 | ||
454 | /* If we have not had any EFAULT-like global errors then set the global | 460 | /* If we have not had any EFAULT-like global errors then set the global |
455 | * error to -ENOENT if necessary. */ | 461 | * error to -ENOENT if necessary. */ |
@@ -457,7 +463,6 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version) | |||
457 | ret = -ENOENT; | 463 | ret = -ENOENT; |
458 | 464 | ||
459 | out: | 465 | out: |
460 | kfree(err_array); | ||
461 | free_page_list(&pagelist); | 466 | free_page_list(&pagelist); |
462 | 467 | ||
463 | return ret; | 468 | return ret; |
diff --git a/drivers/xen/xen-pciback/pciback.h b/drivers/xen/xen-pciback/pciback.h index a7def010eba3..f72af87640e0 100644 --- a/drivers/xen/xen-pciback/pciback.h +++ b/drivers/xen/xen-pciback/pciback.h | |||
@@ -124,7 +124,7 @@ static inline int xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev, | |||
124 | static inline void xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev, | 124 | static inline void xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev, |
125 | struct pci_dev *dev) | 125 | struct pci_dev *dev) |
126 | { | 126 | { |
127 | if (xen_pcibk_backend && xen_pcibk_backend->free) | 127 | if (xen_pcibk_backend && xen_pcibk_backend->release) |
128 | return xen_pcibk_backend->release(pdev, dev); | 128 | return xen_pcibk_backend->release(pdev, dev); |
129 | } | 129 | } |
130 | 130 | ||