diff options
Diffstat (limited to 'drivers')
442 files changed, 16648 insertions, 2950 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/osl.c b/drivers/acpi/osl.c index 3ff267861541..bd22f8667eed 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c | |||
| @@ -250,7 +250,7 @@ acpi_physical_address __init acpi_os_get_root_pointer(void) | |||
| 250 | return acpi_rsdp; | 250 | return acpi_rsdp; |
| 251 | #endif | 251 | #endif |
| 252 | 252 | ||
| 253 | if (efi_enabled) { | 253 | if (efi_enabled(EFI_CONFIG_TABLES)) { |
| 254 | if (efi.acpi20 != EFI_INVALID_TABLE_ADDR) | 254 | if (efi.acpi20 != EFI_INVALID_TABLE_ADDR) |
| 255 | return efi.acpi20; | 255 | return efi.acpi20; |
| 256 | else if (efi.acpi != EFI_INVALID_TABLE_ADDR) | 256 | else if (efi.acpi != EFI_INVALID_TABLE_ADDR) |
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/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index b00000e8aef6..33c9a44a9678 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c | |||
| @@ -77,10 +77,15 @@ static struct usb_device_id ath3k_table[] = { | |||
| 77 | { USB_DEVICE(0x0CF3, 0x311D) }, | 77 | { USB_DEVICE(0x0CF3, 0x311D) }, |
| 78 | { USB_DEVICE(0x13d3, 0x3375) }, | 78 | { USB_DEVICE(0x13d3, 0x3375) }, |
| 79 | { USB_DEVICE(0x04CA, 0x3005) }, | 79 | { USB_DEVICE(0x04CA, 0x3005) }, |
| 80 | { USB_DEVICE(0x04CA, 0x3006) }, | ||
| 81 | { USB_DEVICE(0x04CA, 0x3008) }, | ||
| 80 | { USB_DEVICE(0x13d3, 0x3362) }, | 82 | { USB_DEVICE(0x13d3, 0x3362) }, |
| 81 | { USB_DEVICE(0x0CF3, 0xE004) }, | 83 | { USB_DEVICE(0x0CF3, 0xE004) }, |
| 82 | { USB_DEVICE(0x0930, 0x0219) }, | 84 | { USB_DEVICE(0x0930, 0x0219) }, |
| 83 | { USB_DEVICE(0x0489, 0xe057) }, | 85 | { USB_DEVICE(0x0489, 0xe057) }, |
| 86 | { USB_DEVICE(0x13d3, 0x3393) }, | ||
| 87 | { USB_DEVICE(0x0489, 0xe04e) }, | ||
| 88 | { USB_DEVICE(0x0489, 0xe056) }, | ||
| 84 | 89 | ||
| 85 | /* Atheros AR5BBU12 with sflash firmware */ | 90 | /* Atheros AR5BBU12 with sflash firmware */ |
| 86 | { USB_DEVICE(0x0489, 0xE02C) }, | 91 | { USB_DEVICE(0x0489, 0xE02C) }, |
| @@ -104,10 +109,15 @@ static struct usb_device_id ath3k_blist_tbl[] = { | |||
| 104 | { USB_DEVICE(0x0cf3, 0x311D), .driver_info = BTUSB_ATH3012 }, | 109 | { USB_DEVICE(0x0cf3, 0x311D), .driver_info = BTUSB_ATH3012 }, |
| 105 | { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, | 110 | { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, |
| 106 | { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 }, | 111 | { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 }, |
| 112 | { USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 }, | ||
| 113 | { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 }, | ||
| 107 | { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 }, | 114 | { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 }, |
| 108 | { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 }, | 115 | { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 }, |
| 109 | { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 }, | 116 | { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 }, |
| 110 | { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 }, | 117 | { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 }, |
| 118 | { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 }, | ||
| 119 | { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 }, | ||
| 120 | { USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 }, | ||
| 111 | 121 | ||
| 112 | /* Atheros AR5BBU22 with sflash firmware */ | 122 | /* Atheros AR5BBU22 with sflash firmware */ |
| 113 | { USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 }, | 123 | { USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 }, |
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index a1d4ede5b892..7e351e345476 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c | |||
| @@ -135,10 +135,15 @@ static struct usb_device_id blacklist_table[] = { | |||
| 135 | { USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 }, | 135 | { USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 }, |
| 136 | { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, | 136 | { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, |
| 137 | { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 }, | 137 | { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 }, |
| 138 | { USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 }, | ||
| 139 | { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 }, | ||
| 138 | { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 }, | 140 | { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 }, |
| 139 | { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 }, | 141 | { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 }, |
| 140 | { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 }, | 142 | { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 }, |
| 141 | { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 }, | 143 | { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 }, |
| 144 | { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 }, | ||
| 145 | { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 }, | ||
| 146 | { USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 }, | ||
| 142 | 147 | ||
| 143 | /* Atheros AR5BBU12 with sflash firmware */ | 148 | /* Atheros AR5BBU12 with sflash firmware */ |
| 144 | { USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE }, | 149 | { USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE }, |
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index ee90e87e7675..f0b269a2058d 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile | |||
| @@ -22,6 +22,7 @@ obj-$(CONFIG_ARCH_U8500) += ux500/ | |||
| 22 | obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o | 22 | obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o |
| 23 | obj-$(CONFIG_ARCH_SUNXI) += clk-sunxi.o | 23 | obj-$(CONFIG_ARCH_SUNXI) += clk-sunxi.o |
| 24 | obj-$(CONFIG_ARCH_ZYNQ) += clk-zynq.o | 24 | obj-$(CONFIG_ARCH_ZYNQ) += clk-zynq.o |
| 25 | obj-$(CONFIG_ARCH_TEGRA) += tegra/ | ||
| 25 | 26 | ||
| 26 | # Chip specific | 27 | # Chip specific |
| 27 | obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o | 28 | obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o |
diff --git a/drivers/clk/clk-bcm2835.c b/drivers/clk/clk-bcm2835.c index e69991aab43a..792bc57a9db7 100644 --- a/drivers/clk/clk-bcm2835.c +++ b/drivers/clk/clk-bcm2835.c | |||
| @@ -20,6 +20,13 @@ | |||
| 20 | #include <linux/clk-provider.h> | 20 | #include <linux/clk-provider.h> |
| 21 | #include <linux/clkdev.h> | 21 | #include <linux/clkdev.h> |
| 22 | #include <linux/clk/bcm2835.h> | 22 | #include <linux/clk/bcm2835.h> |
| 23 | #include <linux/clk-provider.h> | ||
| 24 | #include <linux/of.h> | ||
| 25 | |||
| 26 | static const __initconst struct of_device_id clk_match[] = { | ||
| 27 | { .compatible = "fixed-clock", .data = of_fixed_clk_setup, }, | ||
| 28 | { } | ||
| 29 | }; | ||
| 23 | 30 | ||
| 24 | /* | 31 | /* |
| 25 | * These are fixed clocks. They're probably not all root clocks and it may | 32 | * These are fixed clocks. They're probably not all root clocks and it may |
| @@ -56,4 +63,6 @@ void __init bcm2835_init_clocks(void) | |||
| 56 | ret = clk_register_clkdev(clk, NULL, "20215000.uart"); | 63 | ret = clk_register_clkdev(clk, NULL, "20215000.uart"); |
| 57 | if (ret) | 64 | if (ret) |
| 58 | pr_err("uart1_pclk alias not registered\n"); | 65 | pr_err("uart1_pclk alias not registered\n"); |
| 66 | |||
| 67 | of_clk_init(clk_match); | ||
| 59 | } | 68 | } |
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/clk/mxs/clk-imx28.c b/drivers/clk/mxs/clk-imx28.c index db3af0874121..0174270abfe7 100644 --- a/drivers/clk/mxs/clk-imx28.c +++ b/drivers/clk/mxs/clk-imx28.c | |||
| @@ -238,7 +238,7 @@ int __init mx28_clocks_init(void) | |||
| 238 | of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); | 238 | of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); |
| 239 | } | 239 | } |
| 240 | 240 | ||
| 241 | clk_register_clkdev(clks[clk32k], NULL, "timrot"); | 241 | clk_register_clkdev(clks[xbus], NULL, "timrot"); |
| 242 | clk_register_clkdev(clks[enet_out], NULL, "enet_out"); | 242 | clk_register_clkdev(clks[enet_out], NULL, "enet_out"); |
| 243 | 243 | ||
| 244 | for (i = 0; i < ARRAY_SIZE(clks_init_on); i++) | 244 | for (i = 0; i < ARRAY_SIZE(clks_init_on); i++) |
diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile new file mode 100644 index 000000000000..2b41b0f4f731 --- /dev/null +++ b/drivers/clk/tegra/Makefile | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | obj-y += clk.o | ||
| 2 | obj-y += clk-audio-sync.o | ||
| 3 | obj-y += clk-divider.o | ||
| 4 | obj-y += clk-periph.o | ||
| 5 | obj-y += clk-periph-gate.o | ||
| 6 | obj-y += clk-pll.o | ||
| 7 | obj-y += clk-pll-out.o | ||
| 8 | obj-y += clk-super.o | ||
| 9 | |||
| 10 | obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += clk-tegra20.o | ||
| 11 | obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += clk-tegra30.o | ||
diff --git a/drivers/clk/tegra/clk-audio-sync.c b/drivers/clk/tegra/clk-audio-sync.c new file mode 100644 index 000000000000..c0f7843e80e6 --- /dev/null +++ b/drivers/clk/tegra/clk-audio-sync.c | |||
| @@ -0,0 +1,87 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/clk-provider.h> | ||
| 18 | #include <linux/slab.h> | ||
| 19 | #include <linux/err.h> | ||
| 20 | |||
| 21 | #include "clk.h" | ||
| 22 | |||
| 23 | static unsigned long clk_sync_source_recalc_rate(struct clk_hw *hw, | ||
| 24 | unsigned long parent_rate) | ||
| 25 | { | ||
| 26 | struct tegra_clk_sync_source *sync = to_clk_sync_source(hw); | ||
| 27 | |||
| 28 | return sync->rate; | ||
| 29 | } | ||
| 30 | |||
| 31 | static long clk_sync_source_round_rate(struct clk_hw *hw, unsigned long rate, | ||
| 32 | unsigned long *prate) | ||
| 33 | { | ||
| 34 | struct tegra_clk_sync_source *sync = to_clk_sync_source(hw); | ||
| 35 | |||
| 36 | if (rate > sync->max_rate) | ||
| 37 | return -EINVAL; | ||
| 38 | else | ||
| 39 | return rate; | ||
| 40 | } | ||
| 41 | |||
| 42 | static int clk_sync_source_set_rate(struct clk_hw *hw, unsigned long rate, | ||
| 43 | unsigned long parent_rate) | ||
| 44 | { | ||
| 45 | struct tegra_clk_sync_source *sync = to_clk_sync_source(hw); | ||
| 46 | |||
| 47 | sync->rate = rate; | ||
| 48 | return 0; | ||
| 49 | } | ||
| 50 | |||
| 51 | const struct clk_ops tegra_clk_sync_source_ops = { | ||
| 52 | .round_rate = clk_sync_source_round_rate, | ||
| 53 | .set_rate = clk_sync_source_set_rate, | ||
| 54 | .recalc_rate = clk_sync_source_recalc_rate, | ||
| 55 | }; | ||
| 56 | |||
| 57 | struct clk *tegra_clk_register_sync_source(const char *name, | ||
| 58 | unsigned long rate, unsigned long max_rate) | ||
| 59 | { | ||
| 60 | struct tegra_clk_sync_source *sync; | ||
| 61 | struct clk_init_data init; | ||
| 62 | struct clk *clk; | ||
| 63 | |||
| 64 | sync = kzalloc(sizeof(*sync), GFP_KERNEL); | ||
| 65 | if (!sync) { | ||
| 66 | pr_err("%s: could not allocate sync source clk\n", __func__); | ||
| 67 | return ERR_PTR(-ENOMEM); | ||
| 68 | } | ||
| 69 | |||
| 70 | sync->rate = rate; | ||
| 71 | sync->max_rate = max_rate; | ||
| 72 | |||
| 73 | init.ops = &tegra_clk_sync_source_ops; | ||
| 74 | init.name = name; | ||
| 75 | init.flags = CLK_IS_ROOT; | ||
| 76 | init.parent_names = NULL; | ||
| 77 | init.num_parents = 0; | ||
| 78 | |||
| 79 | /* Data in .init is copied by clk_register(), so stack variable OK */ | ||
| 80 | sync->hw.init = &init; | ||
| 81 | |||
| 82 | clk = clk_register(NULL, &sync->hw); | ||
| 83 | if (IS_ERR(clk)) | ||
| 84 | kfree(sync); | ||
| 85 | |||
| 86 | return clk; | ||
| 87 | } | ||
diff --git a/drivers/clk/tegra/clk-divider.c b/drivers/clk/tegra/clk-divider.c new file mode 100644 index 000000000000..4d75b1f37e3a --- /dev/null +++ b/drivers/clk/tegra/clk-divider.c | |||
| @@ -0,0 +1,187 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/kernel.h> | ||
| 18 | #include <linux/io.h> | ||
| 19 | #include <linux/err.h> | ||
| 20 | #include <linux/slab.h> | ||
| 21 | #include <linux/clk-provider.h> | ||
| 22 | #include <linux/clk.h> | ||
| 23 | |||
| 24 | #include "clk.h" | ||
| 25 | |||
| 26 | #define pll_out_override(p) (BIT((p->shift - 6))) | ||
| 27 | #define div_mask(d) ((1 << (d->width)) - 1) | ||
| 28 | #define get_mul(d) (1 << d->frac_width) | ||
| 29 | #define get_max_div(d) div_mask(d) | ||
| 30 | |||
| 31 | #define PERIPH_CLK_UART_DIV_ENB BIT(24) | ||
| 32 | |||
| 33 | static int get_div(struct tegra_clk_frac_div *divider, unsigned long rate, | ||
| 34 | unsigned long parent_rate) | ||
| 35 | { | ||
| 36 | s64 divider_ux1 = parent_rate; | ||
| 37 | u8 flags = divider->flags; | ||
| 38 | int mul; | ||
| 39 | |||
| 40 | if (!rate) | ||
| 41 | return 0; | ||
| 42 | |||
| 43 | mul = get_mul(divider); | ||
| 44 | |||
| 45 | if (!(flags & TEGRA_DIVIDER_INT)) | ||
| 46 | divider_ux1 *= mul; | ||
| 47 | |||
| 48 | if (flags & TEGRA_DIVIDER_ROUND_UP) | ||
| 49 | divider_ux1 += rate - 1; | ||
| 50 | |||
| 51 | do_div(divider_ux1, rate); | ||
| 52 | |||
| 53 | if (flags & TEGRA_DIVIDER_INT) | ||
| 54 | divider_ux1 *= mul; | ||
| 55 | |||
| 56 | divider_ux1 -= mul; | ||
| 57 | |||
| 58 | if (divider_ux1 < 0) | ||
| 59 | return 0; | ||
| 60 | |||
| 61 | if (divider_ux1 > get_max_div(divider)) | ||
| 62 | return -EINVAL; | ||
| 63 | |||
| 64 | return divider_ux1; | ||
| 65 | } | ||
| 66 | |||
| 67 | static unsigned long clk_frac_div_recalc_rate(struct clk_hw *hw, | ||
| 68 | unsigned long parent_rate) | ||
| 69 | { | ||
| 70 | struct tegra_clk_frac_div *divider = to_clk_frac_div(hw); | ||
| 71 | u32 reg; | ||
| 72 | int div, mul; | ||
| 73 | u64 rate = parent_rate; | ||
| 74 | |||
| 75 | reg = readl_relaxed(divider->reg) >> divider->shift; | ||
| 76 | div = reg & div_mask(divider); | ||
| 77 | |||
| 78 | mul = get_mul(divider); | ||
| 79 | div += mul; | ||
| 80 | |||
| 81 | rate *= mul; | ||
| 82 | rate += div - 1; | ||
| 83 | do_div(rate, div); | ||
| 84 | |||
| 85 | return rate; | ||
| 86 | } | ||
| 87 | |||
| 88 | static long clk_frac_div_round_rate(struct clk_hw *hw, unsigned long rate, | ||
| 89 | unsigned long *prate) | ||
| 90 | { | ||
| 91 | struct tegra_clk_frac_div *divider = to_clk_frac_div(hw); | ||
| 92 | int div, mul; | ||
| 93 | unsigned long output_rate = *prate; | ||
| 94 | |||
| 95 | if (!rate) | ||
| 96 | return output_rate; | ||
| 97 | |||
| 98 | div = get_div(divider, rate, output_rate); | ||
| 99 | if (div < 0) | ||
| 100 | return *prate; | ||
| 101 | |||
| 102 | mul = get_mul(divider); | ||
| 103 | |||
| 104 | return DIV_ROUND_UP(output_rate * mul, div + mul); | ||
| 105 | } | ||
| 106 | |||
| 107 | static int clk_frac_div_set_rate(struct clk_hw *hw, unsigned long rate, | ||
| 108 | unsigned long parent_rate) | ||
| 109 | { | ||
| 110 | struct tegra_clk_frac_div *divider = to_clk_frac_div(hw); | ||
| 111 | int div; | ||
| 112 | unsigned long flags = 0; | ||
| 113 | u32 val; | ||
| 114 | |||
| 115 | div = get_div(divider, rate, parent_rate); | ||
| 116 | if (div < 0) | ||
| 117 | return div; | ||
| 118 | |||
| 119 | if (divider->lock) | ||
| 120 | spin_lock_irqsave(divider->lock, flags); | ||
| 121 | |||
| 122 | val = readl_relaxed(divider->reg); | ||
| 123 | val &= ~(div_mask(divider) << divider->shift); | ||
| 124 | val |= div << divider->shift; | ||
| 125 | |||
| 126 | if (divider->flags & TEGRA_DIVIDER_UART) { | ||
| 127 | if (div) | ||
| 128 | val |= PERIPH_CLK_UART_DIV_ENB; | ||
| 129 | else | ||
| 130 | val &= ~PERIPH_CLK_UART_DIV_ENB; | ||
| 131 | } | ||
| 132 | |||
| 133 | if (divider->flags & TEGRA_DIVIDER_FIXED) | ||
| 134 | val |= pll_out_override(divider); | ||
| 135 | |||
| 136 | writel_relaxed(val, divider->reg); | ||
| 137 | |||
| 138 | if (divider->lock) | ||
| 139 | spin_unlock_irqrestore(divider->lock, flags); | ||
| 140 | |||
| 141 | return 0; | ||
| 142 | } | ||
| 143 | |||
| 144 | const struct clk_ops tegra_clk_frac_div_ops = { | ||
| 145 | .recalc_rate = clk_frac_div_recalc_rate, | ||
| 146 | .set_rate = clk_frac_div_set_rate, | ||
| 147 | .round_rate = clk_frac_div_round_rate, | ||
| 148 | }; | ||
| 149 | |||
| 150 | struct clk *tegra_clk_register_divider(const char *name, | ||
| 151 | const char *parent_name, void __iomem *reg, | ||
| 152 | unsigned long flags, u8 clk_divider_flags, u8 shift, u8 width, | ||
| 153 | u8 frac_width, spinlock_t *lock) | ||
| 154 | { | ||
| 155 | struct tegra_clk_frac_div *divider; | ||
| 156 | struct clk *clk; | ||
| 157 | struct clk_init_data init; | ||
| 158 | |||
| 159 | divider = kzalloc(sizeof(*divider), GFP_KERNEL); | ||
| 160 | if (!divider) { | ||
| 161 | pr_err("%s: could not allocate fractional divider clk\n", | ||
| 162 | __func__); | ||
| 163 | return ERR_PTR(-ENOMEM); | ||
| 164 | } | ||
| 165 | |||
| 166 | init.name = name; | ||
| 167 | init.ops = &tegra_clk_frac_div_ops; | ||
| 168 | init.flags = flags; | ||
| 169 | init.parent_names = parent_name ? &parent_name : NULL; | ||
| 170 | init.num_parents = parent_name ? 1 : 0; | ||
| 171 | |||
| 172 | divider->reg = reg; | ||
| 173 | divider->shift = shift; | ||
| 174 | divider->width = width; | ||
| 175 | divider->frac_width = frac_width; | ||
| 176 | divider->lock = lock; | ||
| 177 | divider->flags = clk_divider_flags; | ||
| 178 | |||
| 179 | /* Data in .init is copied by clk_register(), so stack variable OK */ | ||
| 180 | divider->hw.init = &init; | ||
| 181 | |||
| 182 | clk = clk_register(NULL, ÷r->hw); | ||
| 183 | if (IS_ERR(clk)) | ||
| 184 | kfree(divider); | ||
| 185 | |||
| 186 | return clk; | ||
| 187 | } | ||
diff --git a/drivers/clk/tegra/clk-periph-gate.c b/drivers/clk/tegra/clk-periph-gate.c new file mode 100644 index 000000000000..6dd533251e7b --- /dev/null +++ b/drivers/clk/tegra/clk-periph-gate.c | |||
| @@ -0,0 +1,179 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/clk.h> | ||
| 18 | #include <linux/clk-provider.h> | ||
| 19 | #include <linux/slab.h> | ||
| 20 | #include <linux/io.h> | ||
| 21 | #include <linux/delay.h> | ||
| 22 | #include <linux/err.h> | ||
| 23 | #include <linux/tegra-soc.h> | ||
| 24 | |||
| 25 | #include "clk.h" | ||
| 26 | |||
| 27 | static DEFINE_SPINLOCK(periph_ref_lock); | ||
| 28 | |||
| 29 | /* Macros to assist peripheral gate clock */ | ||
| 30 | #define read_enb(gate) \ | ||
| 31 | readl_relaxed(gate->clk_base + (gate->regs->enb_reg)) | ||
| 32 | #define write_enb_set(val, gate) \ | ||
| 33 | writel_relaxed(val, gate->clk_base + (gate->regs->enb_set_reg)) | ||
| 34 | #define write_enb_clr(val, gate) \ | ||
| 35 | writel_relaxed(val, gate->clk_base + (gate->regs->enb_clr_reg)) | ||
| 36 | |||
| 37 | #define read_rst(gate) \ | ||
| 38 | readl_relaxed(gate->clk_base + (gate->regs->rst_reg)) | ||
| 39 | #define write_rst_set(val, gate) \ | ||
| 40 | writel_relaxed(val, gate->clk_base + (gate->regs->rst_set_reg)) | ||
| 41 | #define write_rst_clr(val, gate) \ | ||
| 42 | writel_relaxed(val, gate->clk_base + (gate->regs->rst_clr_reg)) | ||
| 43 | |||
| 44 | #define periph_clk_to_bit(periph) (1 << (gate->clk_num % 32)) | ||
| 45 | |||
| 46 | /* Peripheral gate clock ops */ | ||
| 47 | static int clk_periph_is_enabled(struct clk_hw *hw) | ||
| 48 | { | ||
| 49 | struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw); | ||
| 50 | int state = 1; | ||
| 51 | |||
| 52 | if (!(read_enb(gate) & periph_clk_to_bit(gate))) | ||
| 53 | state = 0; | ||
| 54 | |||
| 55 | if (!(gate->flags & TEGRA_PERIPH_NO_RESET)) | ||
| 56 | if (read_rst(gate) & periph_clk_to_bit(gate)) | ||
| 57 | state = 0; | ||
| 58 | |||
| 59 | return state; | ||
| 60 | } | ||
| 61 | |||
| 62 | static int clk_periph_enable(struct clk_hw *hw) | ||
| 63 | { | ||
| 64 | struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw); | ||
| 65 | unsigned long flags = 0; | ||
| 66 | |||
| 67 | spin_lock_irqsave(&periph_ref_lock, flags); | ||
| 68 | |||
| 69 | gate->enable_refcnt[gate->clk_num]++; | ||
| 70 | if (gate->enable_refcnt[gate->clk_num] > 1) { | ||
| 71 | spin_unlock_irqrestore(&periph_ref_lock, flags); | ||
| 72 | return 0; | ||
| 73 | } | ||
| 74 | |||
| 75 | write_enb_set(periph_clk_to_bit(gate), gate); | ||
| 76 | udelay(2); | ||
| 77 | |||
| 78 | if (!(gate->flags & TEGRA_PERIPH_NO_RESET) && | ||
| 79 | !(gate->flags & TEGRA_PERIPH_MANUAL_RESET)) { | ||
| 80 | if (read_rst(gate) & periph_clk_to_bit(gate)) { | ||
| 81 | udelay(5); /* reset propogation delay */ | ||
| 82 | write_rst_clr(periph_clk_to_bit(gate), gate); | ||
| 83 | } | ||
| 84 | } | ||
| 85 | |||
| 86 | spin_unlock_irqrestore(&periph_ref_lock, flags); | ||
| 87 | |||
| 88 | return 0; | ||
| 89 | } | ||
| 90 | |||
| 91 | static void clk_periph_disable(struct clk_hw *hw) | ||
| 92 | { | ||
| 93 | struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw); | ||
| 94 | unsigned long flags = 0; | ||
| 95 | |||
| 96 | spin_lock_irqsave(&periph_ref_lock, flags); | ||
| 97 | |||
| 98 | gate->enable_refcnt[gate->clk_num]--; | ||
| 99 | if (gate->enable_refcnt[gate->clk_num] > 0) { | ||
| 100 | spin_unlock_irqrestore(&periph_ref_lock, flags); | ||
| 101 | return; | ||
| 102 | } | ||
| 103 | |||
| 104 | /* | ||
| 105 | * If peripheral is in the APB bus then read the APB bus to | ||
| 106 | * flush the write operation in apb bus. This will avoid the | ||
| 107 | * peripheral access after disabling clock | ||
| 108 | */ | ||
| 109 | if (gate->flags & TEGRA_PERIPH_ON_APB) | ||
| 110 | tegra_read_chipid(); | ||
| 111 | |||
| 112 | write_enb_clr(periph_clk_to_bit(gate), gate); | ||
| 113 | |||
| 114 | spin_unlock_irqrestore(&periph_ref_lock, flags); | ||
| 115 | } | ||
| 116 | |||
| 117 | void tegra_periph_reset(struct tegra_clk_periph_gate *gate, bool assert) | ||
| 118 | { | ||
| 119 | if (gate->flags & TEGRA_PERIPH_NO_RESET) | ||
| 120 | return; | ||
| 121 | |||
| 122 | if (assert) { | ||
| 123 | /* | ||
| 124 | * If peripheral is in the APB bus then read the APB bus to | ||
| 125 | * flush the write operation in apb bus. This will avoid the | ||
| 126 | * peripheral access after disabling clock | ||
| 127 | */ | ||
| 128 | if (gate->flags & TEGRA_PERIPH_ON_APB) | ||
| 129 | tegra_read_chipid(); | ||
| 130 | |||
| 131 | write_rst_set(periph_clk_to_bit(gate), gate); | ||
| 132 | } else { | ||
| 133 | write_rst_clr(periph_clk_to_bit(gate), gate); | ||
| 134 | } | ||
| 135 | } | ||
| 136 | |||
| 137 | const struct clk_ops tegra_clk_periph_gate_ops = { | ||
| 138 | .is_enabled = clk_periph_is_enabled, | ||
| 139 | .enable = clk_periph_enable, | ||
| 140 | .disable = clk_periph_disable, | ||
| 141 | }; | ||
| 142 | |||
| 143 | struct clk *tegra_clk_register_periph_gate(const char *name, | ||
| 144 | const char *parent_name, u8 gate_flags, void __iomem *clk_base, | ||
| 145 | unsigned long flags, int clk_num, | ||
| 146 | struct tegra_clk_periph_regs *pregs, int *enable_refcnt) | ||
| 147 | { | ||
| 148 | struct tegra_clk_periph_gate *gate; | ||
| 149 | struct clk *clk; | ||
| 150 | struct clk_init_data init; | ||
| 151 | |||
| 152 | gate = kzalloc(sizeof(*gate), GFP_KERNEL); | ||
| 153 | if (!gate) { | ||
| 154 | pr_err("%s: could not allocate periph gate clk\n", __func__); | ||
| 155 | return ERR_PTR(-ENOMEM); | ||
| 156 | } | ||
| 157 | |||
| 158 | init.name = name; | ||
| 159 | init.flags = flags; | ||
| 160 | init.parent_names = parent_name ? &parent_name : NULL; | ||
| 161 | init.num_parents = parent_name ? 1 : 0; | ||
| 162 | init.ops = &tegra_clk_periph_gate_ops; | ||
| 163 | |||
| 164 | gate->magic = TEGRA_CLK_PERIPH_GATE_MAGIC; | ||
| 165 | gate->clk_base = clk_base; | ||
| 166 | gate->clk_num = clk_num; | ||
| 167 | gate->flags = gate_flags; | ||
| 168 | gate->enable_refcnt = enable_refcnt; | ||
| 169 | gate->regs = pregs; | ||
| 170 | |||
| 171 | /* Data in .init is copied by clk_register(), so stack variable OK */ | ||
| 172 | gate->hw.init = &init; | ||
| 173 | |||
| 174 | clk = clk_register(NULL, &gate->hw); | ||
| 175 | if (IS_ERR(clk)) | ||
| 176 | kfree(gate); | ||
| 177 | |||
| 178 | return clk; | ||
| 179 | } | ||
diff --git a/drivers/clk/tegra/clk-periph.c b/drivers/clk/tegra/clk-periph.c new file mode 100644 index 000000000000..788486e6331a --- /dev/null +++ b/drivers/clk/tegra/clk-periph.c | |||
| @@ -0,0 +1,218 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/clk.h> | ||
| 18 | #include <linux/clk-provider.h> | ||
| 19 | #include <linux/slab.h> | ||
| 20 | #include <linux/err.h> | ||
| 21 | |||
| 22 | #include "clk.h" | ||
| 23 | |||
| 24 | static u8 clk_periph_get_parent(struct clk_hw *hw) | ||
| 25 | { | ||
| 26 | struct tegra_clk_periph *periph = to_clk_periph(hw); | ||
| 27 | const struct clk_ops *mux_ops = periph->mux_ops; | ||
| 28 | struct clk_hw *mux_hw = &periph->mux.hw; | ||
| 29 | |||
| 30 | mux_hw->clk = hw->clk; | ||
| 31 | |||
| 32 | return mux_ops->get_parent(mux_hw); | ||
| 33 | } | ||
| 34 | |||
| 35 | static int clk_periph_set_parent(struct clk_hw *hw, u8 index) | ||
| 36 | { | ||
| 37 | struct tegra_clk_periph *periph = to_clk_periph(hw); | ||
| 38 | const struct clk_ops *mux_ops = periph->mux_ops; | ||
| 39 | struct clk_hw *mux_hw = &periph->mux.hw; | ||
| 40 | |||
| 41 | mux_hw->clk = hw->clk; | ||
| 42 | |||
| 43 | return mux_ops->set_parent(mux_hw, index); | ||
| 44 | } | ||
| 45 | |||
| 46 | static unsigned long clk_periph_recalc_rate(struct clk_hw *hw, | ||
| 47 | unsigned long parent_rate) | ||
| 48 | { | ||
| 49 | struct tegra_clk_periph *periph = to_clk_periph(hw); | ||
| 50 | const struct clk_ops *div_ops = periph->div_ops; | ||
| 51 | struct clk_hw *div_hw = &periph->divider.hw; | ||
| 52 | |||
| 53 | div_hw->clk = hw->clk; | ||
| 54 | |||
| 55 | return div_ops->recalc_rate(div_hw, parent_rate); | ||
| 56 | } | ||
| 57 | |||
| 58 | static long clk_periph_round_rate(struct clk_hw *hw, unsigned long rate, | ||
| 59 | unsigned long *prate) | ||
| 60 | { | ||
| 61 | struct tegra_clk_periph *periph = to_clk_periph(hw); | ||
| 62 | const struct clk_ops *div_ops = periph->div_ops; | ||
| 63 | struct clk_hw *div_hw = &periph->divider.hw; | ||
| 64 | |||
| 65 | div_hw->clk = hw->clk; | ||
| 66 | |||
| 67 | return div_ops->round_rate(div_hw, rate, prate); | ||
| 68 | } | ||
| 69 | |||
| 70 | static int clk_periph_set_rate(struct clk_hw *hw, unsigned long rate, | ||
| 71 | unsigned long parent_rate) | ||
| 72 | { | ||
| 73 | struct tegra_clk_periph *periph = to_clk_periph(hw); | ||
| 74 | const struct clk_ops *div_ops = periph->div_ops; | ||
| 75 | struct clk_hw *div_hw = &periph->divider.hw; | ||
| 76 | |||
| 77 | div_hw->clk = hw->clk; | ||
| 78 | |||
| 79 | return div_ops->set_rate(div_hw, rate, parent_rate); | ||
| 80 | } | ||
| 81 | |||
| 82 | static int clk_periph_is_enabled(struct clk_hw *hw) | ||
| 83 | { | ||
| 84 | struct tegra_clk_periph *periph = to_clk_periph(hw); | ||
| 85 | const struct clk_ops *gate_ops = periph->gate_ops; | ||
| 86 | struct clk_hw *gate_hw = &periph->gate.hw; | ||
| 87 | |||
| 88 | gate_hw->clk = hw->clk; | ||
| 89 | |||
| 90 | return gate_ops->is_enabled(gate_hw); | ||
| 91 | } | ||
| 92 | |||
| 93 | static int clk_periph_enable(struct clk_hw *hw) | ||
| 94 | { | ||
| 95 | struct tegra_clk_periph *periph = to_clk_periph(hw); | ||
| 96 | const struct clk_ops *gate_ops = periph->gate_ops; | ||
| 97 | struct clk_hw *gate_hw = &periph->gate.hw; | ||
| 98 | |||
| 99 | gate_hw->clk = hw->clk; | ||
| 100 | |||
| 101 | return gate_ops->enable(gate_hw); | ||
| 102 | } | ||
| 103 | |||
| 104 | static void clk_periph_disable(struct clk_hw *hw) | ||
| 105 | { | ||
| 106 | struct tegra_clk_periph *periph = to_clk_periph(hw); | ||
| 107 | const struct clk_ops *gate_ops = periph->gate_ops; | ||
| 108 | struct clk_hw *gate_hw = &periph->gate.hw; | ||
| 109 | |||
| 110 | gate_ops->disable(gate_hw); | ||
| 111 | } | ||
| 112 | |||
| 113 | void tegra_periph_reset_deassert(struct clk *c) | ||
| 114 | { | ||
| 115 | struct clk_hw *hw = __clk_get_hw(c); | ||
| 116 | struct tegra_clk_periph *periph = to_clk_periph(hw); | ||
| 117 | struct tegra_clk_periph_gate *gate; | ||
| 118 | |||
| 119 | if (periph->magic != TEGRA_CLK_PERIPH_MAGIC) { | ||
| 120 | gate = to_clk_periph_gate(hw); | ||
| 121 | if (gate->magic != TEGRA_CLK_PERIPH_GATE_MAGIC) { | ||
| 122 | WARN_ON(1); | ||
| 123 | return; | ||
| 124 | } | ||
| 125 | } else { | ||
| 126 | gate = &periph->gate; | ||
| 127 | } | ||
| 128 | |||
| 129 | tegra_periph_reset(gate, 0); | ||
| 130 | } | ||
| 131 | |||
| 132 | void tegra_periph_reset_assert(struct clk *c) | ||
| 133 | { | ||
| 134 | struct clk_hw *hw = __clk_get_hw(c); | ||
| 135 | struct tegra_clk_periph *periph = to_clk_periph(hw); | ||
| 136 | struct tegra_clk_periph_gate *gate; | ||
| 137 | |||
| 138 | if (periph->magic != TEGRA_CLK_PERIPH_MAGIC) { | ||
| 139 | gate = to_clk_periph_gate(hw); | ||
| 140 | if (gate->magic != TEGRA_CLK_PERIPH_GATE_MAGIC) { | ||
| 141 | WARN_ON(1); | ||
| 142 | return; | ||
| 143 | } | ||
| 144 | } else { | ||
| 145 | gate = &periph->gate; | ||
| 146 | } | ||
| 147 | |||
| 148 | tegra_periph_reset(gate, 1); | ||
| 149 | } | ||
| 150 | |||
| 151 | const struct clk_ops tegra_clk_periph_ops = { | ||
| 152 | .get_parent = clk_periph_get_parent, | ||
| 153 | .set_parent = clk_periph_set_parent, | ||
| 154 | .recalc_rate = clk_periph_recalc_rate, | ||
| 155 | .round_rate = clk_periph_round_rate, | ||
| 156 | .set_rate = clk_periph_set_rate, | ||
| 157 | .is_enabled = clk_periph_is_enabled, | ||
| 158 | .enable = clk_periph_enable, | ||
| 159 | .disable = clk_periph_disable, | ||
| 160 | }; | ||
| 161 | |||
| 162 | const struct clk_ops tegra_clk_periph_nodiv_ops = { | ||
| 163 | .get_parent = clk_periph_get_parent, | ||
| 164 | .set_parent = clk_periph_set_parent, | ||
| 165 | .is_enabled = clk_periph_is_enabled, | ||
| 166 | .enable = clk_periph_enable, | ||
| 167 | .disable = clk_periph_disable, | ||
| 168 | }; | ||
| 169 | |||
| 170 | static struct clk *_tegra_clk_register_periph(const char *name, | ||
| 171 | const char **parent_names, int num_parents, | ||
| 172 | struct tegra_clk_periph *periph, | ||
| 173 | void __iomem *clk_base, u32 offset, bool div) | ||
| 174 | { | ||
| 175 | struct clk *clk; | ||
| 176 | struct clk_init_data init; | ||
| 177 | |||
| 178 | init.name = name; | ||
| 179 | init.ops = div ? &tegra_clk_periph_ops : &tegra_clk_periph_nodiv_ops; | ||
| 180 | init.flags = div ? 0 : CLK_SET_RATE_PARENT; | ||
| 181 | init.parent_names = parent_names; | ||
| 182 | init.num_parents = num_parents; | ||
| 183 | |||
| 184 | /* Data in .init is copied by clk_register(), so stack variable OK */ | ||
| 185 | periph->hw.init = &init; | ||
| 186 | periph->magic = TEGRA_CLK_PERIPH_MAGIC; | ||
| 187 | periph->mux.reg = clk_base + offset; | ||
| 188 | periph->divider.reg = div ? (clk_base + offset) : NULL; | ||
| 189 | periph->gate.clk_base = clk_base; | ||
| 190 | |||
| 191 | clk = clk_register(NULL, &periph->hw); | ||
| 192 | if (IS_ERR(clk)) | ||
| 193 | return clk; | ||
| 194 | |||
| 195 | periph->mux.hw.clk = clk; | ||
| 196 | periph->divider.hw.clk = div ? clk : NULL; | ||
| 197 | periph->gate.hw.clk = clk; | ||
| 198 | |||
| 199 | return clk; | ||
| 200 | } | ||
| 201 | |||
| 202 | struct clk *tegra_clk_register_periph(const char *name, | ||
| 203 | const char **parent_names, int num_parents, | ||
| 204 | struct tegra_clk_periph *periph, void __iomem *clk_base, | ||
| 205 | u32 offset) | ||
| 206 | { | ||
| 207 | return _tegra_clk_register_periph(name, parent_names, num_parents, | ||
| 208 | periph, clk_base, offset, true); | ||
| 209 | } | ||
| 210 | |||
| 211 | struct clk *tegra_clk_register_periph_nodiv(const char *name, | ||
| 212 | const char **parent_names, int num_parents, | ||
| 213 | struct tegra_clk_periph *periph, void __iomem *clk_base, | ||
| 214 | u32 offset) | ||
| 215 | { | ||
| 216 | return _tegra_clk_register_periph(name, parent_names, num_parents, | ||
| 217 | periph, clk_base, offset, false); | ||
| 218 | } | ||
diff --git a/drivers/clk/tegra/clk-pll-out.c b/drivers/clk/tegra/clk-pll-out.c new file mode 100644 index 000000000000..3598987a451d --- /dev/null +++ b/drivers/clk/tegra/clk-pll-out.c | |||
| @@ -0,0 +1,123 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/kernel.h> | ||
| 18 | #include <linux/io.h> | ||
| 19 | #include <linux/err.h> | ||
| 20 | #include <linux/delay.h> | ||
| 21 | #include <linux/slab.h> | ||
| 22 | #include <linux/clk-provider.h> | ||
| 23 | #include <linux/clk.h> | ||
| 24 | |||
| 25 | #include "clk.h" | ||
| 26 | |||
| 27 | #define pll_out_enb(p) (BIT(p->enb_bit_idx)) | ||
| 28 | #define pll_out_rst(p) (BIT(p->rst_bit_idx)) | ||
| 29 | |||
| 30 | static int clk_pll_out_is_enabled(struct clk_hw *hw) | ||
| 31 | { | ||
| 32 | struct tegra_clk_pll_out *pll_out = to_clk_pll_out(hw); | ||
| 33 | u32 val = readl_relaxed(pll_out->reg); | ||
| 34 | int state; | ||
| 35 | |||
| 36 | state = (val & pll_out_enb(pll_out)) ? 1 : 0; | ||
| 37 | if (!(val & (pll_out_rst(pll_out)))) | ||
| 38 | state = 0; | ||
| 39 | return state; | ||
| 40 | } | ||
| 41 | |||
| 42 | static int clk_pll_out_enable(struct clk_hw *hw) | ||
| 43 | { | ||
| 44 | struct tegra_clk_pll_out *pll_out = to_clk_pll_out(hw); | ||
| 45 | unsigned long flags = 0; | ||
| 46 | u32 val; | ||
| 47 | |||
| 48 | if (pll_out->lock) | ||
| 49 | spin_lock_irqsave(pll_out->lock, flags); | ||
| 50 | |||
| 51 | val = readl_relaxed(pll_out->reg); | ||
| 52 | |||
| 53 | val |= (pll_out_enb(pll_out) | pll_out_rst(pll_out)); | ||
| 54 | |||
| 55 | writel_relaxed(val, pll_out->reg); | ||
| 56 | udelay(2); | ||
| 57 | |||
| 58 | if (pll_out->lock) | ||
| 59 | spin_unlock_irqrestore(pll_out->lock, flags); | ||
| 60 | |||
| 61 | return 0; | ||
| 62 | } | ||
| 63 | |||
| 64 | static void clk_pll_out_disable(struct clk_hw *hw) | ||
| 65 | { | ||
| 66 | struct tegra_clk_pll_out *pll_out = to_clk_pll_out(hw); | ||
| 67 | unsigned long flags = 0; | ||
| 68 | u32 val; | ||
| 69 | |||
| 70 | if (pll_out->lock) | ||
| 71 | spin_lock_irqsave(pll_out->lock, flags); | ||
| 72 | |||
| 73 | val = readl_relaxed(pll_out->reg); | ||
| 74 | |||
| 75 | val &= ~(pll_out_enb(pll_out) | pll_out_rst(pll_out)); | ||
| 76 | |||
| 77 | writel_relaxed(val, pll_out->reg); | ||
| 78 | udelay(2); | ||
| 79 | |||
| 80 | if (pll_out->lock) | ||
| 81 | spin_unlock_irqrestore(pll_out->lock, flags); | ||
| 82 | } | ||
| 83 | |||
| 84 | const struct clk_ops tegra_clk_pll_out_ops = { | ||
| 85 | .is_enabled = clk_pll_out_is_enabled, | ||
| 86 | .enable = clk_pll_out_enable, | ||
| 87 | .disable = clk_pll_out_disable, | ||
| 88 | }; | ||
| 89 | |||
| 90 | struct clk *tegra_clk_register_pll_out(const char *name, | ||
| 91 | const char *parent_name, void __iomem *reg, u8 enb_bit_idx, | ||
| 92 | u8 rst_bit_idx, unsigned long flags, u8 pll_out_flags, | ||
| 93 | spinlock_t *lock) | ||
| 94 | { | ||
| 95 | struct tegra_clk_pll_out *pll_out; | ||
| 96 | struct clk *clk; | ||
| 97 | struct clk_init_data init; | ||
| 98 | |||
| 99 | pll_out = kzalloc(sizeof(*pll_out), GFP_KERNEL); | ||
| 100 | if (!pll_out) | ||
| 101 | return ERR_PTR(-ENOMEM); | ||
| 102 | |||
| 103 | init.name = name; | ||
| 104 | init.ops = &tegra_clk_pll_out_ops; | ||
| 105 | init.parent_names = (parent_name ? &parent_name : NULL); | ||
| 106 | init.num_parents = (parent_name ? 1 : 0); | ||
| 107 | init.flags = flags; | ||
| 108 | |||
| 109 | pll_out->reg = reg; | ||
| 110 | pll_out->enb_bit_idx = enb_bit_idx; | ||
| 111 | pll_out->rst_bit_idx = rst_bit_idx; | ||
| 112 | pll_out->flags = pll_out_flags; | ||
| 113 | pll_out->lock = lock; | ||
| 114 | |||
| 115 | /* Data in .init is copied by clk_register(), so stack variable OK */ | ||
| 116 | pll_out->hw.init = &init; | ||
| 117 | |||
| 118 | clk = clk_register(NULL, &pll_out->hw); | ||
| 119 | if (IS_ERR(clk)) | ||
| 120 | kfree(pll_out); | ||
| 121 | |||
| 122 | return clk; | ||
| 123 | } | ||
diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c new file mode 100644 index 000000000000..165f24734c1b --- /dev/null +++ b/drivers/clk/tegra/clk-pll.c | |||
| @@ -0,0 +1,648 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/slab.h> | ||
| 18 | #include <linux/io.h> | ||
| 19 | #include <linux/delay.h> | ||
| 20 | #include <linux/err.h> | ||
| 21 | #include <linux/clk-provider.h> | ||
| 22 | #include <linux/clk.h> | ||
| 23 | |||
| 24 | #include "clk.h" | ||
| 25 | |||
| 26 | #define PLL_BASE_BYPASS BIT(31) | ||
| 27 | #define PLL_BASE_ENABLE BIT(30) | ||
| 28 | #define PLL_BASE_REF_ENABLE BIT(29) | ||
| 29 | #define PLL_BASE_OVERRIDE BIT(28) | ||
| 30 | |||
| 31 | #define PLL_BASE_DIVP_SHIFT 20 | ||
| 32 | #define PLL_BASE_DIVP_WIDTH 3 | ||
| 33 | #define PLL_BASE_DIVN_SHIFT 8 | ||
| 34 | #define PLL_BASE_DIVN_WIDTH 10 | ||
| 35 | #define PLL_BASE_DIVM_SHIFT 0 | ||
| 36 | #define PLL_BASE_DIVM_WIDTH 5 | ||
| 37 | #define PLLU_POST_DIVP_MASK 0x1 | ||
| 38 | |||
| 39 | #define PLL_MISC_DCCON_SHIFT 20 | ||
| 40 | #define PLL_MISC_CPCON_SHIFT 8 | ||
| 41 | #define PLL_MISC_CPCON_WIDTH 4 | ||
| 42 | #define PLL_MISC_CPCON_MASK ((1 << PLL_MISC_CPCON_WIDTH) - 1) | ||
| 43 | #define PLL_MISC_LFCON_SHIFT 4 | ||
| 44 | #define PLL_MISC_LFCON_WIDTH 4 | ||
| 45 | #define PLL_MISC_LFCON_MASK ((1 << PLL_MISC_LFCON_WIDTH) - 1) | ||
| 46 | #define PLL_MISC_VCOCON_SHIFT 0 | ||
| 47 | #define PLL_MISC_VCOCON_WIDTH 4 | ||
| 48 | #define PLL_MISC_VCOCON_MASK ((1 << PLL_MISC_VCOCON_WIDTH) - 1) | ||
| 49 | |||
| 50 | #define OUT_OF_TABLE_CPCON 8 | ||
| 51 | |||
| 52 | #define PMC_PLLP_WB0_OVERRIDE 0xf8 | ||
| 53 | #define PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE BIT(12) | ||
| 54 | #define PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE BIT(11) | ||
| 55 | |||
| 56 | #define PLL_POST_LOCK_DELAY 50 | ||
| 57 | |||
| 58 | #define PLLDU_LFCON_SET_DIVN 600 | ||
| 59 | |||
| 60 | #define PLLE_BASE_DIVCML_SHIFT 24 | ||
| 61 | #define PLLE_BASE_DIVCML_WIDTH 4 | ||
| 62 | #define PLLE_BASE_DIVP_SHIFT 16 | ||
| 63 | #define PLLE_BASE_DIVP_WIDTH 7 | ||
| 64 | #define PLLE_BASE_DIVN_SHIFT 8 | ||
| 65 | #define PLLE_BASE_DIVN_WIDTH 8 | ||
| 66 | #define PLLE_BASE_DIVM_SHIFT 0 | ||
| 67 | #define PLLE_BASE_DIVM_WIDTH 8 | ||
| 68 | |||
| 69 | #define PLLE_MISC_SETUP_BASE_SHIFT 16 | ||
| 70 | #define PLLE_MISC_SETUP_BASE_MASK (0xffff << PLLE_MISC_SETUP_BASE_SHIFT) | ||
| 71 | #define PLLE_MISC_LOCK_ENABLE BIT(9) | ||
| 72 | #define PLLE_MISC_READY BIT(15) | ||
| 73 | #define PLLE_MISC_SETUP_EX_SHIFT 2 | ||
| 74 | #define PLLE_MISC_SETUP_EX_MASK (3 << PLLE_MISC_SETUP_EX_SHIFT) | ||
| 75 | #define PLLE_MISC_SETUP_MASK (PLLE_MISC_SETUP_BASE_MASK | \ | ||
| 76 | PLLE_MISC_SETUP_EX_MASK) | ||
| 77 | #define PLLE_MISC_SETUP_VALUE (7 << PLLE_MISC_SETUP_BASE_SHIFT) | ||
| 78 | |||
| 79 | #define PLLE_SS_CTRL 0x68 | ||
| 80 | #define PLLE_SS_DISABLE (7 << 10) | ||
| 81 | |||
| 82 | #define PMC_SATA_PWRGT 0x1ac | ||
| 83 | #define PMC_SATA_PWRGT_PLLE_IDDQ_VALUE BIT(5) | ||
| 84 | #define PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL BIT(4) | ||
| 85 | |||
| 86 | #define pll_readl(offset, p) readl_relaxed(p->clk_base + offset) | ||
| 87 | #define pll_readl_base(p) pll_readl(p->params->base_reg, p) | ||
| 88 | #define pll_readl_misc(p) pll_readl(p->params->misc_reg, p) | ||
| 89 | |||
| 90 | #define pll_writel(val, offset, p) writel_relaxed(val, p->clk_base + offset) | ||
| 91 | #define pll_writel_base(val, p) pll_writel(val, p->params->base_reg, p) | ||
| 92 | #define pll_writel_misc(val, p) pll_writel(val, p->params->misc_reg, p) | ||
| 93 | |||
| 94 | #define mask(w) ((1 << (w)) - 1) | ||
| 95 | #define divm_mask(p) mask(p->divm_width) | ||
| 96 | #define divn_mask(p) mask(p->divn_width) | ||
| 97 | #define divp_mask(p) (p->flags & TEGRA_PLLU ? PLLU_POST_DIVP_MASK : \ | ||
| 98 | mask(p->divp_width)) | ||
| 99 | |||
| 100 | #define divm_max(p) (divm_mask(p)) | ||
| 101 | #define divn_max(p) (divn_mask(p)) | ||
| 102 | #define divp_max(p) (1 << (divp_mask(p))) | ||
| 103 | |||
| 104 | static void clk_pll_enable_lock(struct tegra_clk_pll *pll) | ||
| 105 | { | ||
| 106 | u32 val; | ||
| 107 | |||
| 108 | if (!(pll->flags & TEGRA_PLL_USE_LOCK)) | ||
| 109 | return; | ||
| 110 | |||
| 111 | val = pll_readl_misc(pll); | ||
| 112 | val |= BIT(pll->params->lock_enable_bit_idx); | ||
| 113 | pll_writel_misc(val, pll); | ||
| 114 | } | ||
| 115 | |||
| 116 | static int clk_pll_wait_for_lock(struct tegra_clk_pll *pll, | ||
| 117 | void __iomem *lock_addr, u32 lock_bit_idx) | ||
| 118 | { | ||
| 119 | int i; | ||
| 120 | u32 val; | ||
| 121 | |||
| 122 | if (!(pll->flags & TEGRA_PLL_USE_LOCK)) { | ||
| 123 | udelay(pll->params->lock_delay); | ||
| 124 | return 0; | ||
| 125 | } | ||
| 126 | |||
| 127 | for (i = 0; i < pll->params->lock_delay; i++) { | ||
| 128 | val = readl_relaxed(lock_addr); | ||
| 129 | if (val & BIT(lock_bit_idx)) { | ||
| 130 | udelay(PLL_POST_LOCK_DELAY); | ||
| 131 | return 0; | ||
| 132 | } | ||
| 133 | udelay(2); /* timeout = 2 * lock time */ | ||
| 134 | } | ||
| 135 | |||
| 136 | pr_err("%s: Timed out waiting for pll %s lock\n", __func__, | ||
| 137 | __clk_get_name(pll->hw.clk)); | ||
| 138 | |||
| 139 | return -1; | ||
| 140 | } | ||
| 141 | |||
| 142 | static int clk_pll_is_enabled(struct clk_hw *hw) | ||
| 143 | { | ||
| 144 | struct tegra_clk_pll *pll = to_clk_pll(hw); | ||
| 145 | u32 val; | ||
| 146 | |||
| 147 | if (pll->flags & TEGRA_PLLM) { | ||
| 148 | val = readl_relaxed(pll->pmc + PMC_PLLP_WB0_OVERRIDE); | ||
| 149 | if (val & PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE) | ||
| 150 | return val & PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE ? 1 : 0; | ||
| 151 | } | ||
| 152 | |||
| 153 | val = pll_readl_base(pll); | ||
| 154 | |||
| 155 | return val & PLL_BASE_ENABLE ? 1 : 0; | ||
| 156 | } | ||
| 157 | |||
| 158 | static int _clk_pll_enable(struct clk_hw *hw) | ||
| 159 | { | ||
| 160 | struct tegra_clk_pll *pll = to_clk_pll(hw); | ||
| 161 | u32 val; | ||
| 162 | |||
| 163 | clk_pll_enable_lock(pll); | ||
| 164 | |||
| 165 | val = pll_readl_base(pll); | ||
| 166 | val &= ~PLL_BASE_BYPASS; | ||
| 167 | val |= PLL_BASE_ENABLE; | ||
| 168 | pll_writel_base(val, pll); | ||
| 169 | |||
| 170 | if (pll->flags & TEGRA_PLLM) { | ||
| 171 | val = readl_relaxed(pll->pmc + PMC_PLLP_WB0_OVERRIDE); | ||
| 172 | val |= PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE; | ||
| 173 | writel_relaxed(val, pll->pmc + PMC_PLLP_WB0_OVERRIDE); | ||
| 174 | } | ||
| 175 | |||
| 176 | clk_pll_wait_for_lock(pll, pll->clk_base + pll->params->base_reg, | ||
| 177 | pll->params->lock_bit_idx); | ||
| 178 | |||
| 179 | return 0; | ||
| 180 | } | ||
| 181 | |||
| 182 | static void _clk_pll_disable(struct clk_hw *hw) | ||
| 183 | { | ||
| 184 | struct tegra_clk_pll *pll = to_clk_pll(hw); | ||
| 185 | u32 val; | ||
| 186 | |||
| 187 | val = pll_readl_base(pll); | ||
| 188 | val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE); | ||
| 189 | pll_writel_base(val, pll); | ||
| 190 | |||
| 191 | if (pll->flags & TEGRA_PLLM) { | ||
| 192 | val = readl_relaxed(pll->pmc + PMC_PLLP_WB0_OVERRIDE); | ||
| 193 | val &= ~PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE; | ||
| 194 | writel_relaxed(val, pll->pmc + PMC_PLLP_WB0_OVERRIDE); | ||
| 195 | } | ||
| 196 | } | ||
| 197 | |||
| 198 | static int clk_pll_enable(struct clk_hw *hw) | ||
| 199 | { | ||
| 200 | struct tegra_clk_pll *pll = to_clk_pll(hw); | ||
| 201 | unsigned long flags = 0; | ||
| 202 | int ret; | ||
| 203 | |||
| 204 | if (pll->lock) | ||
| 205 | spin_lock_irqsave(pll->lock, flags); | ||
| 206 | |||
| 207 | ret = _clk_pll_enable(hw); | ||
| 208 | |||
| 209 | if (pll->lock) | ||
| 210 | spin_unlock_irqrestore(pll->lock, flags); | ||
| 211 | |||
| 212 | return ret; | ||
| 213 | } | ||
| 214 | |||
| 215 | static void clk_pll_disable(struct clk_hw *hw) | ||
| 216 | { | ||
| 217 | struct tegra_clk_pll *pll = to_clk_pll(hw); | ||
| 218 | unsigned long flags = 0; | ||
| 219 | |||
| 220 | if (pll->lock) | ||
| 221 | spin_lock_irqsave(pll->lock, flags); | ||
| 222 | |||
| 223 | _clk_pll_disable(hw); | ||
| 224 | |||
| 225 | if (pll->lock) | ||
| 226 | spin_unlock_irqrestore(pll->lock, flags); | ||
| 227 | } | ||
| 228 | |||
| 229 | static int _get_table_rate(struct clk_hw *hw, | ||
| 230 | struct tegra_clk_pll_freq_table *cfg, | ||
| 231 | unsigned long rate, unsigned long parent_rate) | ||
| 232 | { | ||
| 233 | struct tegra_clk_pll *pll = to_clk_pll(hw); | ||
| 234 | struct tegra_clk_pll_freq_table *sel; | ||
| 235 | |||
| 236 | for (sel = pll->freq_table; sel->input_rate != 0; sel++) | ||
| 237 | if (sel->input_rate == parent_rate && | ||
| 238 | sel->output_rate == rate) | ||
| 239 | break; | ||
| 240 | |||
| 241 | if (sel->input_rate == 0) | ||
| 242 | return -EINVAL; | ||
| 243 | |||
| 244 | BUG_ON(sel->p < 1); | ||
| 245 | |||
| 246 | cfg->input_rate = sel->input_rate; | ||
| 247 | cfg->output_rate = sel->output_rate; | ||
| 248 | cfg->m = sel->m; | ||
| 249 | cfg->n = sel->n; | ||
| 250 | cfg->p = sel->p; | ||
| 251 | cfg->cpcon = sel->cpcon; | ||
| 252 | |||
| 253 | return 0; | ||
| 254 | } | ||
| 255 | |||
| 256 | static int _calc_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg, | ||
| 257 | unsigned long rate, unsigned long parent_rate) | ||
| 258 | { | ||
| 259 | struct tegra_clk_pll *pll = to_clk_pll(hw); | ||
| 260 | unsigned long cfreq; | ||
| 261 | u32 p_div = 0; | ||
| 262 | |||
| 263 | switch (parent_rate) { | ||
| 264 | case 12000000: | ||
| 265 | case 26000000: | ||
| 266 | cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2000000; | ||
| 267 | break; | ||
| 268 | case 13000000: | ||
| 269 | cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2600000; | ||
| 270 | break; | ||
| 271 | case 16800000: | ||
| 272 | case 19200000: | ||
| 273 | cfreq = (rate <= 1200000 * 1000) ? 1200000 : 2400000; | ||
| 274 | break; | ||
| 275 | case 9600000: | ||
| 276 | case 28800000: | ||
| 277 | /* | ||
| 278 | * PLL_P_OUT1 rate is not listed in PLLA table | ||
| 279 | */ | ||
| 280 | cfreq = parent_rate/(parent_rate/1000000); | ||
| 281 | break; | ||
| 282 | default: | ||
| 283 | pr_err("%s Unexpected reference rate %lu\n", | ||
| 284 | __func__, parent_rate); | ||
| 285 | BUG(); | ||
| 286 | } | ||
| 287 | |||
| 288 | /* Raise VCO to guarantee 0.5% accuracy */ | ||
| 289 | for (cfg->output_rate = rate; cfg->output_rate < 200 * cfreq; | ||
| 290 | cfg->output_rate <<= 1) | ||
| 291 | p_div++; | ||
| 292 | |||
| 293 | cfg->p = 1 << p_div; | ||
| 294 | cfg->m = parent_rate / cfreq; | ||
| 295 | cfg->n = cfg->output_rate / cfreq; | ||
| 296 | cfg->cpcon = OUT_OF_TABLE_CPCON; | ||
| 297 | |||
| 298 | if (cfg->m > divm_max(pll) || cfg->n > divn_max(pll) || | ||
| 299 | cfg->p > divp_max(pll) || cfg->output_rate > pll->params->vco_max) { | ||
| 300 | pr_err("%s: Failed to set %s rate %lu\n", | ||
| 301 | __func__, __clk_get_name(hw->clk), rate); | ||
| 302 | return -EINVAL; | ||
| 303 | } | ||
| 304 | |||
| 305 | return 0; | ||
| 306 | } | ||
| 307 | |||
| 308 | static int _program_pll(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg, | ||
| 309 | unsigned long rate) | ||
| 310 | { | ||
| 311 | struct tegra_clk_pll *pll = to_clk_pll(hw); | ||
| 312 | unsigned long flags = 0; | ||
| 313 | u32 divp, val, old_base; | ||
| 314 | int state; | ||
| 315 | |||
| 316 | divp = __ffs(cfg->p); | ||
| 317 | |||
| 318 | if (pll->flags & TEGRA_PLLU) | ||
| 319 | divp ^= 1; | ||
| 320 | |||
| 321 | if (pll->lock) | ||
| 322 | spin_lock_irqsave(pll->lock, flags); | ||
| 323 | |||
| 324 | old_base = val = pll_readl_base(pll); | ||
| 325 | val &= ~((divm_mask(pll) << pll->divm_shift) | | ||
| 326 | (divn_mask(pll) << pll->divn_shift) | | ||
| 327 | (divp_mask(pll) << pll->divp_shift)); | ||
| 328 | val |= ((cfg->m << pll->divm_shift) | | ||
| 329 | (cfg->n << pll->divn_shift) | | ||
| 330 | (divp << pll->divp_shift)); | ||
| 331 | if (val == old_base) { | ||
| 332 | if (pll->lock) | ||
| 333 | spin_unlock_irqrestore(pll->lock, flags); | ||
| 334 | return 0; | ||
| 335 | } | ||
| 336 | |||
| 337 | state = clk_pll_is_enabled(hw); | ||
| 338 | |||
| 339 | if (state) { | ||
| 340 | _clk_pll_disable(hw); | ||
| 341 | val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE); | ||
| 342 | } | ||
| 343 | pll_writel_base(val, pll); | ||
| 344 | |||
| 345 | if (pll->flags & TEGRA_PLL_HAS_CPCON) { | ||
| 346 | val = pll_readl_misc(pll); | ||
| 347 | val &= ~(PLL_MISC_CPCON_MASK << PLL_MISC_CPCON_SHIFT); | ||
| 348 | val |= cfg->cpcon << PLL_MISC_CPCON_SHIFT; | ||
| 349 | if (pll->flags & TEGRA_PLL_SET_LFCON) { | ||
| 350 | val &= ~(PLL_MISC_LFCON_MASK << PLL_MISC_LFCON_SHIFT); | ||
| 351 | if (cfg->n >= PLLDU_LFCON_SET_DIVN) | ||
| 352 | val |= 0x1 << PLL_MISC_LFCON_SHIFT; | ||
| 353 | } else if (pll->flags & TEGRA_PLL_SET_DCCON) { | ||
| 354 | val &= ~(0x1 << PLL_MISC_DCCON_SHIFT); | ||
| 355 | if (rate >= (pll->params->vco_max >> 1)) | ||
| 356 | val |= 0x1 << PLL_MISC_DCCON_SHIFT; | ||
| 357 | } | ||
| 358 | pll_writel_misc(val, pll); | ||
| 359 | } | ||
| 360 | |||
| 361 | if (pll->lock) | ||
| 362 | spin_unlock_irqrestore(pll->lock, flags); | ||
| 363 | |||
| 364 | if (state) | ||
| 365 | clk_pll_enable(hw); | ||
| 366 | |||
| 367 | return 0; | ||
| 368 | } | ||
| 369 | |||
| 370 | static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, | ||
| 371 | unsigned long parent_rate) | ||
| 372 | { | ||
| 373 | struct tegra_clk_pll *pll = to_clk_pll(hw); | ||
| 374 | struct tegra_clk_pll_freq_table cfg; | ||
| 375 | |||
| 376 | if (pll->flags & TEGRA_PLL_FIXED) { | ||
| 377 | if (rate != pll->fixed_rate) { | ||
| 378 | pr_err("%s: Can not change %s fixed rate %lu to %lu\n", | ||
| 379 | __func__, __clk_get_name(hw->clk), | ||
| 380 | pll->fixed_rate, rate); | ||
| 381 | return -EINVAL; | ||
| 382 | } | ||
| 383 | return 0; | ||
| 384 | } | ||
| 385 | |||
| 386 | if (_get_table_rate(hw, &cfg, rate, parent_rate) && | ||
| 387 | _calc_rate(hw, &cfg, rate, parent_rate)) | ||
| 388 | return -EINVAL; | ||
| 389 | |||
| 390 | return _program_pll(hw, &cfg, rate); | ||
| 391 | } | ||
| 392 | |||
| 393 | static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, | ||
| 394 | unsigned long *prate) | ||
| 395 | { | ||
| 396 | struct tegra_clk_pll *pll = to_clk_pll(hw); | ||
| 397 | struct tegra_clk_pll_freq_table cfg; | ||
| 398 | u64 output_rate = *prate; | ||
| 399 | |||
| 400 | if (pll->flags & TEGRA_PLL_FIXED) | ||
| 401 | return pll->fixed_rate; | ||
| 402 | |||
| 403 | /* PLLM is used for memory; we do not change rate */ | ||
| 404 | if (pll->flags & TEGRA_PLLM) | ||
| 405 | return __clk_get_rate(hw->clk); | ||
| 406 | |||
| 407 | if (_get_table_rate(hw, &cfg, rate, *prate) && | ||
| 408 | _calc_rate(hw, &cfg, rate, *prate)) | ||
| 409 | return -EINVAL; | ||
| 410 | |||
| 411 | output_rate *= cfg.n; | ||
| 412 | do_div(output_rate, cfg.m * cfg.p); | ||
| 413 | |||
| 414 | return output_rate; | ||
| 415 | } | ||
| 416 | |||
| 417 | static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, | ||
| 418 | unsigned long parent_rate) | ||
| 419 | { | ||
| 420 | struct tegra_clk_pll *pll = to_clk_pll(hw); | ||
| 421 | u32 val = pll_readl_base(pll); | ||
| 422 | u32 divn = 0, divm = 0, divp = 0; | ||
| 423 | u64 rate = parent_rate; | ||
| 424 | |||
| 425 | if (val & PLL_BASE_BYPASS) | ||
| 426 | return parent_rate; | ||
| 427 | |||
| 428 | if ((pll->flags & TEGRA_PLL_FIXED) && !(val & PLL_BASE_OVERRIDE)) { | ||
| 429 | struct tegra_clk_pll_freq_table sel; | ||
| 430 | if (_get_table_rate(hw, &sel, pll->fixed_rate, parent_rate)) { | ||
| 431 | pr_err("Clock %s has unknown fixed frequency\n", | ||
| 432 | __clk_get_name(hw->clk)); | ||
| 433 | BUG(); | ||
| 434 | } | ||
| 435 | return pll->fixed_rate; | ||
| 436 | } | ||
| 437 | |||
| 438 | divp = (val >> pll->divp_shift) & (divp_mask(pll)); | ||
| 439 | if (pll->flags & TEGRA_PLLU) | ||
| 440 | divp ^= 1; | ||
| 441 | |||
| 442 | divn = (val >> pll->divn_shift) & (divn_mask(pll)); | ||
| 443 | divm = (val >> pll->divm_shift) & (divm_mask(pll)); | ||
| 444 | divm *= (1 << divp); | ||
| 445 | |||
| 446 | rate *= divn; | ||
| 447 | do_div(rate, divm); | ||
| 448 | return rate; | ||
| 449 | } | ||
| 450 | |||
| 451 | static int clk_plle_training(struct tegra_clk_pll *pll) | ||
| 452 | { | ||
| 453 | u32 val; | ||
| 454 | unsigned long timeout; | ||
| 455 | |||
| 456 | if (!pll->pmc) | ||
| 457 | return -ENOSYS; | ||
| 458 | |||
| 459 | /* | ||
| 460 | * PLLE is already disabled, and setup cleared; | ||
| 461 | * create falling edge on PLLE IDDQ input. | ||
| 462 | */ | ||
| 463 | val = readl(pll->pmc + PMC_SATA_PWRGT); | ||
| 464 | val |= PMC_SATA_PWRGT_PLLE_IDDQ_VALUE; | ||
| 465 | writel(val, pll->pmc + PMC_SATA_PWRGT); | ||
| 466 | |||
| 467 | val = readl(pll->pmc + PMC_SATA_PWRGT); | ||
| 468 | val |= PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL; | ||
| 469 | writel(val, pll->pmc + PMC_SATA_PWRGT); | ||
| 470 | |||
| 471 | val = readl(pll->pmc + PMC_SATA_PWRGT); | ||
| 472 | val &= ~PMC_SATA_PWRGT_PLLE_IDDQ_VALUE; | ||
| 473 | writel(val, pll->pmc + PMC_SATA_PWRGT); | ||
| 474 | |||
| 475 | val = pll_readl_misc(pll); | ||
| 476 | |||
| 477 | timeout = jiffies + msecs_to_jiffies(100); | ||
| 478 | while (1) { | ||
| 479 | val = pll_readl_misc(pll); | ||
| 480 | if (val & PLLE_MISC_READY) | ||
| 481 | break; | ||
| 482 | if (time_after(jiffies, timeout)) { | ||
| 483 | pr_err("%s: timeout waiting for PLLE\n", __func__); | ||
| 484 | return -EBUSY; | ||
| 485 | } | ||
| 486 | udelay(300); | ||
| 487 | } | ||
| 488 | |||
| 489 | return 0; | ||
| 490 | } | ||
| 491 | |||
| 492 | static int clk_plle_enable(struct clk_hw *hw) | ||
| 493 | { | ||
| 494 | struct tegra_clk_pll *pll = to_clk_pll(hw); | ||
| 495 | unsigned long input_rate = clk_get_rate(clk_get_parent(hw->clk)); | ||
| 496 | struct tegra_clk_pll_freq_table sel; | ||
| 497 | u32 val; | ||
| 498 | int err; | ||
| 499 | |||
| 500 | if (_get_table_rate(hw, &sel, pll->fixed_rate, input_rate)) | ||
| 501 | return -EINVAL; | ||
| 502 | |||
| 503 | clk_pll_disable(hw); | ||
| 504 | |||
| 505 | val = pll_readl_misc(pll); | ||
| 506 | val &= ~(PLLE_MISC_LOCK_ENABLE | PLLE_MISC_SETUP_MASK); | ||
| 507 | pll_writel_misc(val, pll); | ||
| 508 | |||
| 509 | val = pll_readl_misc(pll); | ||
| 510 | if (!(val & PLLE_MISC_READY)) { | ||
| 511 | err = clk_plle_training(pll); | ||
| 512 | if (err) | ||
| 513 | return err; | ||
| 514 | } | ||
| 515 | |||
| 516 | if (pll->flags & TEGRA_PLLE_CONFIGURE) { | ||
| 517 | /* configure dividers */ | ||
| 518 | val = pll_readl_base(pll); | ||
| 519 | val &= ~(divm_mask(pll) | divn_mask(pll) | divp_mask(pll)); | ||
| 520 | val &= ~(PLLE_BASE_DIVCML_WIDTH << PLLE_BASE_DIVCML_SHIFT); | ||
| 521 | val |= sel.m << pll->divm_shift; | ||
| 522 | val |= sel.n << pll->divn_shift; | ||
| 523 | val |= sel.p << pll->divp_shift; | ||
| 524 | val |= sel.cpcon << PLLE_BASE_DIVCML_SHIFT; | ||
| 525 | pll_writel_base(val, pll); | ||
| 526 | } | ||
| 527 | |||
| 528 | val = pll_readl_misc(pll); | ||
| 529 | val |= PLLE_MISC_SETUP_VALUE; | ||
| 530 | val |= PLLE_MISC_LOCK_ENABLE; | ||
| 531 | pll_writel_misc(val, pll); | ||
| 532 | |||
| 533 | val = readl(pll->clk_base + PLLE_SS_CTRL); | ||
| 534 | val |= PLLE_SS_DISABLE; | ||
| 535 | writel(val, pll->clk_base + PLLE_SS_CTRL); | ||
| 536 | |||
| 537 | val |= pll_readl_base(pll); | ||
| 538 | val |= (PLL_BASE_BYPASS | PLL_BASE_ENABLE); | ||
| 539 | pll_writel_base(val, pll); | ||
| 540 | |||
| 541 | clk_pll_wait_for_lock(pll, pll->clk_base + pll->params->misc_reg, | ||
| 542 | pll->params->lock_bit_idx); | ||
| 543 | return 0; | ||
| 544 | } | ||
| 545 | |||
| 546 | static unsigned long clk_plle_recalc_rate(struct clk_hw *hw, | ||
| 547 | unsigned long parent_rate) | ||
| 548 | { | ||
| 549 | struct tegra_clk_pll *pll = to_clk_pll(hw); | ||
| 550 | u32 val = pll_readl_base(pll); | ||
| 551 | u32 divn = 0, divm = 0, divp = 0; | ||
| 552 | u64 rate = parent_rate; | ||
| 553 | |||
| 554 | divp = (val >> pll->divp_shift) & (divp_mask(pll)); | ||
| 555 | divn = (val >> pll->divn_shift) & (divn_mask(pll)); | ||
| 556 | divm = (val >> pll->divm_shift) & (divm_mask(pll)); | ||
| 557 | divm *= divp; | ||
| 558 | |||
| 559 | rate *= divn; | ||
| 560 | do_div(rate, divm); | ||
| 561 | return rate; | ||
| 562 | } | ||
| 563 | |||
| 564 | const struct clk_ops tegra_clk_pll_ops = { | ||
| 565 | .is_enabled = clk_pll_is_enabled, | ||
| 566 | .enable = clk_pll_enable, | ||
| 567 | .disable = clk_pll_disable, | ||
| 568 | .recalc_rate = clk_pll_recalc_rate, | ||
| 569 | .round_rate = clk_pll_round_rate, | ||
| 570 | .set_rate = clk_pll_set_rate, | ||
| 571 | }; | ||
| 572 | |||
| 573 | const struct clk_ops tegra_clk_plle_ops = { | ||
| 574 | .recalc_rate = clk_plle_recalc_rate, | ||
| 575 | .is_enabled = clk_pll_is_enabled, | ||
| 576 | .disable = clk_pll_disable, | ||
| 577 | .enable = clk_plle_enable, | ||
| 578 | }; | ||
| 579 | |||
| 580 | static struct clk *_tegra_clk_register_pll(const char *name, | ||
| 581 | const char *parent_name, void __iomem *clk_base, | ||
| 582 | void __iomem *pmc, unsigned long flags, | ||
| 583 | unsigned long fixed_rate, | ||
| 584 | struct tegra_clk_pll_params *pll_params, u8 pll_flags, | ||
| 585 | struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock, | ||
| 586 | const struct clk_ops *ops) | ||
| 587 | { | ||
| 588 | struct tegra_clk_pll *pll; | ||
| 589 | struct clk *clk; | ||
| 590 | struct clk_init_data init; | ||
| 591 | |||
| 592 | pll = kzalloc(sizeof(*pll), GFP_KERNEL); | ||
| 593 | if (!pll) | ||
| 594 | return ERR_PTR(-ENOMEM); | ||
| 595 | |||
| 596 | init.name = name; | ||
| 597 | init.ops = ops; | ||
| 598 | init.flags = flags; | ||
| 599 | init.parent_names = (parent_name ? &parent_name : NULL); | ||
| 600 | init.num_parents = (parent_name ? 1 : 0); | ||
| 601 | |||
| 602 | pll->clk_base = clk_base; | ||
| 603 | pll->pmc = pmc; | ||
| 604 | |||
| 605 | pll->freq_table = freq_table; | ||
| 606 | pll->params = pll_params; | ||
| 607 | pll->fixed_rate = fixed_rate; | ||
| 608 | pll->flags = pll_flags; | ||
| 609 | pll->lock = lock; | ||
| 610 | |||
| 611 | pll->divp_shift = PLL_BASE_DIVP_SHIFT; | ||
| 612 | pll->divp_width = PLL_BASE_DIVP_WIDTH; | ||
| 613 | pll->divn_shift = PLL_BASE_DIVN_SHIFT; | ||
| 614 | pll->divn_width = PLL_BASE_DIVN_WIDTH; | ||
| 615 | pll->divm_shift = PLL_BASE_DIVM_SHIFT; | ||
| 616 | pll->divm_width = PLL_BASE_DIVM_WIDTH; | ||
| 617 | |||
| 618 | /* Data in .init is copied by clk_register(), so stack variable OK */ | ||
| 619 | pll->hw.init = &init; | ||
| 620 | |||
| 621 | clk = clk_register(NULL, &pll->hw); | ||
| 622 | if (IS_ERR(clk)) | ||
| 623 | kfree(pll); | ||
| 624 | |||
| 625 | return clk; | ||
| 626 | } | ||
| 627 | |||
| 628 | struct clk *tegra_clk_register_pll(const char *name, const char *parent_name, | ||
| 629 | void __iomem *clk_base, void __iomem *pmc, | ||
| 630 | unsigned long flags, unsigned long fixed_rate, | ||
| 631 | struct tegra_clk_pll_params *pll_params, u8 pll_flags, | ||
| 632 | struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock) | ||
| 633 | { | ||
| 634 | return _tegra_clk_register_pll(name, parent_name, clk_base, pmc, | ||
| 635 | flags, fixed_rate, pll_params, pll_flags, freq_table, | ||
| 636 | lock, &tegra_clk_pll_ops); | ||
| 637 | } | ||
| 638 | |||
| 639 | struct clk *tegra_clk_register_plle(const char *name, const char *parent_name, | ||
| 640 | void __iomem *clk_base, void __iomem *pmc, | ||
| 641 | unsigned long flags, unsigned long fixed_rate, | ||
| 642 | struct tegra_clk_pll_params *pll_params, u8 pll_flags, | ||
| 643 | struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock) | ||
| 644 | { | ||
| 645 | return _tegra_clk_register_pll(name, parent_name, clk_base, pmc, | ||
| 646 | flags, fixed_rate, pll_params, pll_flags, freq_table, | ||
| 647 | lock, &tegra_clk_plle_ops); | ||
| 648 | } | ||
diff --git a/drivers/clk/tegra/clk-super.c b/drivers/clk/tegra/clk-super.c new file mode 100644 index 000000000000..7ad48a832334 --- /dev/null +++ b/drivers/clk/tegra/clk-super.c | |||
| @@ -0,0 +1,154 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/kernel.h> | ||
| 18 | #include <linux/io.h> | ||
| 19 | #include <linux/delay.h> | ||
| 20 | #include <linux/err.h> | ||
| 21 | #include <linux/slab.h> | ||
| 22 | #include <linux/clk-provider.h> | ||
| 23 | #include <linux/clk.h> | ||
| 24 | |||
| 25 | #include "clk.h" | ||
| 26 | |||
| 27 | #define SUPER_STATE_IDLE 0 | ||
| 28 | #define SUPER_STATE_RUN 1 | ||
| 29 | #define SUPER_STATE_IRQ 2 | ||
| 30 | #define SUPER_STATE_FIQ 3 | ||
| 31 | |||
| 32 | #define SUPER_STATE_SHIFT 28 | ||
| 33 | #define SUPER_STATE_MASK ((BIT(SUPER_STATE_IDLE) | BIT(SUPER_STATE_RUN) | \ | ||
| 34 | BIT(SUPER_STATE_IRQ) | BIT(SUPER_STATE_FIQ)) \ | ||
| 35 | << SUPER_STATE_SHIFT) | ||
| 36 | |||
| 37 | #define SUPER_LP_DIV2_BYPASS (1 << 16) | ||
| 38 | |||
| 39 | #define super_state(s) (BIT(s) << SUPER_STATE_SHIFT) | ||
| 40 | #define super_state_to_src_shift(m, s) ((m->width * s)) | ||
| 41 | #define super_state_to_src_mask(m) (((1 << m->width) - 1)) | ||
| 42 | |||
| 43 | static u8 clk_super_get_parent(struct clk_hw *hw) | ||
| 44 | { | ||
| 45 | struct tegra_clk_super_mux *mux = to_clk_super_mux(hw); | ||
| 46 | u32 val, state; | ||
| 47 | u8 source, shift; | ||
| 48 | |||
| 49 | val = readl_relaxed(mux->reg); | ||
| 50 | |||
| 51 | state = val & SUPER_STATE_MASK; | ||
| 52 | |||
| 53 | BUG_ON((state != super_state(SUPER_STATE_RUN)) && | ||
| 54 | (state != super_state(SUPER_STATE_IDLE))); | ||
| 55 | shift = (state == super_state(SUPER_STATE_IDLE)) ? | ||
| 56 | super_state_to_src_shift(mux, SUPER_STATE_IDLE) : | ||
| 57 | super_state_to_src_shift(mux, SUPER_STATE_RUN); | ||
| 58 | |||
| 59 | source = (val >> shift) & super_state_to_src_mask(mux); | ||
| 60 | |||
| 61 | /* | ||
| 62 | * If LP_DIV2_BYPASS is not set and PLLX is current parent then | ||
| 63 | * PLLX/2 is the input source to CCLKLP. | ||
| 64 | */ | ||
| 65 | if ((mux->flags & TEGRA_DIVIDER_2) && !(val & SUPER_LP_DIV2_BYPASS) && | ||
| 66 | (source == mux->pllx_index)) | ||
| 67 | source = mux->div2_index; | ||
| 68 | |||
| 69 | return source; | ||
| 70 | } | ||
| 71 | |||
| 72 | static int clk_super_set_parent(struct clk_hw *hw, u8 index) | ||
| 73 | { | ||
| 74 | struct tegra_clk_super_mux *mux = to_clk_super_mux(hw); | ||
| 75 | u32 val, state; | ||
| 76 | u8 parent_index, shift; | ||
| 77 | |||
| 78 | val = readl_relaxed(mux->reg); | ||
| 79 | state = val & SUPER_STATE_MASK; | ||
| 80 | BUG_ON((state != super_state(SUPER_STATE_RUN)) && | ||
| 81 | (state != super_state(SUPER_STATE_IDLE))); | ||
| 82 | shift = (state == super_state(SUPER_STATE_IDLE)) ? | ||
| 83 | super_state_to_src_shift(mux, SUPER_STATE_IDLE) : | ||
| 84 | super_state_to_src_shift(mux, SUPER_STATE_RUN); | ||
| 85 | |||
| 86 | /* | ||
| 87 | * For LP mode super-clock switch between PLLX direct | ||
| 88 | * and divided-by-2 outputs is allowed only when other | ||
| 89 | * than PLLX clock source is current parent. | ||
| 90 | */ | ||
| 91 | if ((mux->flags & TEGRA_DIVIDER_2) && ((index == mux->div2_index) || | ||
| 92 | (index == mux->pllx_index))) { | ||
| 93 | parent_index = clk_super_get_parent(hw); | ||
| 94 | if ((parent_index == mux->div2_index) || | ||
| 95 | (parent_index == mux->pllx_index)) | ||
| 96 | return -EINVAL; | ||
| 97 | |||
| 98 | val ^= SUPER_LP_DIV2_BYPASS; | ||
| 99 | writel_relaxed(val, mux->reg); | ||
| 100 | udelay(2); | ||
| 101 | |||
| 102 | if (index == mux->div2_index) | ||
| 103 | index = mux->pllx_index; | ||
| 104 | } | ||
| 105 | val &= ~((super_state_to_src_mask(mux)) << shift); | ||
| 106 | val |= (index & (super_state_to_src_mask(mux))) << shift; | ||
| 107 | |||
| 108 | writel_relaxed(val, mux->reg); | ||
| 109 | udelay(2); | ||
| 110 | return 0; | ||
| 111 | } | ||
| 112 | |||
| 113 | const struct clk_ops tegra_clk_super_ops = { | ||
| 114 | .get_parent = clk_super_get_parent, | ||
| 115 | .set_parent = clk_super_set_parent, | ||
| 116 | }; | ||
| 117 | |||
| 118 | struct clk *tegra_clk_register_super_mux(const char *name, | ||
| 119 | const char **parent_names, u8 num_parents, | ||
| 120 | unsigned long flags, void __iomem *reg, u8 clk_super_flags, | ||
| 121 | u8 width, u8 pllx_index, u8 div2_index, spinlock_t *lock) | ||
| 122 | { | ||
| 123 | struct tegra_clk_super_mux *super; | ||
| 124 | struct clk *clk; | ||
| 125 | struct clk_init_data init; | ||
| 126 | |||
| 127 | super = kzalloc(sizeof(*super), GFP_KERNEL); | ||
| 128 | if (!super) { | ||
| 129 | pr_err("%s: could not allocate super clk\n", __func__); | ||
| 130 | return ERR_PTR(-ENOMEM); | ||
| 131 | } | ||
| 132 | |||
| 133 | init.name = name; | ||
| 134 | init.ops = &tegra_clk_super_ops; | ||
| 135 | init.flags = flags; | ||
| 136 | init.parent_names = parent_names; | ||
| 137 | init.num_parents = num_parents; | ||
| 138 | |||
| 139 | super->reg = reg; | ||
| 140 | super->pllx_index = pllx_index; | ||
| 141 | super->div2_index = div2_index; | ||
| 142 | super->lock = lock; | ||
| 143 | super->width = width; | ||
| 144 | super->flags = clk_super_flags; | ||
| 145 | |||
| 146 | /* Data in .init is copied by clk_register(), so stack variable OK */ | ||
| 147 | super->hw.init = &init; | ||
| 148 | |||
| 149 | clk = clk_register(NULL, &super->hw); | ||
| 150 | if (IS_ERR(clk)) | ||
| 151 | kfree(super); | ||
| 152 | |||
| 153 | return clk; | ||
| 154 | } | ||
diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c new file mode 100644 index 000000000000..5d41569883a7 --- /dev/null +++ b/drivers/clk/tegra/clk-tegra20.c | |||
| @@ -0,0 +1,1349 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/io.h> | ||
| 18 | #include <linux/clk.h> | ||
| 19 | #include <linux/clk-provider.h> | ||
| 20 | #include <linux/clkdev.h> | ||
| 21 | #include <linux/of.h> | ||
| 22 | #include <linux/of_address.h> | ||
| 23 | #include <linux/clk/tegra.h> | ||
| 24 | #include <linux/delay.h> | ||
| 25 | |||
| 26 | #include "clk.h" | ||
| 27 | |||
| 28 | #define RST_DEVICES_L 0x004 | ||
| 29 | #define RST_DEVICES_H 0x008 | ||
| 30 | #define RST_DEVICES_U 0x00c | ||
| 31 | #define RST_DEVICES_SET_L 0x300 | ||
| 32 | #define RST_DEVICES_CLR_L 0x304 | ||
| 33 | #define RST_DEVICES_SET_H 0x308 | ||
| 34 | #define RST_DEVICES_CLR_H 0x30c | ||
| 35 | #define RST_DEVICES_SET_U 0x310 | ||
| 36 | #define RST_DEVICES_CLR_U 0x314 | ||
| 37 | #define RST_DEVICES_NUM 3 | ||
| 38 | |||
| 39 | #define CLK_OUT_ENB_L 0x010 | ||
| 40 | #define CLK_OUT_ENB_H 0x014 | ||
| 41 | #define CLK_OUT_ENB_U 0x018 | ||
| 42 | #define CLK_OUT_ENB_SET_L 0x320 | ||
| 43 | #define CLK_OUT_ENB_CLR_L 0x324 | ||
| 44 | #define CLK_OUT_ENB_SET_H 0x328 | ||
| 45 | #define CLK_OUT_ENB_CLR_H 0x32c | ||
| 46 | #define CLK_OUT_ENB_SET_U 0x330 | ||
| 47 | #define CLK_OUT_ENB_CLR_U 0x334 | ||
| 48 | #define CLK_OUT_ENB_NUM 3 | ||
| 49 | |||
| 50 | #define OSC_CTRL 0x50 | ||
| 51 | #define OSC_CTRL_OSC_FREQ_MASK (3<<30) | ||
| 52 | #define OSC_CTRL_OSC_FREQ_13MHZ (0<<30) | ||
| 53 | #define OSC_CTRL_OSC_FREQ_19_2MHZ (1<<30) | ||
| 54 | #define OSC_CTRL_OSC_FREQ_12MHZ (2<<30) | ||
| 55 | #define OSC_CTRL_OSC_FREQ_26MHZ (3<<30) | ||
| 56 | #define OSC_CTRL_MASK (0x3f2 | OSC_CTRL_OSC_FREQ_MASK) | ||
| 57 | |||
| 58 | #define OSC_CTRL_PLL_REF_DIV_MASK (3<<28) | ||
| 59 | #define OSC_CTRL_PLL_REF_DIV_1 (0<<28) | ||
| 60 | #define OSC_CTRL_PLL_REF_DIV_2 (1<<28) | ||
| 61 | #define OSC_CTRL_PLL_REF_DIV_4 (2<<28) | ||
| 62 | |||
| 63 | #define OSC_FREQ_DET 0x58 | ||
| 64 | #define OSC_FREQ_DET_TRIG (1<<31) | ||
| 65 | |||
| 66 | #define OSC_FREQ_DET_STATUS 0x5c | ||
| 67 | #define OSC_FREQ_DET_BUSY (1<<31) | ||
| 68 | #define OSC_FREQ_DET_CNT_MASK 0xFFFF | ||
| 69 | |||
| 70 | #define PLLS_BASE 0xf0 | ||
| 71 | #define PLLS_MISC 0xf4 | ||
| 72 | #define PLLC_BASE 0x80 | ||
| 73 | #define PLLC_MISC 0x8c | ||
| 74 | #define PLLM_BASE 0x90 | ||
| 75 | #define PLLM_MISC 0x9c | ||
| 76 | #define PLLP_BASE 0xa0 | ||
| 77 | #define PLLP_MISC 0xac | ||
| 78 | #define PLLA_BASE 0xb0 | ||
| 79 | #define PLLA_MISC 0xbc | ||
| 80 | #define PLLU_BASE 0xc0 | ||
| 81 | #define PLLU_MISC 0xcc | ||
| 82 | #define PLLD_BASE 0xd0 | ||
| 83 | #define PLLD_MISC 0xdc | ||
| 84 | #define PLLX_BASE 0xe0 | ||
| 85 | #define PLLX_MISC 0xe4 | ||
| 86 | #define PLLE_BASE 0xe8 | ||
| 87 | #define PLLE_MISC 0xec | ||
| 88 | |||
| 89 | #define PLL_BASE_LOCK 27 | ||
| 90 | #define PLLE_MISC_LOCK 11 | ||
| 91 | |||
| 92 | #define PLL_MISC_LOCK_ENABLE 18 | ||
| 93 | #define PLLDU_MISC_LOCK_ENABLE 22 | ||
| 94 | #define PLLE_MISC_LOCK_ENABLE 9 | ||
| 95 | |||
| 96 | #define PLLC_OUT 0x84 | ||
| 97 | #define PLLM_OUT 0x94 | ||
| 98 | #define PLLP_OUTA 0xa4 | ||
| 99 | #define PLLP_OUTB 0xa8 | ||
| 100 | #define PLLA_OUT 0xb4 | ||
| 101 | |||
| 102 | #define CCLK_BURST_POLICY 0x20 | ||
| 103 | #define SUPER_CCLK_DIVIDER 0x24 | ||
| 104 | #define SCLK_BURST_POLICY 0x28 | ||
| 105 | #define SUPER_SCLK_DIVIDER 0x2c | ||
| 106 | #define CLK_SYSTEM_RATE 0x30 | ||
| 107 | |||
| 108 | #define CCLK_BURST_POLICY_SHIFT 28 | ||
| 109 | #define CCLK_RUN_POLICY_SHIFT 4 | ||
| 110 | #define CCLK_IDLE_POLICY_SHIFT 0 | ||
| 111 | #define CCLK_IDLE_POLICY 1 | ||
| 112 | #define CCLK_RUN_POLICY 2 | ||
| 113 | #define CCLK_BURST_POLICY_PLLX 8 | ||
| 114 | |||
| 115 | #define CLK_SOURCE_I2S1 0x100 | ||
| 116 | #define CLK_SOURCE_I2S2 0x104 | ||
| 117 | #define CLK_SOURCE_SPDIF_OUT 0x108 | ||
| 118 | #define CLK_SOURCE_SPDIF_IN 0x10c | ||
| 119 | #define CLK_SOURCE_PWM 0x110 | ||
| 120 | #define CLK_SOURCE_SPI 0x114 | ||
| 121 | #define CLK_SOURCE_SBC1 0x134 | ||
| 122 | #define CLK_SOURCE_SBC2 0x118 | ||
| 123 | #define CLK_SOURCE_SBC3 0x11c | ||
| 124 | #define CLK_SOURCE_SBC4 0x1b4 | ||
| 125 | #define CLK_SOURCE_XIO 0x120 | ||
| 126 | #define CLK_SOURCE_TWC 0x12c | ||
| 127 | #define CLK_SOURCE_IDE 0x144 | ||
| 128 | #define CLK_SOURCE_NDFLASH 0x160 | ||
| 129 | #define CLK_SOURCE_VFIR 0x168 | ||
| 130 | #define CLK_SOURCE_SDMMC1 0x150 | ||
| 131 | #define CLK_SOURCE_SDMMC2 0x154 | ||
| 132 | #define CLK_SOURCE_SDMMC3 0x1bc | ||
| 133 | #define CLK_SOURCE_SDMMC4 0x164 | ||
| 134 | #define CLK_SOURCE_CVE 0x140 | ||
| 135 | #define CLK_SOURCE_TVO 0x188 | ||
| 136 | #define CLK_SOURCE_TVDAC 0x194 | ||
| 137 | #define CLK_SOURCE_HDMI 0x18c | ||
| 138 | #define CLK_SOURCE_DISP1 0x138 | ||
| 139 | #define CLK_SOURCE_DISP2 0x13c | ||
| 140 | #define CLK_SOURCE_CSITE 0x1d4 | ||
| 141 | #define CLK_SOURCE_LA 0x1f8 | ||
| 142 | #define CLK_SOURCE_OWR 0x1cc | ||
| 143 | #define CLK_SOURCE_NOR 0x1d0 | ||
| 144 | #define CLK_SOURCE_MIPI 0x174 | ||
| 145 | #define CLK_SOURCE_I2C1 0x124 | ||
| 146 | #define CLK_SOURCE_I2C2 0x198 | ||
| 147 | #define CLK_SOURCE_I2C3 0x1b8 | ||
| 148 | #define CLK_SOURCE_DVC 0x128 | ||
| 149 | #define CLK_SOURCE_UARTA 0x178 | ||
| 150 | #define CLK_SOURCE_UARTB 0x17c | ||
| 151 | #define CLK_SOURCE_UARTC 0x1a0 | ||
| 152 | #define CLK_SOURCE_UARTD 0x1c0 | ||
| 153 | #define CLK_SOURCE_UARTE 0x1c4 | ||
| 154 | #define CLK_SOURCE_3D 0x158 | ||
| 155 | #define CLK_SOURCE_2D 0x15c | ||
| 156 | #define CLK_SOURCE_MPE 0x170 | ||
| 157 | #define CLK_SOURCE_EPP 0x16c | ||
| 158 | #define CLK_SOURCE_HOST1X 0x180 | ||
| 159 | #define CLK_SOURCE_VDE 0x1c8 | ||
| 160 | #define CLK_SOURCE_VI 0x148 | ||
| 161 | #define CLK_SOURCE_VI_SENSOR 0x1a8 | ||
| 162 | #define CLK_SOURCE_EMC 0x19c | ||
| 163 | |||
| 164 | #define AUDIO_SYNC_CLK 0x38 | ||
| 165 | |||
| 166 | #define PMC_CTRL 0x0 | ||
| 167 | #define PMC_CTRL_BLINK_ENB 7 | ||
| 168 | #define PMC_DPD_PADS_ORIDE 0x1c | ||
| 169 | #define PMC_DPD_PADS_ORIDE_BLINK_ENB 20 | ||
| 170 | #define PMC_BLINK_TIMER 0x40 | ||
| 171 | |||
| 172 | /* Tegra CPU clock and reset control regs */ | ||
| 173 | #define TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX 0x4c | ||
| 174 | #define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET 0x340 | ||
| 175 | #define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR 0x344 | ||
| 176 | |||
| 177 | #define CPU_CLOCK(cpu) (0x1 << (8 + cpu)) | ||
| 178 | #define CPU_RESET(cpu) (0x1111ul << (cpu)) | ||
| 179 | |||
| 180 | #ifdef CONFIG_PM_SLEEP | ||
| 181 | static struct cpu_clk_suspend_context { | ||
| 182 | u32 pllx_misc; | ||
| 183 | u32 pllx_base; | ||
| 184 | |||
| 185 | u32 cpu_burst; | ||
| 186 | u32 clk_csite_src; | ||
| 187 | u32 cclk_divider; | ||
| 188 | } tegra20_cpu_clk_sctx; | ||
| 189 | #endif | ||
| 190 | |||
| 191 | static int periph_clk_enb_refcnt[CLK_OUT_ENB_NUM * 32]; | ||
| 192 | |||
| 193 | static void __iomem *clk_base; | ||
| 194 | static void __iomem *pmc_base; | ||
| 195 | |||
| 196 | static DEFINE_SPINLOCK(pll_div_lock); | ||
| 197 | |||
| 198 | #define TEGRA_INIT_DATA_MUX(_name, _con_id, _dev_id, _parents, _offset, \ | ||
| 199 | _clk_num, _regs, _gate_flags, _clk_id) \ | ||
| 200 | TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ | ||
| 201 | 30, 2, 0, 0, 8, 1, TEGRA_DIVIDER_ROUND_UP, \ | ||
| 202 | _regs, _clk_num, periph_clk_enb_refcnt, \ | ||
| 203 | _gate_flags, _clk_id) | ||
| 204 | |||
| 205 | #define TEGRA_INIT_DATA_INT(_name, _con_id, _dev_id, _parents, _offset, \ | ||
| 206 | _clk_num, _regs, _gate_flags, _clk_id) \ | ||
| 207 | TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ | ||
| 208 | 30, 2, 0, 0, 8, 1, TEGRA_DIVIDER_INT, _regs, \ | ||
| 209 | _clk_num, periph_clk_enb_refcnt, _gate_flags, \ | ||
| 210 | _clk_id) | ||
| 211 | |||
| 212 | #define TEGRA_INIT_DATA_DIV16(_name, _con_id, _dev_id, _parents, _offset, \ | ||
| 213 | _clk_num, _regs, _gate_flags, _clk_id) \ | ||
| 214 | TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ | ||
| 215 | 30, 2, 0, 0, 16, 0, TEGRA_DIVIDER_ROUND_UP, _regs, \ | ||
| 216 | _clk_num, periph_clk_enb_refcnt, _gate_flags, \ | ||
| 217 | _clk_id) | ||
| 218 | |||
| 219 | #define TEGRA_INIT_DATA_NODIV(_name, _con_id, _dev_id, _parents, _offset, \ | ||
| 220 | _mux_shift, _mux_width, _clk_num, _regs, \ | ||
| 221 | _gate_flags, _clk_id) \ | ||
| 222 | TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ | ||
| 223 | _mux_shift, _mux_width, 0, 0, 0, 0, 0, _regs, \ | ||
| 224 | _clk_num, periph_clk_enb_refcnt, _gate_flags, \ | ||
| 225 | _clk_id) | ||
| 226 | |||
| 227 | /* IDs assigned here must be in sync with DT bindings definition | ||
| 228 | * for Tegra20 clocks . | ||
| 229 | */ | ||
| 230 | enum tegra20_clk { | ||
| 231 | cpu, ac97 = 3, rtc, timer, uarta, gpio = 8, sdmmc2, i2s1 = 11, i2c1, | ||
| 232 | ndflash, sdmmc1, sdmmc4, twc, pwm, i2s2, epp, gr2d = 21, usbd, isp, | ||
| 233 | gr3d, ide, disp2, disp1, host1x, vcp, cache2 = 31, mem, ahbdma, apbdma, | ||
| 234 | kbc = 36, stat_mon, pmc, fuse, kfuse, sbc1, nor, spi, sbc2, xio, sbc3, | ||
| 235 | dvc, dsi, mipi = 50, hdmi, csi, tvdac, i2c2, uartc, emc = 57, usb2, | ||
| 236 | usb3, mpe, vde, bsea, bsev, speedo, uartd, uarte, i2c3, sbc4, sdmmc3, | ||
| 237 | pex, owr, afi, csite, pcie_xclk, avpucq = 75, la, irama = 84, iramb, | ||
| 238 | iramc, iramd, cram2, audio_2x, clk_d, csus = 92, cdev1, cdev2, | ||
| 239 | uartb = 96, vfir, spdif_in, spdif_out, vi, vi_sensor, tvo, cve, | ||
| 240 | osc, clk_32k, clk_m, sclk, cclk, hclk, pclk, blink, pll_a, pll_a_out0, | ||
| 241 | pll_c, pll_c_out1, pll_d, pll_d_out0, pll_e, pll_m, pll_m_out1, | ||
| 242 | pll_p, pll_p_out1, pll_p_out2, pll_p_out3, pll_p_out4, pll_u, | ||
| 243 | pll_x, audio, pll_ref, twd, clk_max, | ||
| 244 | }; | ||
| 245 | |||
| 246 | static struct clk *clks[clk_max]; | ||
| 247 | static struct clk_onecell_data clk_data; | ||
| 248 | |||
| 249 | static struct tegra_clk_pll_freq_table pll_c_freq_table[] = { | ||
| 250 | { 12000000, 600000000, 600, 12, 1, 8 }, | ||
| 251 | { 13000000, 600000000, 600, 13, 1, 8 }, | ||
| 252 | { 19200000, 600000000, 500, 16, 1, 6 }, | ||
| 253 | { 26000000, 600000000, 600, 26, 1, 8 }, | ||
| 254 | { 0, 0, 0, 0, 0, 0 }, | ||
| 255 | }; | ||
| 256 | |||
| 257 | static struct tegra_clk_pll_freq_table pll_m_freq_table[] = { | ||
| 258 | { 12000000, 666000000, 666, 12, 1, 8}, | ||
| 259 | { 13000000, 666000000, 666, 13, 1, 8}, | ||
| 260 | { 19200000, 666000000, 555, 16, 1, 8}, | ||
| 261 | { 26000000, 666000000, 666, 26, 1, 8}, | ||
| 262 | { 12000000, 600000000, 600, 12, 1, 8}, | ||
| 263 | { 13000000, 600000000, 600, 13, 1, 8}, | ||
| 264 | { 19200000, 600000000, 375, 12, 1, 6}, | ||
| 265 | { 26000000, 600000000, 600, 26, 1, 8}, | ||
| 266 | { 0, 0, 0, 0, 0, 0 }, | ||
| 267 | }; | ||
| 268 | |||
| 269 | static struct tegra_clk_pll_freq_table pll_p_freq_table[] = { | ||
| 270 | { 12000000, 216000000, 432, 12, 2, 8}, | ||
| 271 | { 13000000, 216000000, 432, 13, 2, 8}, | ||
| 272 | { 19200000, 216000000, 90, 4, 2, 1}, | ||
| 273 | { 26000000, 216000000, 432, 26, 2, 8}, | ||
| 274 | { 12000000, 432000000, 432, 12, 1, 8}, | ||
| 275 | { 13000000, 432000000, 432, 13, 1, 8}, | ||
| 276 | { 19200000, 432000000, 90, 4, 1, 1}, | ||
| 277 | { 26000000, 432000000, 432, 26, 1, 8}, | ||
| 278 | { 0, 0, 0, 0, 0, 0 }, | ||
| 279 | }; | ||
| 280 | |||
| 281 | static struct tegra_clk_pll_freq_table pll_a_freq_table[] = { | ||
| 282 | { 28800000, 56448000, 49, 25, 1, 1}, | ||
| 283 | { 28800000, 73728000, 64, 25, 1, 1}, | ||
| 284 | { 28800000, 24000000, 5, 6, 1, 1}, | ||
| 285 | { 0, 0, 0, 0, 0, 0 }, | ||
| 286 | }; | ||
| 287 | |||
| 288 | static struct tegra_clk_pll_freq_table pll_d_freq_table[] = { | ||
| 289 | { 12000000, 216000000, 216, 12, 1, 4}, | ||
| 290 | { 13000000, 216000000, 216, 13, 1, 4}, | ||
| 291 | { 19200000, 216000000, 135, 12, 1, 3}, | ||
| 292 | { 26000000, 216000000, 216, 26, 1, 4}, | ||
| 293 | |||
| 294 | { 12000000, 594000000, 594, 12, 1, 8}, | ||
| 295 | { 13000000, 594000000, 594, 13, 1, 8}, | ||
| 296 | { 19200000, 594000000, 495, 16, 1, 8}, | ||
| 297 | { 26000000, 594000000, 594, 26, 1, 8}, | ||
| 298 | |||
| 299 | { 12000000, 1000000000, 1000, 12, 1, 12}, | ||
| 300 | { 13000000, 1000000000, 1000, 13, 1, 12}, | ||
| 301 | { 19200000, 1000000000, 625, 12, 1, 8}, | ||
| 302 | { 26000000, 1000000000, 1000, 26, 1, 12}, | ||
| 303 | |||
| 304 | { 0, 0, 0, 0, 0, 0 }, | ||
| 305 | }; | ||
| 306 | |||
| 307 | static struct tegra_clk_pll_freq_table pll_u_freq_table[] = { | ||
| 308 | { 12000000, 480000000, 960, 12, 2, 0}, | ||
| 309 | { 13000000, 480000000, 960, 13, 2, 0}, | ||
| 310 | { 19200000, 480000000, 200, 4, 2, 0}, | ||
| 311 | { 26000000, 480000000, 960, 26, 2, 0}, | ||
| 312 | { 0, 0, 0, 0, 0, 0 }, | ||
| 313 | }; | ||
| 314 | |||
| 315 | static struct tegra_clk_pll_freq_table pll_x_freq_table[] = { | ||
| 316 | /* 1 GHz */ | ||
| 317 | { 12000000, 1000000000, 1000, 12, 1, 12}, | ||
| 318 | { 13000000, 1000000000, 1000, 13, 1, 12}, | ||
| 319 | { 19200000, 1000000000, 625, 12, 1, 8}, | ||
| 320 | { 26000000, 1000000000, 1000, 26, 1, 12}, | ||
| 321 | |||
| 322 | /* 912 MHz */ | ||
| 323 | { 12000000, 912000000, 912, 12, 1, 12}, | ||
| 324 | { 13000000, 912000000, 912, 13, 1, 12}, | ||
| 325 | { 19200000, 912000000, 760, 16, 1, 8}, | ||
| 326 | { 26000000, 912000000, 912, 26, 1, 12}, | ||
| 327 | |||
| 328 | /* 816 MHz */ | ||
| 329 | { 12000000, 816000000, 816, 12, 1, 12}, | ||
| 330 | { 13000000, 816000000, 816, 13, 1, 12}, | ||
| 331 | { 19200000, 816000000, 680, 16, 1, 8}, | ||
| 332 | { 26000000, 816000000, 816, 26, 1, 12}, | ||
| 333 | |||
| 334 | /* 760 MHz */ | ||
| 335 | { 12000000, 760000000, 760, 12, 1, 12}, | ||
| 336 | { 13000000, 760000000, 760, 13, 1, 12}, | ||
| 337 | { 19200000, 760000000, 950, 24, 1, 8}, | ||
| 338 | { 26000000, 760000000, 760, 26, 1, 12}, | ||
| 339 | |||
| 340 | /* 750 MHz */ | ||
| 341 | { 12000000, 750000000, 750, 12, 1, 12}, | ||
| 342 | { 13000000, 750000000, 750, 13, 1, 12}, | ||
| 343 | { 19200000, 750000000, 625, 16, 1, 8}, | ||
| 344 | { 26000000, 750000000, 750, 26, 1, 12}, | ||
| 345 | |||
| 346 | /* 608 MHz */ | ||
| 347 | { 12000000, 608000000, 608, 12, 1, 12}, | ||
| 348 | { 13000000, 608000000, 608, 13, 1, 12}, | ||
| 349 | { 19200000, 608000000, 380, 12, 1, 8}, | ||
| 350 | { 26000000, 608000000, 608, 26, 1, 12}, | ||
| 351 | |||
| 352 | /* 456 MHz */ | ||
| 353 | { 12000000, 456000000, 456, 12, 1, 12}, | ||
| 354 | { 13000000, 456000000, 456, 13, 1, 12}, | ||
| 355 | { 19200000, 456000000, 380, 16, 1, 8}, | ||
| 356 | { 26000000, 456000000, 456, 26, 1, 12}, | ||
| 357 | |||
| 358 | /* 312 MHz */ | ||
| 359 | { 12000000, 312000000, 312, 12, 1, 12}, | ||
| 360 | { 13000000, 312000000, 312, 13, 1, 12}, | ||
| 361 | { 19200000, 312000000, 260, 16, 1, 8}, | ||
| 362 | { 26000000, 312000000, 312, 26, 1, 12}, | ||
| 363 | |||
| 364 | { 0, 0, 0, 0, 0, 0 }, | ||
| 365 | }; | ||
| 366 | |||
| 367 | static struct tegra_clk_pll_freq_table pll_e_freq_table[] = { | ||
| 368 | { 12000000, 100000000, 200, 24, 1, 0 }, | ||
| 369 | { 0, 0, 0, 0, 0, 0 }, | ||
| 370 | }; | ||
| 371 | |||
| 372 | /* PLL parameters */ | ||
| 373 | static struct tegra_clk_pll_params pll_c_params = { | ||
| 374 | .input_min = 2000000, | ||
| 375 | .input_max = 31000000, | ||
| 376 | .cf_min = 1000000, | ||
| 377 | .cf_max = 6000000, | ||
| 378 | .vco_min = 20000000, | ||
| 379 | .vco_max = 1400000000, | ||
| 380 | .base_reg = PLLC_BASE, | ||
| 381 | .misc_reg = PLLC_MISC, | ||
| 382 | .lock_bit_idx = PLL_BASE_LOCK, | ||
| 383 | .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, | ||
| 384 | .lock_delay = 300, | ||
| 385 | }; | ||
| 386 | |||
| 387 | static struct tegra_clk_pll_params pll_m_params = { | ||
| 388 | .input_min = 2000000, | ||
| 389 | .input_max = 31000000, | ||
| 390 | .cf_min = 1000000, | ||
| 391 | .cf_max = 6000000, | ||
| 392 | .vco_min = 20000000, | ||
| 393 | .vco_max = 1200000000, | ||
| 394 | .base_reg = PLLM_BASE, | ||
| 395 | .misc_reg = PLLM_MISC, | ||
| 396 | .lock_bit_idx = PLL_BASE_LOCK, | ||
| 397 | .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, | ||
| 398 | .lock_delay = 300, | ||
| 399 | }; | ||
| 400 | |||
| 401 | static struct tegra_clk_pll_params pll_p_params = { | ||
| 402 | .input_min = 2000000, | ||
| 403 | .input_max = 31000000, | ||
| 404 | .cf_min = 1000000, | ||
| 405 | .cf_max = 6000000, | ||
| 406 | .vco_min = 20000000, | ||
| 407 | .vco_max = 1400000000, | ||
| 408 | .base_reg = PLLP_BASE, | ||
| 409 | .misc_reg = PLLP_MISC, | ||
| 410 | .lock_bit_idx = PLL_BASE_LOCK, | ||
| 411 | .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, | ||
| 412 | .lock_delay = 300, | ||
| 413 | }; | ||
| 414 | |||
| 415 | static struct tegra_clk_pll_params pll_a_params = { | ||
| 416 | .input_min = 2000000, | ||
| 417 | .input_max = 31000000, | ||
| 418 | .cf_min = 1000000, | ||
| 419 | .cf_max = 6000000, | ||
| 420 | .vco_min = 20000000, | ||
| 421 | .vco_max = 1400000000, | ||
| 422 | .base_reg = PLLA_BASE, | ||
| 423 | .misc_reg = PLLA_MISC, | ||
| 424 | .lock_bit_idx = PLL_BASE_LOCK, | ||
| 425 | .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, | ||
| 426 | .lock_delay = 300, | ||
| 427 | }; | ||
| 428 | |||
| 429 | static struct tegra_clk_pll_params pll_d_params = { | ||
| 430 | .input_min = 2000000, | ||
| 431 | .input_max = 40000000, | ||
| 432 | .cf_min = 1000000, | ||
| 433 | .cf_max = 6000000, | ||
| 434 | .vco_min = 40000000, | ||
| 435 | .vco_max = 1000000000, | ||
| 436 | .base_reg = PLLD_BASE, | ||
| 437 | .misc_reg = PLLD_MISC, | ||
| 438 | .lock_bit_idx = PLL_BASE_LOCK, | ||
| 439 | .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, | ||
| 440 | .lock_delay = 1000, | ||
| 441 | }; | ||
| 442 | |||
| 443 | static struct tegra_clk_pll_params pll_u_params = { | ||
| 444 | .input_min = 2000000, | ||
| 445 | .input_max = 40000000, | ||
| 446 | .cf_min = 1000000, | ||
| 447 | .cf_max = 6000000, | ||
| 448 | .vco_min = 48000000, | ||
| 449 | .vco_max = 960000000, | ||
| 450 | .base_reg = PLLU_BASE, | ||
| 451 | .misc_reg = PLLU_MISC, | ||
| 452 | .lock_bit_idx = PLL_BASE_LOCK, | ||
| 453 | .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, | ||
| 454 | .lock_delay = 1000, | ||
| 455 | }; | ||
| 456 | |||
| 457 | static struct tegra_clk_pll_params pll_x_params = { | ||
| 458 | .input_min = 2000000, | ||
| 459 | .input_max = 31000000, | ||
| 460 | .cf_min = 1000000, | ||
| 461 | .cf_max = 6000000, | ||
| 462 | .vco_min = 20000000, | ||
| 463 | .vco_max = 1200000000, | ||
| 464 | .base_reg = PLLX_BASE, | ||
| 465 | .misc_reg = PLLX_MISC, | ||
| 466 | .lock_bit_idx = PLL_BASE_LOCK, | ||
| 467 | .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, | ||
| 468 | .lock_delay = 300, | ||
| 469 | }; | ||
| 470 | |||
| 471 | static struct tegra_clk_pll_params pll_e_params = { | ||
| 472 | .input_min = 12000000, | ||
| 473 | .input_max = 12000000, | ||
| 474 | .cf_min = 0, | ||
| 475 | .cf_max = 0, | ||
| 476 | .vco_min = 0, | ||
| 477 | .vco_max = 0, | ||
| 478 | .base_reg = PLLE_BASE, | ||
| 479 | .misc_reg = PLLE_MISC, | ||
| 480 | .lock_bit_idx = PLLE_MISC_LOCK, | ||
| 481 | .lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE, | ||
| 482 | .lock_delay = 0, | ||
| 483 | }; | ||
| 484 | |||
| 485 | /* Peripheral clock registers */ | ||
| 486 | static struct tegra_clk_periph_regs periph_l_regs = { | ||
| 487 | .enb_reg = CLK_OUT_ENB_L, | ||
| 488 | .enb_set_reg = CLK_OUT_ENB_SET_L, | ||
| 489 | .enb_clr_reg = CLK_OUT_ENB_CLR_L, | ||
| 490 | .rst_reg = RST_DEVICES_L, | ||
| 491 | .rst_set_reg = RST_DEVICES_SET_L, | ||
| 492 | .rst_clr_reg = RST_DEVICES_CLR_L, | ||
| 493 | }; | ||
| 494 | |||
| 495 | static struct tegra_clk_periph_regs periph_h_regs = { | ||
| 496 | .enb_reg = CLK_OUT_ENB_H, | ||
| 497 | .enb_set_reg = CLK_OUT_ENB_SET_H, | ||
| 498 | .enb_clr_reg = CLK_OUT_ENB_CLR_H, | ||
| 499 | .rst_reg = RST_DEVICES_H, | ||
| 500 | .rst_set_reg = RST_DEVICES_SET_H, | ||
| 501 | .rst_clr_reg = RST_DEVICES_CLR_H, | ||
| 502 | }; | ||
| 503 | |||
| 504 | static struct tegra_clk_periph_regs periph_u_regs = { | ||
| 505 | .enb_reg = CLK_OUT_ENB_U, | ||
| 506 | .enb_set_reg = CLK_OUT_ENB_SET_U, | ||
| 507 | .enb_clr_reg = CLK_OUT_ENB_CLR_U, | ||
| 508 | .rst_reg = RST_DEVICES_U, | ||
| 509 | .rst_set_reg = RST_DEVICES_SET_U, | ||
| 510 | .rst_clr_reg = RST_DEVICES_CLR_U, | ||
| 511 | }; | ||
| 512 | |||
| 513 | static unsigned long tegra20_clk_measure_input_freq(void) | ||
| 514 | { | ||
| 515 | u32 osc_ctrl = readl_relaxed(clk_base + OSC_CTRL); | ||
| 516 | u32 auto_clk_control = osc_ctrl & OSC_CTRL_OSC_FREQ_MASK; | ||
| 517 | u32 pll_ref_div = osc_ctrl & OSC_CTRL_PLL_REF_DIV_MASK; | ||
| 518 | unsigned long input_freq; | ||
| 519 | |||
| 520 | switch (auto_clk_control) { | ||
| 521 | case OSC_CTRL_OSC_FREQ_12MHZ: | ||
| 522 | BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); | ||
| 523 | input_freq = 12000000; | ||
| 524 | break; | ||
| 525 | case OSC_CTRL_OSC_FREQ_13MHZ: | ||
| 526 | BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); | ||
| 527 | input_freq = 13000000; | ||
| 528 | break; | ||
| 529 | case OSC_CTRL_OSC_FREQ_19_2MHZ: | ||
| 530 | BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); | ||
| 531 | input_freq = 19200000; | ||
| 532 | break; | ||
| 533 | case OSC_CTRL_OSC_FREQ_26MHZ: | ||
| 534 | BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); | ||
| 535 | input_freq = 26000000; | ||
| 536 | break; | ||
| 537 | default: | ||
| 538 | pr_err("Unexpected clock autodetect value %d", | ||
| 539 | auto_clk_control); | ||
| 540 | BUG(); | ||
| 541 | return 0; | ||
| 542 | } | ||
| 543 | |||
| 544 | return input_freq; | ||
| 545 | } | ||
| 546 | |||
| 547 | static unsigned int tegra20_get_pll_ref_div(void) | ||
| 548 | { | ||
| 549 | u32 pll_ref_div = readl_relaxed(clk_base + OSC_CTRL) & | ||
| 550 | OSC_CTRL_PLL_REF_DIV_MASK; | ||
| 551 | |||
| 552 | switch (pll_ref_div) { | ||
| 553 | case OSC_CTRL_PLL_REF_DIV_1: | ||
| 554 | return 1; | ||
| 555 | case OSC_CTRL_PLL_REF_DIV_2: | ||
| 556 | return 2; | ||
| 557 | case OSC_CTRL_PLL_REF_DIV_4: | ||
| 558 | return 4; | ||
| 559 | default: | ||
| 560 | pr_err("Invalied pll ref divider %d\n", pll_ref_div); | ||
| 561 | BUG(); | ||
| 562 | } | ||
| 563 | return 0; | ||
| 564 | } | ||
| 565 | |||
| 566 | static void tegra20_pll_init(void) | ||
| 567 | { | ||
| 568 | struct clk *clk; | ||
| 569 | |||
| 570 | /* PLLC */ | ||
| 571 | clk = tegra_clk_register_pll("pll_c", "pll_ref", clk_base, NULL, 0, | ||
| 572 | 0, &pll_c_params, TEGRA_PLL_HAS_CPCON, | ||
| 573 | pll_c_freq_table, NULL); | ||
| 574 | clk_register_clkdev(clk, "pll_c", NULL); | ||
| 575 | clks[pll_c] = clk; | ||
| 576 | |||
| 577 | /* PLLC_OUT1 */ | ||
| 578 | clk = tegra_clk_register_divider("pll_c_out1_div", "pll_c", | ||
| 579 | clk_base + PLLC_OUT, 0, TEGRA_DIVIDER_ROUND_UP, | ||
| 580 | 8, 8, 1, NULL); | ||
| 581 | clk = tegra_clk_register_pll_out("pll_c_out1", "pll_c_out1_div", | ||
| 582 | clk_base + PLLC_OUT, 1, 0, CLK_SET_RATE_PARENT, | ||
| 583 | 0, NULL); | ||
| 584 | clk_register_clkdev(clk, "pll_c_out1", NULL); | ||
| 585 | clks[pll_c_out1] = clk; | ||
| 586 | |||
| 587 | /* PLLP */ | ||
| 588 | clk = tegra_clk_register_pll("pll_p", "pll_ref", clk_base, NULL, 0, | ||
| 589 | 216000000, &pll_p_params, TEGRA_PLL_FIXED | | ||
| 590 | TEGRA_PLL_HAS_CPCON, pll_p_freq_table, NULL); | ||
| 591 | clk_register_clkdev(clk, "pll_p", NULL); | ||
| 592 | clks[pll_p] = clk; | ||
| 593 | |||
| 594 | /* PLLP_OUT1 */ | ||
| 595 | clk = tegra_clk_register_divider("pll_p_out1_div", "pll_p", | ||
| 596 | clk_base + PLLP_OUTA, 0, | ||
| 597 | TEGRA_DIVIDER_FIXED | TEGRA_DIVIDER_ROUND_UP, | ||
| 598 | 8, 8, 1, &pll_div_lock); | ||
| 599 | clk = tegra_clk_register_pll_out("pll_p_out1", "pll_p_out1_div", | ||
| 600 | clk_base + PLLP_OUTA, 1, 0, | ||
| 601 | CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, | ||
| 602 | &pll_div_lock); | ||
| 603 | clk_register_clkdev(clk, "pll_p_out1", NULL); | ||
| 604 | clks[pll_p_out1] = clk; | ||
| 605 | |||
| 606 | /* PLLP_OUT2 */ | ||
| 607 | clk = tegra_clk_register_divider("pll_p_out2_div", "pll_p", | ||
| 608 | clk_base + PLLP_OUTA, 0, | ||
| 609 | TEGRA_DIVIDER_FIXED | TEGRA_DIVIDER_ROUND_UP, | ||
| 610 | 24, 8, 1, &pll_div_lock); | ||
| 611 | clk = tegra_clk_register_pll_out("pll_p_out2", "pll_p_out2_div", | ||
| 612 | clk_base + PLLP_OUTA, 17, 16, | ||
| 613 | CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, | ||
| 614 | &pll_div_lock); | ||
| 615 | clk_register_clkdev(clk, "pll_p_out2", NULL); | ||
| 616 | clks[pll_p_out2] = clk; | ||
| 617 | |||
| 618 | /* PLLP_OUT3 */ | ||
| 619 | clk = tegra_clk_register_divider("pll_p_out3_div", "pll_p", | ||
| 620 | clk_base + PLLP_OUTB, 0, | ||
| 621 | TEGRA_DIVIDER_FIXED | TEGRA_DIVIDER_ROUND_UP, | ||
| 622 | 8, 8, 1, &pll_div_lock); | ||
| 623 | clk = tegra_clk_register_pll_out("pll_p_out3", "pll_p_out3_div", | ||
| 624 | clk_base + PLLP_OUTB, 1, 0, | ||
| 625 | CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, | ||
| 626 | &pll_div_lock); | ||
| 627 | clk_register_clkdev(clk, "pll_p_out3", NULL); | ||
| 628 | clks[pll_p_out3] = clk; | ||
| 629 | |||
| 630 | /* PLLP_OUT4 */ | ||
| 631 | clk = tegra_clk_register_divider("pll_p_out4_div", "pll_p", | ||
| 632 | clk_base + PLLP_OUTB, 0, | ||
| 633 | TEGRA_DIVIDER_FIXED | TEGRA_DIVIDER_ROUND_UP, | ||
| 634 | 24, 8, 1, &pll_div_lock); | ||
| 635 | clk = tegra_clk_register_pll_out("pll_p_out4", "pll_p_out4_div", | ||
| 636 | clk_base + PLLP_OUTB, 17, 16, | ||
| 637 | CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, | ||
| 638 | &pll_div_lock); | ||
| 639 | clk_register_clkdev(clk, "pll_p_out4", NULL); | ||
| 640 | clks[pll_p_out4] = clk; | ||
| 641 | |||
| 642 | /* PLLM */ | ||
| 643 | clk = tegra_clk_register_pll("pll_m", "pll_ref", clk_base, NULL, | ||
| 644 | CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE, 0, | ||
| 645 | &pll_m_params, TEGRA_PLL_HAS_CPCON, | ||
| 646 | pll_m_freq_table, NULL); | ||
| 647 | clk_register_clkdev(clk, "pll_m", NULL); | ||
| 648 | clks[pll_m] = clk; | ||
| 649 | |||
| 650 | /* PLLM_OUT1 */ | ||
| 651 | clk = tegra_clk_register_divider("pll_m_out1_div", "pll_m", | ||
| 652 | clk_base + PLLM_OUT, 0, TEGRA_DIVIDER_ROUND_UP, | ||
| 653 | 8, 8, 1, NULL); | ||
| 654 | clk = tegra_clk_register_pll_out("pll_m_out1", "pll_m_out1_div", | ||
| 655 | clk_base + PLLM_OUT, 1, 0, CLK_IGNORE_UNUSED | | ||
| 656 | CLK_SET_RATE_PARENT, 0, NULL); | ||
| 657 | clk_register_clkdev(clk, "pll_m_out1", NULL); | ||
| 658 | clks[pll_m_out1] = clk; | ||
| 659 | |||
| 660 | /* PLLX */ | ||
| 661 | clk = tegra_clk_register_pll("pll_x", "pll_ref", clk_base, NULL, 0, | ||
| 662 | 0, &pll_x_params, TEGRA_PLL_HAS_CPCON, | ||
| 663 | pll_x_freq_table, NULL); | ||
| 664 | clk_register_clkdev(clk, "pll_x", NULL); | ||
| 665 | clks[pll_x] = clk; | ||
| 666 | |||
| 667 | /* PLLU */ | ||
| 668 | clk = tegra_clk_register_pll("pll_u", "pll_ref", clk_base, NULL, 0, | ||
| 669 | 0, &pll_u_params, TEGRA_PLLU | TEGRA_PLL_HAS_CPCON, | ||
| 670 | pll_u_freq_table, NULL); | ||
| 671 | clk_register_clkdev(clk, "pll_u", NULL); | ||
| 672 | clks[pll_u] = clk; | ||
| 673 | |||
| 674 | /* PLLD */ | ||
| 675 | clk = tegra_clk_register_pll("pll_d", "pll_ref", clk_base, NULL, 0, | ||
| 676 | 0, &pll_d_params, TEGRA_PLL_HAS_CPCON, | ||
| 677 | pll_d_freq_table, NULL); | ||
| 678 | clk_register_clkdev(clk, "pll_d", NULL); | ||
| 679 | clks[pll_d] = clk; | ||
| 680 | |||
| 681 | /* PLLD_OUT0 */ | ||
| 682 | clk = clk_register_fixed_factor(NULL, "pll_d_out0", "pll_d", | ||
| 683 | CLK_SET_RATE_PARENT, 1, 2); | ||
| 684 | clk_register_clkdev(clk, "pll_d_out0", NULL); | ||
| 685 | clks[pll_d_out0] = clk; | ||
| 686 | |||
| 687 | /* PLLA */ | ||
| 688 | clk = tegra_clk_register_pll("pll_a", "pll_p_out1", clk_base, NULL, 0, | ||
| 689 | 0, &pll_a_params, TEGRA_PLL_HAS_CPCON, | ||
| 690 | pll_a_freq_table, NULL); | ||
| 691 | clk_register_clkdev(clk, "pll_a", NULL); | ||
| 692 | clks[pll_a] = clk; | ||
| 693 | |||
| 694 | /* PLLA_OUT0 */ | ||
| 695 | clk = tegra_clk_register_divider("pll_a_out0_div", "pll_a", | ||
| 696 | clk_base + PLLA_OUT, 0, TEGRA_DIVIDER_ROUND_UP, | ||
| 697 | 8, 8, 1, NULL); | ||
| 698 | clk = tegra_clk_register_pll_out("pll_a_out0", "pll_a_out0_div", | ||
| 699 | clk_base + PLLA_OUT, 1, 0, CLK_IGNORE_UNUSED | | ||
| 700 | CLK_SET_RATE_PARENT, 0, NULL); | ||
| 701 | clk_register_clkdev(clk, "pll_a_out0", NULL); | ||
| 702 | clks[pll_a_out0] = clk; | ||
| 703 | |||
| 704 | /* PLLE */ | ||
| 705 | clk = tegra_clk_register_plle("pll_e", "pll_ref", clk_base, NULL, | ||
| 706 | 0, 100000000, &pll_e_params, | ||
| 707 | 0, pll_e_freq_table, NULL); | ||
| 708 | clk_register_clkdev(clk, "pll_e", NULL); | ||
| 709 | clks[pll_e] = clk; | ||
| 710 | } | ||
| 711 | |||
| 712 | static const char *cclk_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m", | ||
| 713 | "pll_p_cclk", "pll_p_out4_cclk", | ||
| 714 | "pll_p_out3_cclk", "clk_d", "pll_x" }; | ||
| 715 | static const char *sclk_parents[] = { "clk_m", "pll_c_out1", "pll_p_out4", | ||
| 716 | "pll_p_out3", "pll_p_out2", "clk_d", | ||
| 717 | "clk_32k", "pll_m_out1" }; | ||
| 718 | |||
| 719 | static void tegra20_super_clk_init(void) | ||
| 720 | { | ||
| 721 | struct clk *clk; | ||
| 722 | |||
| 723 | /* | ||
| 724 | * DIV_U71 dividers for CCLK, these dividers are used only | ||
| 725 | * if parent clock is fixed rate. | ||
| 726 | */ | ||
| 727 | |||
| 728 | /* | ||
| 729 | * Clock input to cclk divided from pll_p using | ||
| 730 | * U71 divider of cclk. | ||
| 731 | */ | ||
| 732 | clk = tegra_clk_register_divider("pll_p_cclk", "pll_p", | ||
| 733 | clk_base + SUPER_CCLK_DIVIDER, 0, | ||
| 734 | TEGRA_DIVIDER_INT, 16, 8, 1, NULL); | ||
| 735 | clk_register_clkdev(clk, "pll_p_cclk", NULL); | ||
| 736 | |||
| 737 | /* | ||
| 738 | * Clock input to cclk divided from pll_p_out3 using | ||
| 739 | * U71 divider of cclk. | ||
| 740 | */ | ||
| 741 | clk = tegra_clk_register_divider("pll_p_out3_cclk", "pll_p_out3", | ||
| 742 | clk_base + SUPER_CCLK_DIVIDER, 0, | ||
| 743 | TEGRA_DIVIDER_INT, 16, 8, 1, NULL); | ||
| 744 | clk_register_clkdev(clk, "pll_p_out3_cclk", NULL); | ||
| 745 | |||
| 746 | /* | ||
| 747 | * Clock input to cclk divided from pll_p_out4 using | ||
| 748 | * U71 divider of cclk. | ||
| 749 | */ | ||
| 750 | clk = tegra_clk_register_divider("pll_p_out4_cclk", "pll_p_out4", | ||
| 751 | clk_base + SUPER_CCLK_DIVIDER, 0, | ||
| 752 | TEGRA_DIVIDER_INT, 16, 8, 1, NULL); | ||
| 753 | clk_register_clkdev(clk, "pll_p_out4_cclk", NULL); | ||
| 754 | |||
| 755 | /* CCLK */ | ||
| 756 | clk = tegra_clk_register_super_mux("cclk", cclk_parents, | ||
| 757 | ARRAY_SIZE(cclk_parents), CLK_SET_RATE_PARENT, | ||
| 758 | clk_base + CCLK_BURST_POLICY, 0, 4, 0, 0, NULL); | ||
| 759 | clk_register_clkdev(clk, "cclk", NULL); | ||
| 760 | clks[cclk] = clk; | ||
| 761 | |||
| 762 | /* SCLK */ | ||
| 763 | clk = tegra_clk_register_super_mux("sclk", sclk_parents, | ||
| 764 | ARRAY_SIZE(sclk_parents), CLK_SET_RATE_PARENT, | ||
| 765 | clk_base + SCLK_BURST_POLICY, 0, 4, 0, 0, NULL); | ||
| 766 | clk_register_clkdev(clk, "sclk", NULL); | ||
| 767 | clks[sclk] = clk; | ||
| 768 | |||
| 769 | /* HCLK */ | ||
| 770 | clk = clk_register_divider(NULL, "hclk_div", "sclk", 0, | ||
| 771 | clk_base + CLK_SYSTEM_RATE, 4, 2, 0, NULL); | ||
| 772 | clk = clk_register_gate(NULL, "hclk", "hclk_div", CLK_SET_RATE_PARENT, | ||
| 773 | clk_base + CLK_SYSTEM_RATE, 7, | ||
| 774 | CLK_GATE_SET_TO_DISABLE, NULL); | ||
| 775 | clk_register_clkdev(clk, "hclk", NULL); | ||
| 776 | clks[hclk] = clk; | ||
| 777 | |||
| 778 | /* PCLK */ | ||
| 779 | clk = clk_register_divider(NULL, "pclk_div", "hclk", 0, | ||
| 780 | clk_base + CLK_SYSTEM_RATE, 0, 2, 0, NULL); | ||
| 781 | clk = clk_register_gate(NULL, "pclk", "pclk_div", CLK_SET_RATE_PARENT, | ||
| 782 | clk_base + CLK_SYSTEM_RATE, 3, | ||
| 783 | CLK_GATE_SET_TO_DISABLE, NULL); | ||
| 784 | clk_register_clkdev(clk, "pclk", NULL); | ||
| 785 | clks[pclk] = clk; | ||
| 786 | |||
| 787 | /* twd */ | ||
| 788 | clk = clk_register_fixed_factor(NULL, "twd", "cclk", 0, 1, 4); | ||
| 789 | clk_register_clkdev(clk, "twd", NULL); | ||
| 790 | clks[twd] = clk; | ||
| 791 | } | ||
| 792 | |||
| 793 | static const char *audio_parents[] = {"spdif_in", "i2s1", "i2s2", "unused", | ||
| 794 | "pll_a_out0", "unused", "unused", | ||
| 795 | "unused"}; | ||
| 796 | |||
| 797 | static void __init tegra20_audio_clk_init(void) | ||
| 798 | { | ||
| 799 | struct clk *clk; | ||
| 800 | |||
| 801 | /* audio */ | ||
| 802 | clk = clk_register_mux(NULL, "audio_mux", audio_parents, | ||
| 803 | ARRAY_SIZE(audio_parents), 0, | ||
| 804 | clk_base + AUDIO_SYNC_CLK, 0, 3, 0, NULL); | ||
| 805 | clk = clk_register_gate(NULL, "audio", "audio_mux", 0, | ||
| 806 | clk_base + AUDIO_SYNC_CLK, 4, | ||
| 807 | CLK_GATE_SET_TO_DISABLE, NULL); | ||
| 808 | clk_register_clkdev(clk, "audio", NULL); | ||
| 809 | clks[audio] = clk; | ||
| 810 | |||
| 811 | /* audio_2x */ | ||
| 812 | clk = clk_register_fixed_factor(NULL, "audio_doubler", "audio", | ||
| 813 | CLK_SET_RATE_PARENT, 2, 1); | ||
| 814 | clk = tegra_clk_register_periph_gate("audio_2x", "audio_doubler", | ||
| 815 | TEGRA_PERIPH_NO_RESET, clk_base, | ||
| 816 | CLK_SET_RATE_PARENT, 89, &periph_u_regs, | ||
| 817 | periph_clk_enb_refcnt); | ||
| 818 | clk_register_clkdev(clk, "audio_2x", NULL); | ||
| 819 | clks[audio_2x] = clk; | ||
| 820 | |||
| 821 | } | ||
| 822 | |||
| 823 | static const char *i2s1_parents[] = {"pll_a_out0", "audio_2x", "pll_p", | ||
| 824 | "clk_m"}; | ||
| 825 | static const char *i2s2_parents[] = {"pll_a_out0", "audio_2x", "pll_p", | ||
| 826 | "clk_m"}; | ||
| 827 | static const char *spdif_out_parents[] = {"pll_a_out0", "audio_2x", "pll_p", | ||
| 828 | "clk_m"}; | ||
| 829 | static const char *spdif_in_parents[] = {"pll_p", "pll_c", "pll_m"}; | ||
| 830 | static const char *pwm_parents[] = {"pll_p", "pll_c", "audio", "clk_m", | ||
| 831 | "clk_32k"}; | ||
| 832 | static const char *mux_pllpcm_clkm[] = {"pll_p", "pll_c", "pll_m", "clk_m"}; | ||
| 833 | static const char *mux_pllmcpa[] = {"pll_m", "pll_c", "pll_c", "pll_a"}; | ||
| 834 | static const char *mux_pllpdc_clkm[] = {"pll_p", "pll_d_out0", "pll_c", | ||
| 835 | "clk_m"}; | ||
| 836 | static const char *mux_pllmcp_clkm[] = {"pll_m", "pll_c", "pll_p", "clk_m"}; | ||
| 837 | |||
| 838 | static struct tegra_periph_init_data tegra_periph_clk_list[] = { | ||
| 839 | TEGRA_INIT_DATA_MUX("i2s1", NULL, "tegra20-i2s.0", i2s1_parents, CLK_SOURCE_I2S1, 11, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2s1), | ||
| 840 | TEGRA_INIT_DATA_MUX("i2s2", NULL, "tegra20-i2s.1", i2s2_parents, CLK_SOURCE_I2S2, 18, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2s2), | ||
| 841 | TEGRA_INIT_DATA_MUX("spdif_out", "spdif_out", "tegra20-spdif", spdif_out_parents, CLK_SOURCE_SPDIF_OUT, 10, &periph_l_regs, TEGRA_PERIPH_ON_APB, spdif_out), | ||
| 842 | TEGRA_INIT_DATA_MUX("spdif_in", "spdif_in", "tegra20-spdif", spdif_in_parents, CLK_SOURCE_SPDIF_IN, 10, &periph_l_regs, TEGRA_PERIPH_ON_APB, spdif_in), | ||
| 843 | TEGRA_INIT_DATA_MUX("sbc1", NULL, "spi_tegra.0", mux_pllpcm_clkm, CLK_SOURCE_SBC1, 41, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc1), | ||
| 844 | TEGRA_INIT_DATA_MUX("sbc2", NULL, "spi_tegra.1", mux_pllpcm_clkm, CLK_SOURCE_SBC2, 44, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc2), | ||
| 845 | TEGRA_INIT_DATA_MUX("sbc3", NULL, "spi_tegra.2", mux_pllpcm_clkm, CLK_SOURCE_SBC3, 46, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc3), | ||
| 846 | TEGRA_INIT_DATA_MUX("sbc4", NULL, "spi_tegra.3", mux_pllpcm_clkm, CLK_SOURCE_SBC4, 68, &periph_u_regs, TEGRA_PERIPH_ON_APB, sbc4), | ||
| 847 | TEGRA_INIT_DATA_MUX("spi", NULL, "spi", mux_pllpcm_clkm, CLK_SOURCE_SPI, 43, &periph_h_regs, TEGRA_PERIPH_ON_APB, spi), | ||
| 848 | TEGRA_INIT_DATA_MUX("xio", NULL, "xio", mux_pllpcm_clkm, CLK_SOURCE_XIO, 45, &periph_h_regs, 0, xio), | ||
| 849 | TEGRA_INIT_DATA_MUX("twc", NULL, "twc", mux_pllpcm_clkm, CLK_SOURCE_TWC, 16, &periph_l_regs, TEGRA_PERIPH_ON_APB, twc), | ||
| 850 | TEGRA_INIT_DATA_MUX("ide", NULL, "ide", mux_pllpcm_clkm, CLK_SOURCE_XIO, 25, &periph_l_regs, 0, ide), | ||
| 851 | TEGRA_INIT_DATA_MUX("ndflash", NULL, "tegra_nand", mux_pllpcm_clkm, CLK_SOURCE_NDFLASH, 13, &periph_l_regs, 0, ndflash), | ||
| 852 | TEGRA_INIT_DATA_MUX("vfir", NULL, "vfir", mux_pllpcm_clkm, CLK_SOURCE_VFIR, 7, &periph_l_regs, TEGRA_PERIPH_ON_APB, vfir), | ||
| 853 | TEGRA_INIT_DATA_MUX("csite", NULL, "csite", mux_pllpcm_clkm, CLK_SOURCE_CSITE, 73, &periph_u_regs, 0, csite), | ||
| 854 | TEGRA_INIT_DATA_MUX("la", NULL, "la", mux_pllpcm_clkm, CLK_SOURCE_LA, 76, &periph_u_regs, 0, la), | ||
| 855 | TEGRA_INIT_DATA_MUX("owr", NULL, "tegra_w1", mux_pllpcm_clkm, CLK_SOURCE_OWR, 71, &periph_u_regs, TEGRA_PERIPH_ON_APB, owr), | ||
| 856 | TEGRA_INIT_DATA_MUX("mipi", NULL, "mipi", mux_pllpcm_clkm, CLK_SOURCE_MIPI, 50, &periph_h_regs, TEGRA_PERIPH_ON_APB, mipi), | ||
| 857 | TEGRA_INIT_DATA_MUX("vde", NULL, "vde", mux_pllpcm_clkm, CLK_SOURCE_VDE, 61, &periph_h_regs, 0, vde), | ||
| 858 | TEGRA_INIT_DATA_MUX("vi", "vi", "tegra_camera", mux_pllmcpa, CLK_SOURCE_VI, 20, &periph_l_regs, 0, vi), | ||
| 859 | TEGRA_INIT_DATA_MUX("epp", NULL, "epp", mux_pllmcpa, CLK_SOURCE_EPP, 19, &periph_l_regs, 0, epp), | ||
| 860 | TEGRA_INIT_DATA_MUX("mpe", NULL, "mpe", mux_pllmcpa, CLK_SOURCE_MPE, 60, &periph_h_regs, 0, mpe), | ||
| 861 | TEGRA_INIT_DATA_MUX("host1x", NULL, "host1x", mux_pllmcpa, CLK_SOURCE_HOST1X, 28, &periph_l_regs, 0, host1x), | ||
| 862 | TEGRA_INIT_DATA_MUX("3d", NULL, "3d", mux_pllmcpa, CLK_SOURCE_3D, 24, &periph_l_regs, TEGRA_PERIPH_MANUAL_RESET, gr3d), | ||
| 863 | TEGRA_INIT_DATA_MUX("2d", NULL, "2d", mux_pllmcpa, CLK_SOURCE_2D, 21, &periph_l_regs, 0, gr2d), | ||
| 864 | TEGRA_INIT_DATA_MUX("nor", NULL, "tegra-nor", mux_pllpcm_clkm, CLK_SOURCE_NOR, 42, &periph_h_regs, 0, nor), | ||
| 865 | TEGRA_INIT_DATA_MUX("sdmmc1", NULL, "sdhci-tegra.0", mux_pllpcm_clkm, CLK_SOURCE_SDMMC1, 14, &periph_l_regs, 0, sdmmc1), | ||
| 866 | TEGRA_INIT_DATA_MUX("sdmmc2", NULL, "sdhci-tegra.1", mux_pllpcm_clkm, CLK_SOURCE_SDMMC2, 9, &periph_l_regs, 0, sdmmc2), | ||
| 867 | TEGRA_INIT_DATA_MUX("sdmmc3", NULL, "sdhci-tegra.2", mux_pllpcm_clkm, CLK_SOURCE_SDMMC3, 69, &periph_u_regs, 0, sdmmc3), | ||
| 868 | TEGRA_INIT_DATA_MUX("sdmmc4", NULL, "sdhci-tegra.3", mux_pllpcm_clkm, CLK_SOURCE_SDMMC4, 15, &periph_l_regs, 0, sdmmc4), | ||
| 869 | TEGRA_INIT_DATA_MUX("cve", NULL, "cve", mux_pllpdc_clkm, CLK_SOURCE_CVE, 49, &periph_h_regs, 0, cve), | ||
| 870 | TEGRA_INIT_DATA_MUX("tvo", NULL, "tvo", mux_pllpdc_clkm, CLK_SOURCE_TVO, 49, &periph_h_regs, 0, tvo), | ||
| 871 | TEGRA_INIT_DATA_MUX("tvdac", NULL, "tvdac", mux_pllpdc_clkm, CLK_SOURCE_TVDAC, 53, &periph_h_regs, 0, tvdac), | ||
| 872 | TEGRA_INIT_DATA_MUX("vi_sensor", "vi_sensor", "tegra_camera", mux_pllmcpa, CLK_SOURCE_VI_SENSOR, 20, &periph_l_regs, TEGRA_PERIPH_NO_RESET, vi_sensor), | ||
| 873 | TEGRA_INIT_DATA_DIV16("i2c1", "div-clk", "tegra-i2c.0", mux_pllpcm_clkm, CLK_SOURCE_I2C1, 12, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2c1), | ||
| 874 | TEGRA_INIT_DATA_DIV16("i2c2", "div-clk", "tegra-i2c.1", mux_pllpcm_clkm, CLK_SOURCE_I2C2, 54, &periph_h_regs, TEGRA_PERIPH_ON_APB, i2c2), | ||
| 875 | TEGRA_INIT_DATA_DIV16("i2c3", "div-clk", "tegra-i2c.2", mux_pllpcm_clkm, CLK_SOURCE_I2C3, 67, &periph_u_regs, TEGRA_PERIPH_ON_APB, i2c3), | ||
| 876 | TEGRA_INIT_DATA_DIV16("dvc", "div-clk", "tegra-i2c.3", mux_pllpcm_clkm, CLK_SOURCE_DVC, 47, &periph_h_regs, TEGRA_PERIPH_ON_APB, dvc), | ||
| 877 | TEGRA_INIT_DATA_MUX("hdmi", NULL, "hdmi", mux_pllpdc_clkm, CLK_SOURCE_HDMI, 51, &periph_h_regs, 0, hdmi), | ||
| 878 | TEGRA_INIT_DATA("pwm", NULL, "tegra-pwm", pwm_parents, CLK_SOURCE_PWM, 28, 3, 0, 0, 8, 1, 0, &periph_l_regs, 17, periph_clk_enb_refcnt, TEGRA_PERIPH_ON_APB, pwm), | ||
| 879 | }; | ||
| 880 | |||
| 881 | static struct tegra_periph_init_data tegra_periph_nodiv_clk_list[] = { | ||
| 882 | TEGRA_INIT_DATA_NODIV("uarta", NULL, "tegra_uart.0", mux_pllpcm_clkm, CLK_SOURCE_UARTA, 30, 2, 6, &periph_l_regs, TEGRA_PERIPH_ON_APB, uarta), | ||
| 883 | TEGRA_INIT_DATA_NODIV("uartb", NULL, "tegra_uart.1", mux_pllpcm_clkm, CLK_SOURCE_UARTB, 30, 2, 7, &periph_l_regs, TEGRA_PERIPH_ON_APB, uartb), | ||
| 884 | TEGRA_INIT_DATA_NODIV("uartc", NULL, "tegra_uart.2", mux_pllpcm_clkm, CLK_SOURCE_UARTC, 30, 2, 55, &periph_h_regs, TEGRA_PERIPH_ON_APB, uartc), | ||
| 885 | TEGRA_INIT_DATA_NODIV("uartd", NULL, "tegra_uart.3", mux_pllpcm_clkm, CLK_SOURCE_UARTD, 30, 2, 65, &periph_u_regs, TEGRA_PERIPH_ON_APB, uartd), | ||
| 886 | TEGRA_INIT_DATA_NODIV("uarte", NULL, "tegra_uart.4", mux_pllpcm_clkm, CLK_SOURCE_UARTE, 30, 2, 66, &periph_u_regs, TEGRA_PERIPH_ON_APB, uarte), | ||
| 887 | TEGRA_INIT_DATA_NODIV("disp1", NULL, "tegradc.0", mux_pllpdc_clkm, CLK_SOURCE_DISP1, 30, 2, 27, &periph_l_regs, 0, disp1), | ||
| 888 | TEGRA_INIT_DATA_NODIV("disp2", NULL, "tegradc.1", mux_pllpdc_clkm, CLK_SOURCE_DISP2, 30, 2, 26, &periph_l_regs, 0, disp2), | ||
| 889 | }; | ||
| 890 | |||
| 891 | static void __init tegra20_periph_clk_init(void) | ||
| 892 | { | ||
| 893 | struct tegra_periph_init_data *data; | ||
| 894 | struct clk *clk; | ||
| 895 | int i; | ||
| 896 | |||
| 897 | /* apbdma */ | ||
| 898 | clk = tegra_clk_register_periph_gate("apbdma", "pclk", 0, clk_base, | ||
| 899 | 0, 34, &periph_h_regs, | ||
| 900 | periph_clk_enb_refcnt); | ||
| 901 | clk_register_clkdev(clk, NULL, "tegra-apbdma"); | ||
| 902 | clks[apbdma] = clk; | ||
| 903 | |||
| 904 | /* rtc */ | ||
| 905 | clk = tegra_clk_register_periph_gate("rtc", "clk_32k", | ||
| 906 | TEGRA_PERIPH_NO_RESET, | ||
| 907 | clk_base, 0, 4, &periph_l_regs, | ||
| 908 | periph_clk_enb_refcnt); | ||
| 909 | clk_register_clkdev(clk, NULL, "rtc-tegra"); | ||
| 910 | clks[rtc] = clk; | ||
| 911 | |||
| 912 | /* timer */ | ||
| 913 | clk = tegra_clk_register_periph_gate("timer", "clk_m", 0, clk_base, | ||
| 914 | 0, 5, &periph_l_regs, | ||
| 915 | periph_clk_enb_refcnt); | ||
| 916 | clk_register_clkdev(clk, NULL, "timer"); | ||
| 917 | clks[timer] = clk; | ||
| 918 | |||
| 919 | /* kbc */ | ||
| 920 | clk = tegra_clk_register_periph_gate("kbc", "clk_32k", | ||
| 921 | TEGRA_PERIPH_NO_RESET | TEGRA_PERIPH_ON_APB, | ||
| 922 | clk_base, 0, 36, &periph_h_regs, | ||
| 923 | periph_clk_enb_refcnt); | ||
| 924 | clk_register_clkdev(clk, NULL, "tegra-kbc"); | ||
| 925 | clks[kbc] = clk; | ||
| 926 | |||
| 927 | /* csus */ | ||
| 928 | clk = tegra_clk_register_periph_gate("csus", "clk_m", | ||
| 929 | TEGRA_PERIPH_NO_RESET, | ||
| 930 | clk_base, 0, 92, &periph_u_regs, | ||
| 931 | periph_clk_enb_refcnt); | ||
| 932 | clk_register_clkdev(clk, "csus", "tengra_camera"); | ||
| 933 | clks[csus] = clk; | ||
| 934 | |||
| 935 | /* vcp */ | ||
| 936 | clk = tegra_clk_register_periph_gate("vcp", "clk_m", 0, | ||
| 937 | clk_base, 0, 29, &periph_l_regs, | ||
| 938 | periph_clk_enb_refcnt); | ||
| 939 | clk_register_clkdev(clk, "vcp", "tegra-avp"); | ||
| 940 | clks[vcp] = clk; | ||
| 941 | |||
| 942 | /* bsea */ | ||
| 943 | clk = tegra_clk_register_periph_gate("bsea", "clk_m", 0, | ||
| 944 | clk_base, 0, 62, &periph_h_regs, | ||
| 945 | periph_clk_enb_refcnt); | ||
| 946 | clk_register_clkdev(clk, "bsea", "tegra-avp"); | ||
| 947 | clks[bsea] = clk; | ||
| 948 | |||
| 949 | /* bsev */ | ||
| 950 | clk = tegra_clk_register_periph_gate("bsev", "clk_m", 0, | ||
| 951 | clk_base, 0, 63, &periph_h_regs, | ||
| 952 | periph_clk_enb_refcnt); | ||
| 953 | clk_register_clkdev(clk, "bsev", "tegra-aes"); | ||
| 954 | clks[bsev] = clk; | ||
| 955 | |||
| 956 | /* emc */ | ||
| 957 | clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm, | ||
| 958 | ARRAY_SIZE(mux_pllmcp_clkm), 0, | ||
| 959 | clk_base + CLK_SOURCE_EMC, | ||
| 960 | 30, 2, 0, NULL); | ||
| 961 | clk = tegra_clk_register_periph_gate("emc", "emc_mux", 0, clk_base, 0, | ||
| 962 | 57, &periph_h_regs, periph_clk_enb_refcnt); | ||
| 963 | clk_register_clkdev(clk, "emc", NULL); | ||
| 964 | clks[emc] = clk; | ||
| 965 | |||
| 966 | /* usbd */ | ||
| 967 | clk = tegra_clk_register_periph_gate("usbd", "clk_m", 0, clk_base, 0, | ||
| 968 | 22, &periph_l_regs, periph_clk_enb_refcnt); | ||
| 969 | clk_register_clkdev(clk, NULL, "fsl-tegra-udc"); | ||
| 970 | clks[usbd] = clk; | ||
| 971 | |||
| 972 | /* usb2 */ | ||
| 973 | clk = tegra_clk_register_periph_gate("usb2", "clk_m", 0, clk_base, 0, | ||
| 974 | 58, &periph_h_regs, periph_clk_enb_refcnt); | ||
| 975 | clk_register_clkdev(clk, NULL, "tegra-ehci.1"); | ||
| 976 | clks[usb2] = clk; | ||
| 977 | |||
| 978 | /* usb3 */ | ||
| 979 | clk = tegra_clk_register_periph_gate("usb3", "clk_m", 0, clk_base, 0, | ||
| 980 | 59, &periph_h_regs, periph_clk_enb_refcnt); | ||
| 981 | clk_register_clkdev(clk, NULL, "tegra-ehci.2"); | ||
| 982 | clks[usb3] = clk; | ||
| 983 | |||
| 984 | /* dsi */ | ||
| 985 | clk = tegra_clk_register_periph_gate("dsi", "pll_d", 0, clk_base, 0, | ||
| 986 | 48, &periph_h_regs, periph_clk_enb_refcnt); | ||
| 987 | clk_register_clkdev(clk, NULL, "dsi"); | ||
| 988 | clks[dsi] = clk; | ||
| 989 | |||
| 990 | /* csi */ | ||
| 991 | clk = tegra_clk_register_periph_gate("csi", "pll_p_out3", 0, clk_base, | ||
| 992 | 0, 52, &periph_h_regs, | ||
| 993 | periph_clk_enb_refcnt); | ||
| 994 | clk_register_clkdev(clk, "csi", "tegra_camera"); | ||
| 995 | clks[csi] = clk; | ||
| 996 | |||
| 997 | /* isp */ | ||
| 998 | clk = tegra_clk_register_periph_gate("isp", "clk_m", 0, clk_base, 0, 23, | ||
| 999 | &periph_l_regs, periph_clk_enb_refcnt); | ||
| 1000 | clk_register_clkdev(clk, "isp", "tegra_camera"); | ||
| 1001 | clks[isp] = clk; | ||
| 1002 | |||
| 1003 | /* pex */ | ||
| 1004 | clk = tegra_clk_register_periph_gate("pex", "clk_m", 0, clk_base, 0, 70, | ||
| 1005 | &periph_u_regs, periph_clk_enb_refcnt); | ||
| 1006 | clk_register_clkdev(clk, "pex", NULL); | ||
| 1007 | clks[pex] = clk; | ||
| 1008 | |||
| 1009 | /* afi */ | ||
| 1010 | clk = tegra_clk_register_periph_gate("afi", "clk_m", 0, clk_base, 0, 72, | ||
| 1011 | &periph_u_regs, periph_clk_enb_refcnt); | ||
| 1012 | clk_register_clkdev(clk, "afi", NULL); | ||
| 1013 | clks[afi] = clk; | ||
| 1014 | |||
| 1015 | /* pcie_xclk */ | ||
| 1016 | clk = tegra_clk_register_periph_gate("pcie_xclk", "clk_m", 0, clk_base, | ||
| 1017 | 0, 74, &periph_u_regs, | ||
| 1018 | periph_clk_enb_refcnt); | ||
| 1019 | clk_register_clkdev(clk, "pcie_xclk", NULL); | ||
| 1020 | clks[pcie_xclk] = clk; | ||
| 1021 | |||
| 1022 | /* cdev1 */ | ||
| 1023 | clk = clk_register_fixed_rate(NULL, "cdev1_fixed", NULL, CLK_IS_ROOT, | ||
| 1024 | 26000000); | ||
| 1025 | clk = tegra_clk_register_periph_gate("cdev1", "cdev1_fixed", 0, | ||
| 1026 | clk_base, 0, 94, &periph_u_regs, | ||
| 1027 | periph_clk_enb_refcnt); | ||
| 1028 | clk_register_clkdev(clk, "cdev1", NULL); | ||
| 1029 | clks[cdev1] = clk; | ||
| 1030 | |||
| 1031 | /* cdev2 */ | ||
| 1032 | clk = clk_register_fixed_rate(NULL, "cdev2_fixed", NULL, CLK_IS_ROOT, | ||
| 1033 | 26000000); | ||
| 1034 | clk = tegra_clk_register_periph_gate("cdev2", "cdev2_fixed", 0, | ||
| 1035 | clk_base, 0, 93, &periph_u_regs, | ||
| 1036 | periph_clk_enb_refcnt); | ||
| 1037 | clk_register_clkdev(clk, "cdev2", NULL); | ||
| 1038 | clks[cdev2] = clk; | ||
| 1039 | |||
| 1040 | for (i = 0; i < ARRAY_SIZE(tegra_periph_clk_list); i++) { | ||
| 1041 | data = &tegra_periph_clk_list[i]; | ||
| 1042 | clk = tegra_clk_register_periph(data->name, data->parent_names, | ||
| 1043 | data->num_parents, &data->periph, | ||
| 1044 | clk_base, data->offset); | ||
| 1045 | clk_register_clkdev(clk, data->con_id, data->dev_id); | ||
| 1046 | clks[data->clk_id] = clk; | ||
| 1047 | } | ||
| 1048 | |||
| 1049 | for (i = 0; i < ARRAY_SIZE(tegra_periph_nodiv_clk_list); i++) { | ||
| 1050 | data = &tegra_periph_nodiv_clk_list[i]; | ||
| 1051 | clk = tegra_clk_register_periph_nodiv(data->name, | ||
| 1052 | data->parent_names, | ||
| 1053 | data->num_parents, &data->periph, | ||
| 1054 | clk_base, data->offset); | ||
| 1055 | clk_register_clkdev(clk, data->con_id, data->dev_id); | ||
| 1056 | clks[data->clk_id] = clk; | ||
| 1057 | } | ||
| 1058 | } | ||
| 1059 | |||
| 1060 | |||
| 1061 | static void __init tegra20_fixed_clk_init(void) | ||
| 1062 | { | ||
| 1063 | struct clk *clk; | ||
| 1064 | |||
| 1065 | /* clk_32k */ | ||
| 1066 | clk = clk_register_fixed_rate(NULL, "clk_32k", NULL, CLK_IS_ROOT, | ||
| 1067 | 32768); | ||
| 1068 | clk_register_clkdev(clk, "clk_32k", NULL); | ||
| 1069 | clks[clk_32k] = clk; | ||
| 1070 | } | ||
| 1071 | |||
| 1072 | static void __init tegra20_pmc_clk_init(void) | ||
| 1073 | { | ||
| 1074 | struct clk *clk; | ||
| 1075 | |||
| 1076 | /* blink */ | ||
| 1077 | writel_relaxed(0, pmc_base + PMC_BLINK_TIMER); | ||
| 1078 | clk = clk_register_gate(NULL, "blink_override", "clk_32k", 0, | ||
| 1079 | pmc_base + PMC_DPD_PADS_ORIDE, | ||
| 1080 | PMC_DPD_PADS_ORIDE_BLINK_ENB, 0, NULL); | ||
| 1081 | clk = clk_register_gate(NULL, "blink", "blink_override", 0, | ||
| 1082 | pmc_base + PMC_CTRL, | ||
| 1083 | PMC_CTRL_BLINK_ENB, 0, NULL); | ||
| 1084 | clk_register_clkdev(clk, "blink", NULL); | ||
| 1085 | clks[blink] = clk; | ||
| 1086 | } | ||
| 1087 | |||
| 1088 | static void __init tegra20_osc_clk_init(void) | ||
| 1089 | { | ||
| 1090 | struct clk *clk; | ||
| 1091 | unsigned long input_freq; | ||
| 1092 | unsigned int pll_ref_div; | ||
| 1093 | |||
| 1094 | input_freq = tegra20_clk_measure_input_freq(); | ||
| 1095 | |||
| 1096 | /* clk_m */ | ||
| 1097 | clk = clk_register_fixed_rate(NULL, "clk_m", NULL, CLK_IS_ROOT | | ||
| 1098 | CLK_IGNORE_UNUSED, input_freq); | ||
| 1099 | clk_register_clkdev(clk, "clk_m", NULL); | ||
| 1100 | clks[clk_m] = clk; | ||
| 1101 | |||
| 1102 | /* pll_ref */ | ||
| 1103 | pll_ref_div = tegra20_get_pll_ref_div(); | ||
| 1104 | clk = clk_register_fixed_factor(NULL, "pll_ref", "clk_m", | ||
| 1105 | CLK_SET_RATE_PARENT, 1, pll_ref_div); | ||
| 1106 | clk_register_clkdev(clk, "pll_ref", NULL); | ||
| 1107 | clks[pll_ref] = clk; | ||
| 1108 | } | ||
| 1109 | |||
| 1110 | /* Tegra20 CPU clock and reset control functions */ | ||
| 1111 | static void tegra20_wait_cpu_in_reset(u32 cpu) | ||
| 1112 | { | ||
| 1113 | unsigned int reg; | ||
| 1114 | |||
| 1115 | do { | ||
| 1116 | reg = readl(clk_base + | ||
| 1117 | TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET); | ||
| 1118 | cpu_relax(); | ||
| 1119 | } while (!(reg & (1 << cpu))); /* check CPU been reset or not */ | ||
| 1120 | |||
| 1121 | return; | ||
| 1122 | } | ||
| 1123 | |||
| 1124 | static void tegra20_put_cpu_in_reset(u32 cpu) | ||
| 1125 | { | ||
| 1126 | writel(CPU_RESET(cpu), | ||
| 1127 | clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET); | ||
| 1128 | dmb(); | ||
| 1129 | } | ||
| 1130 | |||
| 1131 | static void tegra20_cpu_out_of_reset(u32 cpu) | ||
| 1132 | { | ||
| 1133 | writel(CPU_RESET(cpu), | ||
| 1134 | clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR); | ||
| 1135 | wmb(); | ||
| 1136 | } | ||
| 1137 | |||
| 1138 | static void tegra20_enable_cpu_clock(u32 cpu) | ||
| 1139 | { | ||
| 1140 | unsigned int reg; | ||
| 1141 | |||
| 1142 | reg = readl(clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); | ||
| 1143 | writel(reg & ~CPU_CLOCK(cpu), | ||
| 1144 | clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); | ||
| 1145 | barrier(); | ||
| 1146 | reg = readl(clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); | ||
| 1147 | } | ||
| 1148 | |||
| 1149 | static void tegra20_disable_cpu_clock(u32 cpu) | ||
| 1150 | { | ||
| 1151 | unsigned int reg; | ||
| 1152 | |||
| 1153 | reg = readl(clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); | ||
| 1154 | writel(reg | CPU_CLOCK(cpu), | ||
| 1155 | clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); | ||
| 1156 | } | ||
| 1157 | |||
| 1158 | #ifdef CONFIG_PM_SLEEP | ||
| 1159 | static bool tegra20_cpu_rail_off_ready(void) | ||
| 1160 | { | ||
| 1161 | unsigned int cpu_rst_status; | ||
| 1162 | |||
| 1163 | cpu_rst_status = readl(clk_base + | ||
| 1164 | TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET); | ||
| 1165 | |||
| 1166 | return !!(cpu_rst_status & 0x2); | ||
| 1167 | } | ||
| 1168 | |||
| 1169 | static void tegra20_cpu_clock_suspend(void) | ||
| 1170 | { | ||
| 1171 | /* switch coresite to clk_m, save off original source */ | ||
| 1172 | tegra20_cpu_clk_sctx.clk_csite_src = | ||
| 1173 | readl(clk_base + CLK_SOURCE_CSITE); | ||
| 1174 | writel(3<<30, clk_base + CLK_SOURCE_CSITE); | ||
| 1175 | |||
| 1176 | tegra20_cpu_clk_sctx.cpu_burst = | ||
| 1177 | readl(clk_base + CCLK_BURST_POLICY); | ||
| 1178 | tegra20_cpu_clk_sctx.pllx_base = | ||
| 1179 | readl(clk_base + PLLX_BASE); | ||
| 1180 | tegra20_cpu_clk_sctx.pllx_misc = | ||
| 1181 | readl(clk_base + PLLX_MISC); | ||
| 1182 | tegra20_cpu_clk_sctx.cclk_divider = | ||
| 1183 | readl(clk_base + SUPER_CCLK_DIVIDER); | ||
| 1184 | } | ||
| 1185 | |||
| 1186 | static void tegra20_cpu_clock_resume(void) | ||
| 1187 | { | ||
| 1188 | unsigned int reg, policy; | ||
| 1189 | |||
| 1190 | /* Is CPU complex already running on PLLX? */ | ||
| 1191 | reg = readl(clk_base + CCLK_BURST_POLICY); | ||
| 1192 | policy = (reg >> CCLK_BURST_POLICY_SHIFT) & 0xF; | ||
| 1193 | |||
| 1194 | if (policy == CCLK_IDLE_POLICY) | ||
| 1195 | reg = (reg >> CCLK_IDLE_POLICY_SHIFT) & 0xF; | ||
| 1196 | else if (policy == CCLK_RUN_POLICY) | ||
| 1197 | reg = (reg >> CCLK_RUN_POLICY_SHIFT) & 0xF; | ||
| 1198 | else | ||
| 1199 | BUG(); | ||
| 1200 | |||
| 1201 | if (reg != CCLK_BURST_POLICY_PLLX) { | ||
| 1202 | /* restore PLLX settings if CPU is on different PLL */ | ||
| 1203 | writel(tegra20_cpu_clk_sctx.pllx_misc, | ||
| 1204 | clk_base + PLLX_MISC); | ||
| 1205 | writel(tegra20_cpu_clk_sctx.pllx_base, | ||
| 1206 | clk_base + PLLX_BASE); | ||
| 1207 | |||
| 1208 | /* wait for PLL stabilization if PLLX was enabled */ | ||
| 1209 | if (tegra20_cpu_clk_sctx.pllx_base & (1 << 30)) | ||
| 1210 | udelay(300); | ||
| 1211 | } | ||
| 1212 | |||
| 1213 | /* | ||
| 1214 | * Restore original burst policy setting for calls resulting from CPU | ||
| 1215 | * LP2 in idle or system suspend. | ||
| 1216 | */ | ||
| 1217 | writel(tegra20_cpu_clk_sctx.cclk_divider, | ||
| 1218 | clk_base + SUPER_CCLK_DIVIDER); | ||
| 1219 | writel(tegra20_cpu_clk_sctx.cpu_burst, | ||
| 1220 | clk_base + CCLK_BURST_POLICY); | ||
| 1221 | |||
| 1222 | writel(tegra20_cpu_clk_sctx.clk_csite_src, | ||
| 1223 | clk_base + CLK_SOURCE_CSITE); | ||
| 1224 | } | ||
| 1225 | #endif | ||
| 1226 | |||
| 1227 | static struct tegra_cpu_car_ops tegra20_cpu_car_ops = { | ||
| 1228 | .wait_for_reset = tegra20_wait_cpu_in_reset, | ||
| 1229 | .put_in_reset = tegra20_put_cpu_in_reset, | ||
| 1230 | .out_of_reset = tegra20_cpu_out_of_reset, | ||
| 1231 | .enable_clock = tegra20_enable_cpu_clock, | ||
| 1232 | .disable_clock = tegra20_disable_cpu_clock, | ||
| 1233 | #ifdef CONFIG_PM_SLEEP | ||
| 1234 | .rail_off_ready = tegra20_cpu_rail_off_ready, | ||
| 1235 | .suspend = tegra20_cpu_clock_suspend, | ||
| 1236 | .resume = tegra20_cpu_clock_resume, | ||
| 1237 | #endif | ||
| 1238 | }; | ||
| 1239 | |||
| 1240 | static __initdata struct tegra_clk_init_table init_table[] = { | ||
| 1241 | {pll_p, clk_max, 216000000, 1}, | ||
| 1242 | {pll_p_out1, clk_max, 28800000, 1}, | ||
| 1243 | {pll_p_out2, clk_max, 48000000, 1}, | ||
| 1244 | {pll_p_out3, clk_max, 72000000, 1}, | ||
| 1245 | {pll_p_out4, clk_max, 24000000, 1}, | ||
| 1246 | {pll_c, clk_max, 600000000, 1}, | ||
| 1247 | {pll_c_out1, clk_max, 120000000, 1}, | ||
| 1248 | {sclk, pll_c_out1, 0, 1}, | ||
| 1249 | {hclk, clk_max, 0, 1}, | ||
| 1250 | {pclk, clk_max, 60000000, 1}, | ||
| 1251 | {csite, clk_max, 0, 1}, | ||
| 1252 | {emc, clk_max, 0, 1}, | ||
| 1253 | {cclk, clk_max, 0, 1}, | ||
| 1254 | {uarta, pll_p, 0, 1}, | ||
| 1255 | {uartd, pll_p, 0, 1}, | ||
| 1256 | {usbd, clk_max, 12000000, 0}, | ||
| 1257 | {usb2, clk_max, 12000000, 0}, | ||
| 1258 | {usb3, clk_max, 12000000, 0}, | ||
| 1259 | {pll_a, clk_max, 56448000, 1}, | ||
| 1260 | {pll_a_out0, clk_max, 11289600, 1}, | ||
| 1261 | {cdev1, clk_max, 0, 1}, | ||
| 1262 | {blink, clk_max, 32768, 1}, | ||
| 1263 | {i2s1, pll_a_out0, 11289600, 0}, | ||
| 1264 | {i2s2, pll_a_out0, 11289600, 0}, | ||
| 1265 | {sdmmc1, pll_p, 48000000, 0}, | ||
| 1266 | {sdmmc3, pll_p, 48000000, 0}, | ||
| 1267 | {sdmmc4, pll_p, 48000000, 0}, | ||
| 1268 | {spi, pll_p, 20000000, 0}, | ||
| 1269 | {sbc1, pll_p, 100000000, 0}, | ||
| 1270 | {sbc2, pll_p, 100000000, 0}, | ||
| 1271 | {sbc3, pll_p, 100000000, 0}, | ||
| 1272 | {sbc4, pll_p, 100000000, 0}, | ||
| 1273 | {host1x, pll_c, 150000000, 0}, | ||
| 1274 | {disp1, pll_p, 600000000, 0}, | ||
| 1275 | {disp2, pll_p, 600000000, 0}, | ||
| 1276 | {clk_max, clk_max, 0, 0}, /* This MUST be the last entry */ | ||
| 1277 | }; | ||
| 1278 | |||
| 1279 | /* | ||
| 1280 | * Some clocks may be used by different drivers depending on the board | ||
| 1281 | * configuration. List those here to register them twice in the clock lookup | ||
| 1282 | * table under two names. | ||
| 1283 | */ | ||
| 1284 | static struct tegra_clk_duplicate tegra_clk_duplicates[] = { | ||
| 1285 | TEGRA_CLK_DUPLICATE(usbd, "utmip-pad", NULL), | ||
| 1286 | TEGRA_CLK_DUPLICATE(usbd, "tegra-ehci.0", NULL), | ||
| 1287 | TEGRA_CLK_DUPLICATE(usbd, "tegra-otg", NULL), | ||
| 1288 | TEGRA_CLK_DUPLICATE(cclk, NULL, "cpu"), | ||
| 1289 | TEGRA_CLK_DUPLICATE(twd, "smp_twd", NULL), | ||
| 1290 | TEGRA_CLK_DUPLICATE(clk_max, NULL, NULL), /* Must be the last entry */ | ||
| 1291 | }; | ||
| 1292 | |||
| 1293 | static const struct of_device_id pmc_match[] __initconst = { | ||
| 1294 | { .compatible = "nvidia,tegra20-pmc" }, | ||
| 1295 | {}, | ||
| 1296 | }; | ||
| 1297 | |||
| 1298 | void __init tegra20_clock_init(struct device_node *np) | ||
| 1299 | { | ||
| 1300 | int i; | ||
| 1301 | struct device_node *node; | ||
| 1302 | |||
| 1303 | clk_base = of_iomap(np, 0); | ||
| 1304 | if (!clk_base) { | ||
| 1305 | pr_err("Can't map CAR registers\n"); | ||
| 1306 | BUG(); | ||
| 1307 | } | ||
| 1308 | |||
| 1309 | node = of_find_matching_node(NULL, pmc_match); | ||
| 1310 | if (!node) { | ||
| 1311 | pr_err("Failed to find pmc node\n"); | ||
| 1312 | BUG(); | ||
| 1313 | } | ||
| 1314 | |||
| 1315 | pmc_base = of_iomap(node, 0); | ||
| 1316 | if (!pmc_base) { | ||
| 1317 | pr_err("Can't map pmc registers\n"); | ||
| 1318 | BUG(); | ||
| 1319 | } | ||
| 1320 | |||
| 1321 | tegra20_osc_clk_init(); | ||
| 1322 | tegra20_pmc_clk_init(); | ||
| 1323 | tegra20_fixed_clk_init(); | ||
| 1324 | tegra20_pll_init(); | ||
| 1325 | tegra20_super_clk_init(); | ||
| 1326 | tegra20_periph_clk_init(); | ||
| 1327 | tegra20_audio_clk_init(); | ||
| 1328 | |||
| 1329 | |||
| 1330 | for (i = 0; i < ARRAY_SIZE(clks); i++) { | ||
| 1331 | if (IS_ERR(clks[i])) { | ||
| 1332 | pr_err("Tegra20 clk %d: register failed with %ld\n", | ||
| 1333 | i, PTR_ERR(clks[i])); | ||
| 1334 | BUG(); | ||
| 1335 | } | ||
| 1336 | if (!clks[i]) | ||
| 1337 | clks[i] = ERR_PTR(-EINVAL); | ||
| 1338 | } | ||
| 1339 | |||
| 1340 | tegra_init_dup_clks(tegra_clk_duplicates, clks, clk_max); | ||
| 1341 | |||
| 1342 | clk_data.clks = clks; | ||
| 1343 | clk_data.clk_num = ARRAY_SIZE(clks); | ||
| 1344 | of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); | ||
| 1345 | |||
| 1346 | tegra_init_from_table(init_table, clks, clk_max); | ||
| 1347 | |||
| 1348 | tegra_cpu_car_ops = &tegra20_cpu_car_ops; | ||
| 1349 | } | ||
diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c new file mode 100644 index 000000000000..a1638129eba4 --- /dev/null +++ b/drivers/clk/tegra/clk-tegra30.c | |||
| @@ -0,0 +1,1987 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/io.h> | ||
| 18 | #include <linux/delay.h> | ||
| 19 | #include <linux/clk.h> | ||
| 20 | #include <linux/clk-provider.h> | ||
| 21 | #include <linux/clkdev.h> | ||
| 22 | #include <linux/of.h> | ||
| 23 | #include <linux/of_address.h> | ||
| 24 | #include <linux/clk/tegra.h> | ||
| 25 | |||
| 26 | #include <mach/powergate.h> | ||
| 27 | |||
| 28 | #include "clk.h" | ||
| 29 | |||
| 30 | #define RST_DEVICES_L 0x004 | ||
| 31 | #define RST_DEVICES_H 0x008 | ||
| 32 | #define RST_DEVICES_U 0x00c | ||
| 33 | #define RST_DEVICES_V 0x358 | ||
| 34 | #define RST_DEVICES_W 0x35c | ||
| 35 | #define RST_DEVICES_SET_L 0x300 | ||
| 36 | #define RST_DEVICES_CLR_L 0x304 | ||
| 37 | #define RST_DEVICES_SET_H 0x308 | ||
| 38 | #define RST_DEVICES_CLR_H 0x30c | ||
| 39 | #define RST_DEVICES_SET_U 0x310 | ||
| 40 | #define RST_DEVICES_CLR_U 0x314 | ||
| 41 | #define RST_DEVICES_SET_V 0x430 | ||
| 42 | #define RST_DEVICES_CLR_V 0x434 | ||
| 43 | #define RST_DEVICES_SET_W 0x438 | ||
| 44 | #define RST_DEVICES_CLR_W 0x43c | ||
| 45 | #define RST_DEVICES_NUM 5 | ||
| 46 | |||
| 47 | #define CLK_OUT_ENB_L 0x010 | ||
| 48 | #define CLK_OUT_ENB_H 0x014 | ||
| 49 | #define CLK_OUT_ENB_U 0x018 | ||
| 50 | #define CLK_OUT_ENB_V 0x360 | ||
| 51 | #define CLK_OUT_ENB_W 0x364 | ||
| 52 | #define CLK_OUT_ENB_SET_L 0x320 | ||
| 53 | #define CLK_OUT_ENB_CLR_L 0x324 | ||
| 54 | #define CLK_OUT_ENB_SET_H 0x328 | ||
| 55 | #define CLK_OUT_ENB_CLR_H 0x32c | ||
| 56 | #define CLK_OUT_ENB_SET_U 0x330 | ||
| 57 | #define CLK_OUT_ENB_CLR_U 0x334 | ||
| 58 | #define CLK_OUT_ENB_SET_V 0x440 | ||
| 59 | #define CLK_OUT_ENB_CLR_V 0x444 | ||
| 60 | #define CLK_OUT_ENB_SET_W 0x448 | ||
| 61 | #define CLK_OUT_ENB_CLR_W 0x44c | ||
| 62 | #define CLK_OUT_ENB_NUM 5 | ||
| 63 | |||
| 64 | #define OSC_CTRL 0x50 | ||
| 65 | #define OSC_CTRL_OSC_FREQ_MASK (0xF<<28) | ||
| 66 | #define OSC_CTRL_OSC_FREQ_13MHZ (0X0<<28) | ||
| 67 | #define OSC_CTRL_OSC_FREQ_19_2MHZ (0X4<<28) | ||
| 68 | #define OSC_CTRL_OSC_FREQ_12MHZ (0X8<<28) | ||
| 69 | #define OSC_CTRL_OSC_FREQ_26MHZ (0XC<<28) | ||
| 70 | #define OSC_CTRL_OSC_FREQ_16_8MHZ (0X1<<28) | ||
| 71 | #define OSC_CTRL_OSC_FREQ_38_4MHZ (0X5<<28) | ||
| 72 | #define OSC_CTRL_OSC_FREQ_48MHZ (0X9<<28) | ||
| 73 | #define OSC_CTRL_MASK (0x3f2 | OSC_CTRL_OSC_FREQ_MASK) | ||
| 74 | |||
| 75 | #define OSC_CTRL_PLL_REF_DIV_MASK (3<<26) | ||
| 76 | #define OSC_CTRL_PLL_REF_DIV_1 (0<<26) | ||
| 77 | #define OSC_CTRL_PLL_REF_DIV_2 (1<<26) | ||
| 78 | #define OSC_CTRL_PLL_REF_DIV_4 (2<<26) | ||
| 79 | |||
| 80 | #define OSC_FREQ_DET 0x58 | ||
| 81 | #define OSC_FREQ_DET_TRIG BIT(31) | ||
| 82 | |||
| 83 | #define OSC_FREQ_DET_STATUS 0x5c | ||
| 84 | #define OSC_FREQ_DET_BUSY BIT(31) | ||
| 85 | #define OSC_FREQ_DET_CNT_MASK 0xffff | ||
| 86 | |||
| 87 | #define CCLKG_BURST_POLICY 0x368 | ||
| 88 | #define SUPER_CCLKG_DIVIDER 0x36c | ||
| 89 | #define CCLKLP_BURST_POLICY 0x370 | ||
| 90 | #define SUPER_CCLKLP_DIVIDER 0x374 | ||
| 91 | #define SCLK_BURST_POLICY 0x028 | ||
| 92 | #define SUPER_SCLK_DIVIDER 0x02c | ||
| 93 | |||
| 94 | #define SYSTEM_CLK_RATE 0x030 | ||
| 95 | |||
| 96 | #define PLLC_BASE 0x80 | ||
| 97 | #define PLLC_MISC 0x8c | ||
| 98 | #define PLLM_BASE 0x90 | ||
| 99 | #define PLLM_MISC 0x9c | ||
| 100 | #define PLLP_BASE 0xa0 | ||
| 101 | #define PLLP_MISC 0xac | ||
| 102 | #define PLLX_BASE 0xe0 | ||
| 103 | #define PLLX_MISC 0xe4 | ||
| 104 | #define PLLD_BASE 0xd0 | ||
| 105 | #define PLLD_MISC 0xdc | ||
| 106 | #define PLLD2_BASE 0x4b8 | ||
| 107 | #define PLLD2_MISC 0x4bc | ||
| 108 | #define PLLE_BASE 0xe8 | ||
| 109 | #define PLLE_MISC 0xec | ||
| 110 | #define PLLA_BASE 0xb0 | ||
| 111 | #define PLLA_MISC 0xbc | ||
| 112 | #define PLLU_BASE 0xc0 | ||
| 113 | #define PLLU_MISC 0xcc | ||
| 114 | |||
| 115 | #define PLL_MISC_LOCK_ENABLE 18 | ||
| 116 | #define PLLDU_MISC_LOCK_ENABLE 22 | ||
| 117 | #define PLLE_MISC_LOCK_ENABLE 9 | ||
| 118 | |||
| 119 | #define PLL_BASE_LOCK 27 | ||
| 120 | #define PLLE_MISC_LOCK 11 | ||
| 121 | |||
| 122 | #define PLLE_AUX 0x48c | ||
| 123 | #define PLLC_OUT 0x84 | ||
| 124 | #define PLLM_OUT 0x94 | ||
| 125 | #define PLLP_OUTA 0xa4 | ||
| 126 | #define PLLP_OUTB 0xa8 | ||
| 127 | #define PLLA_OUT 0xb4 | ||
| 128 | |||
| 129 | #define AUDIO_SYNC_CLK_I2S0 0x4a0 | ||
| 130 | #define AUDIO_SYNC_CLK_I2S1 0x4a4 | ||
| 131 | #define AUDIO_SYNC_CLK_I2S2 0x4a8 | ||
| 132 | #define AUDIO_SYNC_CLK_I2S3 0x4ac | ||
| 133 | #define AUDIO_SYNC_CLK_I2S4 0x4b0 | ||
| 134 | #define AUDIO_SYNC_CLK_SPDIF 0x4b4 | ||
| 135 | |||
| 136 | #define PMC_CLK_OUT_CNTRL 0x1a8 | ||
| 137 | |||
| 138 | #define CLK_SOURCE_I2S0 0x1d8 | ||
| 139 | #define CLK_SOURCE_I2S1 0x100 | ||
| 140 | #define CLK_SOURCE_I2S2 0x104 | ||
| 141 | #define CLK_SOURCE_I2S3 0x3bc | ||
| 142 | #define CLK_SOURCE_I2S4 0x3c0 | ||
| 143 | #define CLK_SOURCE_SPDIF_OUT 0x108 | ||
| 144 | #define CLK_SOURCE_SPDIF_IN 0x10c | ||
| 145 | #define CLK_SOURCE_PWM 0x110 | ||
| 146 | #define CLK_SOURCE_D_AUDIO 0x3d0 | ||
| 147 | #define CLK_SOURCE_DAM0 0x3d8 | ||
| 148 | #define CLK_SOURCE_DAM1 0x3dc | ||
| 149 | #define CLK_SOURCE_DAM2 0x3e0 | ||
| 150 | #define CLK_SOURCE_HDA 0x428 | ||
| 151 | #define CLK_SOURCE_HDA2CODEC_2X 0x3e4 | ||
| 152 | #define CLK_SOURCE_SBC1 0x134 | ||
| 153 | #define CLK_SOURCE_SBC2 0x118 | ||
| 154 | #define CLK_SOURCE_SBC3 0x11c | ||
| 155 | #define CLK_SOURCE_SBC4 0x1b4 | ||
| 156 | #define CLK_SOURCE_SBC5 0x3c8 | ||
| 157 | #define CLK_SOURCE_SBC6 0x3cc | ||
| 158 | #define CLK_SOURCE_SATA_OOB 0x420 | ||
| 159 | #define CLK_SOURCE_SATA 0x424 | ||
| 160 | #define CLK_SOURCE_NDFLASH 0x160 | ||
| 161 | #define CLK_SOURCE_NDSPEED 0x3f8 | ||
| 162 | #define CLK_SOURCE_VFIR 0x168 | ||
| 163 | #define CLK_SOURCE_SDMMC1 0x150 | ||
| 164 | #define CLK_SOURCE_SDMMC2 0x154 | ||
| 165 | #define CLK_SOURCE_SDMMC3 0x1bc | ||
| 166 | #define CLK_SOURCE_SDMMC4 0x164 | ||
| 167 | #define CLK_SOURCE_VDE 0x1c8 | ||
| 168 | #define CLK_SOURCE_CSITE 0x1d4 | ||
| 169 | #define CLK_SOURCE_LA 0x1f8 | ||
| 170 | #define CLK_SOURCE_OWR 0x1cc | ||
| 171 | #define CLK_SOURCE_NOR 0x1d0 | ||
| 172 | #define CLK_SOURCE_MIPI 0x174 | ||
| 173 | #define CLK_SOURCE_I2C1 0x124 | ||
| 174 | #define CLK_SOURCE_I2C2 0x198 | ||
| 175 | #define CLK_SOURCE_I2C3 0x1b8 | ||
| 176 | #define CLK_SOURCE_I2C4 0x3c4 | ||
| 177 | #define CLK_SOURCE_I2C5 0x128 | ||
| 178 | #define CLK_SOURCE_UARTA 0x178 | ||
| 179 | #define CLK_SOURCE_UARTB 0x17c | ||
| 180 | #define CLK_SOURCE_UARTC 0x1a0 | ||
| 181 | #define CLK_SOURCE_UARTD 0x1c0 | ||
| 182 | #define CLK_SOURCE_UARTE 0x1c4 | ||
| 183 | #define CLK_SOURCE_VI 0x148 | ||
| 184 | #define CLK_SOURCE_VI_SENSOR 0x1a8 | ||
| 185 | #define CLK_SOURCE_3D 0x158 | ||
| 186 | #define CLK_SOURCE_3D2 0x3b0 | ||
| 187 | #define CLK_SOURCE_2D 0x15c | ||
| 188 | #define CLK_SOURCE_EPP 0x16c | ||
| 189 | #define CLK_SOURCE_MPE 0x170 | ||
| 190 | #define CLK_SOURCE_HOST1X 0x180 | ||
| 191 | #define CLK_SOURCE_CVE 0x140 | ||
| 192 | #define CLK_SOURCE_TVO 0x188 | ||
| 193 | #define CLK_SOURCE_DTV 0x1dc | ||
| 194 | #define CLK_SOURCE_HDMI 0x18c | ||
| 195 | #define CLK_SOURCE_TVDAC 0x194 | ||
| 196 | #define CLK_SOURCE_DISP1 0x138 | ||
| 197 | #define CLK_SOURCE_DISP2 0x13c | ||
| 198 | #define CLK_SOURCE_DSIB 0xd0 | ||
| 199 | #define CLK_SOURCE_TSENSOR 0x3b8 | ||
| 200 | #define CLK_SOURCE_ACTMON 0x3e8 | ||
| 201 | #define CLK_SOURCE_EXTERN1 0x3ec | ||
| 202 | #define CLK_SOURCE_EXTERN2 0x3f0 | ||
| 203 | #define CLK_SOURCE_EXTERN3 0x3f4 | ||
| 204 | #define CLK_SOURCE_I2CSLOW 0x3fc | ||
| 205 | #define CLK_SOURCE_SE 0x42c | ||
| 206 | #define CLK_SOURCE_MSELECT 0x3b4 | ||
| 207 | #define CLK_SOURCE_EMC 0x19c | ||
| 208 | |||
| 209 | #define AUDIO_SYNC_DOUBLER 0x49c | ||
| 210 | |||
| 211 | #define PMC_CTRL 0 | ||
| 212 | #define PMC_CTRL_BLINK_ENB 7 | ||
| 213 | |||
| 214 | #define PMC_DPD_PADS_ORIDE 0x1c | ||
| 215 | #define PMC_DPD_PADS_ORIDE_BLINK_ENB 20 | ||
| 216 | #define PMC_BLINK_TIMER 0x40 | ||
| 217 | |||
| 218 | #define UTMIP_PLL_CFG2 0x488 | ||
| 219 | #define UTMIP_PLL_CFG2_STABLE_COUNT(x) (((x) & 0xffff) << 6) | ||
| 220 | #define UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(x) (((x) & 0x3f) << 18) | ||
| 221 | #define UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN BIT(0) | ||
| 222 | #define UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN BIT(2) | ||
| 223 | #define UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN BIT(4) | ||
| 224 | |||
| 225 | #define UTMIP_PLL_CFG1 0x484 | ||
| 226 | #define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 6) | ||
| 227 | #define UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0) | ||
| 228 | #define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN BIT(14) | ||
| 229 | #define UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN BIT(12) | ||
| 230 | #define UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN BIT(16) | ||
| 231 | |||
| 232 | /* Tegra CPU clock and reset control regs */ | ||
| 233 | #define TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX 0x4c | ||
| 234 | #define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET 0x340 | ||
| 235 | #define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR 0x344 | ||
| 236 | #define TEGRA30_CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR 0x34c | ||
| 237 | #define TEGRA30_CLK_RST_CONTROLLER_CPU_CMPLX_STATUS 0x470 | ||
| 238 | |||
| 239 | #define CPU_CLOCK(cpu) (0x1 << (8 + cpu)) | ||
| 240 | #define CPU_RESET(cpu) (0x1111ul << (cpu)) | ||
| 241 | |||
| 242 | #define CLK_RESET_CCLK_BURST 0x20 | ||
| 243 | #define CLK_RESET_CCLK_DIVIDER 0x24 | ||
| 244 | #define CLK_RESET_PLLX_BASE 0xe0 | ||
| 245 | #define CLK_RESET_PLLX_MISC 0xe4 | ||
| 246 | |||
| 247 | #define CLK_RESET_SOURCE_CSITE 0x1d4 | ||
| 248 | |||
| 249 | #define CLK_RESET_CCLK_BURST_POLICY_SHIFT 28 | ||
| 250 | #define CLK_RESET_CCLK_RUN_POLICY_SHIFT 4 | ||
| 251 | #define CLK_RESET_CCLK_IDLE_POLICY_SHIFT 0 | ||
| 252 | #define CLK_RESET_CCLK_IDLE_POLICY 1 | ||
| 253 | #define CLK_RESET_CCLK_RUN_POLICY 2 | ||
| 254 | #define CLK_RESET_CCLK_BURST_POLICY_PLLX 8 | ||
| 255 | |||
| 256 | #ifdef CONFIG_PM_SLEEP | ||
| 257 | static struct cpu_clk_suspend_context { | ||
| 258 | u32 pllx_misc; | ||
| 259 | u32 pllx_base; | ||
| 260 | |||
| 261 | u32 cpu_burst; | ||
| 262 | u32 clk_csite_src; | ||
| 263 | u32 cclk_divider; | ||
| 264 | } tegra30_cpu_clk_sctx; | ||
| 265 | #endif | ||
| 266 | |||
| 267 | static int periph_clk_enb_refcnt[CLK_OUT_ENB_NUM * 32]; | ||
| 268 | |||
| 269 | static void __iomem *clk_base; | ||
| 270 | static void __iomem *pmc_base; | ||
| 271 | static unsigned long input_freq; | ||
| 272 | |||
| 273 | static DEFINE_SPINLOCK(clk_doubler_lock); | ||
| 274 | static DEFINE_SPINLOCK(clk_out_lock); | ||
| 275 | static DEFINE_SPINLOCK(pll_div_lock); | ||
| 276 | static DEFINE_SPINLOCK(cml_lock); | ||
| 277 | static DEFINE_SPINLOCK(pll_d_lock); | ||
| 278 | |||
| 279 | #define TEGRA_INIT_DATA_MUX(_name, _con_id, _dev_id, _parents, _offset, \ | ||
| 280 | _clk_num, _regs, _gate_flags, _clk_id) \ | ||
| 281 | TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ | ||
| 282 | 30, 2, 0, 0, 8, 1, 0, _regs, _clk_num, \ | ||
| 283 | periph_clk_enb_refcnt, _gate_flags, _clk_id) | ||
| 284 | |||
| 285 | #define TEGRA_INIT_DATA_DIV16(_name, _con_id, _dev_id, _parents, _offset, \ | ||
| 286 | _clk_num, _regs, _gate_flags, _clk_id) \ | ||
| 287 | TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ | ||
| 288 | 30, 2, 0, 0, 16, 0, TEGRA_DIVIDER_ROUND_UP, \ | ||
| 289 | _regs, _clk_num, periph_clk_enb_refcnt, \ | ||
| 290 | _gate_flags, _clk_id) | ||
| 291 | |||
| 292 | #define TEGRA_INIT_DATA_MUX8(_name, _con_id, _dev_id, _parents, _offset, \ | ||
| 293 | _clk_num, _regs, _gate_flags, _clk_id) \ | ||
| 294 | TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ | ||
| 295 | 29, 3, 0, 0, 8, 1, 0, _regs, _clk_num, \ | ||
| 296 | periph_clk_enb_refcnt, _gate_flags, _clk_id) | ||
| 297 | |||
| 298 | #define TEGRA_INIT_DATA_INT(_name, _con_id, _dev_id, _parents, _offset, \ | ||
| 299 | _clk_num, _regs, _gate_flags, _clk_id) \ | ||
| 300 | TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ | ||
| 301 | 30, 2, 0, 0, 8, 1, TEGRA_DIVIDER_INT, _regs, \ | ||
| 302 | _clk_num, periph_clk_enb_refcnt, _gate_flags, \ | ||
| 303 | _clk_id) | ||
| 304 | |||
| 305 | #define TEGRA_INIT_DATA_UART(_name, _con_id, _dev_id, _parents, _offset,\ | ||
| 306 | _clk_num, _regs, _clk_id) \ | ||
| 307 | TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ | ||
| 308 | 30, 2, 0, 0, 16, 1, TEGRA_DIVIDER_UART, _regs, \ | ||
| 309 | _clk_num, periph_clk_enb_refcnt, 0, _clk_id) | ||
| 310 | |||
| 311 | #define TEGRA_INIT_DATA_NODIV(_name, _con_id, _dev_id, _parents, _offset, \ | ||
| 312 | _mux_shift, _mux_width, _clk_num, _regs, \ | ||
| 313 | _gate_flags, _clk_id) \ | ||
| 314 | TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ | ||
| 315 | _mux_shift, _mux_width, 0, 0, 0, 0, 0, _regs, \ | ||
| 316 | _clk_num, periph_clk_enb_refcnt, _gate_flags, \ | ||
| 317 | _clk_id) | ||
| 318 | |||
| 319 | /* | ||
| 320 | * IDs assigned here must be in sync with DT bindings definition | ||
| 321 | * for Tegra30 clocks. | ||
| 322 | */ | ||
| 323 | enum tegra30_clk { | ||
| 324 | cpu, rtc = 4, timer, uarta, gpio = 8, sdmmc2, i2s1 = 11, i2c1, ndflash, | ||
| 325 | sdmmc1, sdmmc4, pwm = 17, i2s2, epp, gr2d = 21, usbd, isp, gr3d, | ||
| 326 | disp2 = 26, disp1, host1x, vcp, i2s0, cop_cache, mc, ahbdma, apbdma, | ||
| 327 | kbc = 36, statmon, pmc, kfuse = 40, sbc1, nor, sbc2 = 44, sbc3 = 46, | ||
| 328 | i2c5, dsia, mipi = 50, hdmi, csi, tvdac, i2c2, uartc, emc = 57, usb2, | ||
| 329 | usb3, mpe, vde, bsea, bsev, speedo, uartd, uarte, i2c3, sbc4, sdmmc3, | ||
| 330 | pcie, owr, afi, csite, pciex, avpucq, la, dtv = 79, ndspeed, i2c_slow, | ||
| 331 | dsib, irama = 84, iramb, iramc, iramd, cram2, audio_2x = 90, csus = 92, | ||
| 332 | cdev1, cdev2, cpu_g = 96, cpu_lp, gr3d2, mselect, tsensor, i2s3, i2s4, | ||
| 333 | i2c4, sbc5, sbc6, d_audio, apbif, dam0, dam1, dam2, hda2codec_2x, | ||
| 334 | atomics, audio0_2x, audio1_2x, audio2_2x, audio3_2x, audio4_2x, | ||
| 335 | spdif_2x, actmon, extern1, extern2, extern3, sata_oob, sata, hda, se, | ||
| 336 | hda2hdmi, sata_cold, uartb = 160, vfir, spdif_out, spdif_in, vi, | ||
| 337 | vi_sensor, fuse, fuse_burn, cve, tvo, clk_32k, clk_m, clk_m_div2, | ||
| 338 | clk_m_div4, pll_ref, pll_c, pll_c_out1, pll_m, pll_m_out1, pll_p, | ||
| 339 | pll_p_out1, pll_p_out2, pll_p_out3, pll_p_out4, pll_a, pll_a_out0, | ||
| 340 | pll_d, pll_d_out0, pll_d2, pll_d2_out0, pll_u, pll_x, pll_x_out0, pll_e, | ||
| 341 | spdif_in_sync, i2s0_sync, i2s1_sync, i2s2_sync, i2s3_sync, i2s4_sync, | ||
| 342 | vimclk_sync, audio0, audio1, audio2, audio3, audio4, spdif, clk_out_1, | ||
| 343 | clk_out_2, clk_out_3, sclk, blink, cclk_g, cclk_lp, twd, cml0, cml1, | ||
| 344 | i2cslow, hclk, pclk, clk_out_1_mux = 300, clk_max | ||
| 345 | }; | ||
| 346 | |||
| 347 | static struct clk *clks[clk_max]; | ||
| 348 | static struct clk_onecell_data clk_data; | ||
| 349 | |||
| 350 | /* | ||
| 351 | * Structure defining the fields for USB UTMI clocks Parameters. | ||
| 352 | */ | ||
| 353 | struct utmi_clk_param { | ||
| 354 | /* Oscillator Frequency in KHz */ | ||
| 355 | u32 osc_frequency; | ||
| 356 | /* UTMIP PLL Enable Delay Count */ | ||
| 357 | u8 enable_delay_count; | ||
| 358 | /* UTMIP PLL Stable count */ | ||
| 359 | u8 stable_count; | ||
| 360 | /* UTMIP PLL Active delay count */ | ||
| 361 | u8 active_delay_count; | ||
| 362 | /* UTMIP PLL Xtal frequency count */ | ||
| 363 | u8 xtal_freq_count; | ||
| 364 | }; | ||
| 365 | |||
| 366 | static const struct utmi_clk_param utmi_parameters[] = { | ||
| 367 | /* OSC_FREQUENCY, ENABLE_DLY, STABLE_CNT, ACTIVE_DLY, XTAL_FREQ_CNT */ | ||
| 368 | {13000000, 0x02, 0x33, 0x05, 0x7F}, | ||
| 369 | {19200000, 0x03, 0x4B, 0x06, 0xBB}, | ||
| 370 | {12000000, 0x02, 0x2F, 0x04, 0x76}, | ||
| 371 | {26000000, 0x04, 0x66, 0x09, 0xFE}, | ||
| 372 | {16800000, 0x03, 0x41, 0x0A, 0xA4}, | ||
| 373 | }; | ||
| 374 | |||
| 375 | static struct tegra_clk_pll_freq_table pll_c_freq_table[] = { | ||
| 376 | { 12000000, 1040000000, 520, 6, 1, 8}, | ||
| 377 | { 13000000, 1040000000, 480, 6, 1, 8}, | ||
| 378 | { 16800000, 1040000000, 495, 8, 1, 8}, /* actual: 1039.5 MHz */ | ||
| 379 | { 19200000, 1040000000, 325, 6, 1, 6}, | ||
| 380 | { 26000000, 1040000000, 520, 13, 1, 8}, | ||
| 381 | |||
| 382 | { 12000000, 832000000, 416, 6, 1, 8}, | ||
| 383 | { 13000000, 832000000, 832, 13, 1, 8}, | ||
| 384 | { 16800000, 832000000, 396, 8, 1, 8}, /* actual: 831.6 MHz */ | ||
| 385 | { 19200000, 832000000, 260, 6, 1, 8}, | ||
| 386 | { 26000000, 832000000, 416, 13, 1, 8}, | ||
| 387 | |||
| 388 | { 12000000, 624000000, 624, 12, 1, 8}, | ||
| 389 | { 13000000, 624000000, 624, 13, 1, 8}, | ||
| 390 | { 16800000, 600000000, 520, 14, 1, 8}, | ||
| 391 | { 19200000, 624000000, 520, 16, 1, 8}, | ||
| 392 | { 26000000, 624000000, 624, 26, 1, 8}, | ||
| 393 | |||
| 394 | { 12000000, 600000000, 600, 12, 1, 8}, | ||
| 395 | { 13000000, 600000000, 600, 13, 1, 8}, | ||
| 396 | { 16800000, 600000000, 500, 14, 1, 8}, | ||
| 397 | { 19200000, 600000000, 375, 12, 1, 6}, | ||
| 398 | { 26000000, 600000000, 600, 26, 1, 8}, | ||
| 399 | |||
| 400 | { 12000000, 520000000, 520, 12, 1, 8}, | ||
| 401 | { 13000000, 520000000, 520, 13, 1, 8}, | ||
| 402 | { 16800000, 520000000, 495, 16, 1, 8}, /* actual: 519.75 MHz */ | ||
| 403 | { 19200000, 520000000, 325, 12, 1, 6}, | ||
| 404 | { 26000000, 520000000, 520, 26, 1, 8}, | ||
| 405 | |||
| 406 | { 12000000, 416000000, 416, 12, 1, 8}, | ||
| 407 | { 13000000, 416000000, 416, 13, 1, 8}, | ||
| 408 | { 16800000, 416000000, 396, 16, 1, 8}, /* actual: 415.8 MHz */ | ||
| 409 | { 19200000, 416000000, 260, 12, 1, 6}, | ||
| 410 | { 26000000, 416000000, 416, 26, 1, 8}, | ||
| 411 | { 0, 0, 0, 0, 0, 0 }, | ||
| 412 | }; | ||
| 413 | |||
| 414 | static struct tegra_clk_pll_freq_table pll_m_freq_table[] = { | ||
| 415 | { 12000000, 666000000, 666, 12, 1, 8}, | ||
| 416 | { 13000000, 666000000, 666, 13, 1, 8}, | ||
| 417 | { 16800000, 666000000, 555, 14, 1, 8}, | ||
| 418 | { 19200000, 666000000, 555, 16, 1, 8}, | ||
| 419 | { 26000000, 666000000, 666, 26, 1, 8}, | ||
| 420 | { 12000000, 600000000, 600, 12, 1, 8}, | ||
| 421 | { 13000000, 600000000, 600, 13, 1, 8}, | ||
| 422 | { 16800000, 600000000, 500, 14, 1, 8}, | ||
| 423 | { 19200000, 600000000, 375, 12, 1, 6}, | ||
| 424 | { 26000000, 600000000, 600, 26, 1, 8}, | ||
| 425 | { 0, 0, 0, 0, 0, 0 }, | ||
| 426 | }; | ||
| 427 | |||
| 428 | static struct tegra_clk_pll_freq_table pll_p_freq_table[] = { | ||
| 429 | { 12000000, 216000000, 432, 12, 2, 8}, | ||
| 430 | { 13000000, 216000000, 432, 13, 2, 8}, | ||
| 431 | { 16800000, 216000000, 360, 14, 2, 8}, | ||
| 432 | { 19200000, 216000000, 360, 16, 2, 8}, | ||
| 433 | { 26000000, 216000000, 432, 26, 2, 8}, | ||
| 434 | { 0, 0, 0, 0, 0, 0 }, | ||
| 435 | }; | ||
| 436 | |||
| 437 | static struct tegra_clk_pll_freq_table pll_a_freq_table[] = { | ||
| 438 | { 9600000, 564480000, 294, 5, 1, 4}, | ||
| 439 | { 9600000, 552960000, 288, 5, 1, 4}, | ||
| 440 | { 9600000, 24000000, 5, 2, 1, 1}, | ||
| 441 | |||
| 442 | { 28800000, 56448000, 49, 25, 1, 1}, | ||
| 443 | { 28800000, 73728000, 64, 25, 1, 1}, | ||
| 444 | { 28800000, 24000000, 5, 6, 1, 1}, | ||
| 445 | { 0, 0, 0, 0, 0, 0 }, | ||
| 446 | }; | ||
| 447 | |||
| 448 | static struct tegra_clk_pll_freq_table pll_d_freq_table[] = { | ||
| 449 | { 12000000, 216000000, 216, 12, 1, 4}, | ||
| 450 | { 13000000, 216000000, 216, 13, 1, 4}, | ||
| 451 | { 16800000, 216000000, 180, 14, 1, 4}, | ||
| 452 | { 19200000, 216000000, 180, 16, 1, 4}, | ||
| 453 | { 26000000, 216000000, 216, 26, 1, 4}, | ||
| 454 | |||
| 455 | { 12000000, 594000000, 594, 12, 1, 8}, | ||
| 456 | { 13000000, 594000000, 594, 13, 1, 8}, | ||
| 457 | { 16800000, 594000000, 495, 14, 1, 8}, | ||
| 458 | { 19200000, 594000000, 495, 16, 1, 8}, | ||
| 459 | { 26000000, 594000000, 594, 26, 1, 8}, | ||
| 460 | |||
| 461 | { 12000000, 1000000000, 1000, 12, 1, 12}, | ||
| 462 | { 13000000, 1000000000, 1000, 13, 1, 12}, | ||
| 463 | { 19200000, 1000000000, 625, 12, 1, 8}, | ||
| 464 | { 26000000, 1000000000, 1000, 26, 1, 12}, | ||
| 465 | |||
| 466 | { 0, 0, 0, 0, 0, 0 }, | ||
| 467 | }; | ||
| 468 | |||
| 469 | static struct tegra_clk_pll_freq_table pll_u_freq_table[] = { | ||
| 470 | { 12000000, 480000000, 960, 12, 2, 12}, | ||
| 471 | { 13000000, 480000000, 960, 13, 2, 12}, | ||
| 472 | { 16800000, 480000000, 400, 7, 2, 5}, | ||
| 473 | { 19200000, 480000000, 200, 4, 2, 3}, | ||
| 474 | { 26000000, 480000000, 960, 26, 2, 12}, | ||
| 475 | { 0, 0, 0, 0, 0, 0 }, | ||
| 476 | }; | ||
| 477 | |||
| 478 | static struct tegra_clk_pll_freq_table pll_x_freq_table[] = { | ||
| 479 | /* 1.7 GHz */ | ||
| 480 | { 12000000, 1700000000, 850, 6, 1, 8}, | ||
| 481 | { 13000000, 1700000000, 915, 7, 1, 8}, /* actual: 1699.2 MHz */ | ||
| 482 | { 16800000, 1700000000, 708, 7, 1, 8}, /* actual: 1699.2 MHz */ | ||
| 483 | { 19200000, 1700000000, 885, 10, 1, 8}, /* actual: 1699.2 MHz */ | ||
| 484 | { 26000000, 1700000000, 850, 13, 1, 8}, | ||
| 485 | |||
| 486 | /* 1.6 GHz */ | ||
| 487 | { 12000000, 1600000000, 800, 6, 1, 8}, | ||
| 488 | { 13000000, 1600000000, 738, 6, 1, 8}, /* actual: 1599.0 MHz */ | ||
| 489 | { 16800000, 1600000000, 857, 9, 1, 8}, /* actual: 1599.7 MHz */ | ||
| 490 | { 19200000, 1600000000, 500, 6, 1, 8}, | ||
| 491 | { 26000000, 1600000000, 800, 13, 1, 8}, | ||
| 492 | |||
| 493 | /* 1.5 GHz */ | ||
| 494 | { 12000000, 1500000000, 750, 6, 1, 8}, | ||
| 495 | { 13000000, 1500000000, 923, 8, 1, 8}, /* actual: 1499.8 MHz */ | ||
| 496 | { 16800000, 1500000000, 625, 7, 1, 8}, | ||
| 497 | { 19200000, 1500000000, 625, 8, 1, 8}, | ||
| 498 | { 26000000, 1500000000, 750, 13, 1, 8}, | ||
| 499 | |||
| 500 | /* 1.4 GHz */ | ||
| 501 | { 12000000, 1400000000, 700, 6, 1, 8}, | ||
| 502 | { 13000000, 1400000000, 969, 9, 1, 8}, /* actual: 1399.7 MHz */ | ||
| 503 | { 16800000, 1400000000, 1000, 12, 1, 8}, | ||
| 504 | { 19200000, 1400000000, 875, 12, 1, 8}, | ||
| 505 | { 26000000, 1400000000, 700, 13, 1, 8}, | ||
| 506 | |||
| 507 | /* 1.3 GHz */ | ||
| 508 | { 12000000, 1300000000, 975, 9, 1, 8}, | ||
| 509 | { 13000000, 1300000000, 1000, 10, 1, 8}, | ||
| 510 | { 16800000, 1300000000, 928, 12, 1, 8}, /* actual: 1299.2 MHz */ | ||
| 511 | { 19200000, 1300000000, 812, 12, 1, 8}, /* actual: 1299.2 MHz */ | ||
| 512 | { 26000000, 1300000000, 650, 13, 1, 8}, | ||
| 513 | |||
| 514 | /* 1.2 GHz */ | ||
| 515 | { 12000000, 1200000000, 1000, 10, 1, 8}, | ||
| 516 | { 13000000, 1200000000, 923, 10, 1, 8}, /* actual: 1199.9 MHz */ | ||
| 517 | { 16800000, 1200000000, 1000, 14, 1, 8}, | ||
| 518 | { 19200000, 1200000000, 1000, 16, 1, 8}, | ||
| 519 | { 26000000, 1200000000, 600, 13, 1, 8}, | ||
| 520 | |||
| 521 | /* 1.1 GHz */ | ||
| 522 | { 12000000, 1100000000, 825, 9, 1, 8}, | ||
| 523 | { 13000000, 1100000000, 846, 10, 1, 8}, /* actual: 1099.8 MHz */ | ||
| 524 | { 16800000, 1100000000, 982, 15, 1, 8}, /* actual: 1099.8 MHz */ | ||
| 525 | { 19200000, 1100000000, 859, 15, 1, 8}, /* actual: 1099.5 MHz */ | ||
| 526 | { 26000000, 1100000000, 550, 13, 1, 8}, | ||
| 527 | |||
| 528 | /* 1 GHz */ | ||
| 529 | { 12000000, 1000000000, 1000, 12, 1, 8}, | ||
| 530 | { 13000000, 1000000000, 1000, 13, 1, 8}, | ||
| 531 | { 16800000, 1000000000, 833, 14, 1, 8}, /* actual: 999.6 MHz */ | ||
| 532 | { 19200000, 1000000000, 625, 12, 1, 8}, | ||
| 533 | { 26000000, 1000000000, 1000, 26, 1, 8}, | ||
| 534 | |||
| 535 | { 0, 0, 0, 0, 0, 0 }, | ||
| 536 | }; | ||
| 537 | |||
| 538 | static struct tegra_clk_pll_freq_table pll_e_freq_table[] = { | ||
| 539 | /* PLLE special case: use cpcon field to store cml divider value */ | ||
| 540 | { 12000000, 100000000, 150, 1, 18, 11}, | ||
| 541 | { 216000000, 100000000, 200, 18, 24, 13}, | ||
| 542 | { 0, 0, 0, 0, 0, 0 }, | ||
| 543 | }; | ||
| 544 | |||
| 545 | /* PLL parameters */ | ||
| 546 | static struct tegra_clk_pll_params pll_c_params = { | ||
| 547 | .input_min = 2000000, | ||
| 548 | .input_max = 31000000, | ||
| 549 | .cf_min = 1000000, | ||
| 550 | .cf_max = 6000000, | ||
| 551 | .vco_min = 20000000, | ||
| 552 | .vco_max = 1400000000, | ||
| 553 | .base_reg = PLLC_BASE, | ||
| 554 | .misc_reg = PLLC_MISC, | ||
| 555 | .lock_bit_idx = PLL_BASE_LOCK, | ||
| 556 | .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, | ||
| 557 | .lock_delay = 300, | ||
| 558 | }; | ||
| 559 | |||
| 560 | static struct tegra_clk_pll_params pll_m_params = { | ||
| 561 | .input_min = 2000000, | ||
| 562 | .input_max = 31000000, | ||
| 563 | .cf_min = 1000000, | ||
| 564 | .cf_max = 6000000, | ||
| 565 | .vco_min = 20000000, | ||
| 566 | .vco_max = 1200000000, | ||
| 567 | .base_reg = PLLM_BASE, | ||
| 568 | .misc_reg = PLLM_MISC, | ||
| 569 | .lock_bit_idx = PLL_BASE_LOCK, | ||
| 570 | .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, | ||
| 571 | .lock_delay = 300, | ||
| 572 | }; | ||
| 573 | |||
| 574 | static struct tegra_clk_pll_params pll_p_params = { | ||
| 575 | .input_min = 2000000, | ||
| 576 | .input_max = 31000000, | ||
| 577 | .cf_min = 1000000, | ||
| 578 | .cf_max = 6000000, | ||
| 579 | .vco_min = 20000000, | ||
| 580 | .vco_max = 1400000000, | ||
| 581 | .base_reg = PLLP_BASE, | ||
| 582 | .misc_reg = PLLP_MISC, | ||
| 583 | .lock_bit_idx = PLL_BASE_LOCK, | ||
| 584 | .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, | ||
| 585 | .lock_delay = 300, | ||
| 586 | }; | ||
| 587 | |||
| 588 | static struct tegra_clk_pll_params pll_a_params = { | ||
| 589 | .input_min = 2000000, | ||
| 590 | .input_max = 31000000, | ||
| 591 | .cf_min = 1000000, | ||
| 592 | .cf_max = 6000000, | ||
| 593 | .vco_min = 20000000, | ||
| 594 | .vco_max = 1400000000, | ||
| 595 | .base_reg = PLLA_BASE, | ||
| 596 | .misc_reg = PLLA_MISC, | ||
| 597 | .lock_bit_idx = PLL_BASE_LOCK, | ||
| 598 | .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, | ||
| 599 | .lock_delay = 300, | ||
| 600 | }; | ||
| 601 | |||
| 602 | static struct tegra_clk_pll_params pll_d_params = { | ||
| 603 | .input_min = 2000000, | ||
| 604 | .input_max = 40000000, | ||
| 605 | .cf_min = 1000000, | ||
| 606 | .cf_max = 6000000, | ||
| 607 | .vco_min = 40000000, | ||
| 608 | .vco_max = 1000000000, | ||
| 609 | .base_reg = PLLD_BASE, | ||
| 610 | .misc_reg = PLLD_MISC, | ||
| 611 | .lock_bit_idx = PLL_BASE_LOCK, | ||
| 612 | .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, | ||
| 613 | .lock_delay = 1000, | ||
| 614 | }; | ||
| 615 | |||
| 616 | static struct tegra_clk_pll_params pll_d2_params = { | ||
| 617 | .input_min = 2000000, | ||
| 618 | .input_max = 40000000, | ||
| 619 | .cf_min = 1000000, | ||
| 620 | .cf_max = 6000000, | ||
| 621 | .vco_min = 40000000, | ||
| 622 | .vco_max = 1000000000, | ||
| 623 | .base_reg = PLLD2_BASE, | ||
| 624 | .misc_reg = PLLD2_MISC, | ||
| 625 | .lock_bit_idx = PLL_BASE_LOCK, | ||
| 626 | .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, | ||
| 627 | .lock_delay = 1000, | ||
| 628 | }; | ||
| 629 | |||
| 630 | static struct tegra_clk_pll_params pll_u_params = { | ||
| 631 | .input_min = 2000000, | ||
| 632 | .input_max = 40000000, | ||
| 633 | .cf_min = 1000000, | ||
| 634 | .cf_max = 6000000, | ||
| 635 | .vco_min = 48000000, | ||
| 636 | .vco_max = 960000000, | ||
| 637 | .base_reg = PLLU_BASE, | ||
| 638 | .misc_reg = PLLU_MISC, | ||
| 639 | .lock_bit_idx = PLL_BASE_LOCK, | ||
| 640 | .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, | ||
| 641 | .lock_delay = 1000, | ||
| 642 | }; | ||
| 643 | |||
| 644 | static struct tegra_clk_pll_params pll_x_params = { | ||
| 645 | .input_min = 2000000, | ||
| 646 | .input_max = 31000000, | ||
| 647 | .cf_min = 1000000, | ||
| 648 | .cf_max = 6000000, | ||
| 649 | .vco_min = 20000000, | ||
| 650 | .vco_max = 1700000000, | ||
| 651 | .base_reg = PLLX_BASE, | ||
| 652 | .misc_reg = PLLX_MISC, | ||
| 653 | .lock_bit_idx = PLL_BASE_LOCK, | ||
| 654 | .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, | ||
| 655 | .lock_delay = 300, | ||
| 656 | }; | ||
| 657 | |||
| 658 | static struct tegra_clk_pll_params pll_e_params = { | ||
| 659 | .input_min = 12000000, | ||
| 660 | .input_max = 216000000, | ||
| 661 | .cf_min = 12000000, | ||
| 662 | .cf_max = 12000000, | ||
| 663 | .vco_min = 1200000000, | ||
| 664 | .vco_max = 2400000000U, | ||
| 665 | .base_reg = PLLE_BASE, | ||
| 666 | .misc_reg = PLLE_MISC, | ||
| 667 | .lock_bit_idx = PLLE_MISC_LOCK, | ||
| 668 | .lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE, | ||
| 669 | .lock_delay = 300, | ||
| 670 | }; | ||
| 671 | |||
| 672 | /* Peripheral clock registers */ | ||
| 673 | static struct tegra_clk_periph_regs periph_l_regs = { | ||
| 674 | .enb_reg = CLK_OUT_ENB_L, | ||
| 675 | .enb_set_reg = CLK_OUT_ENB_SET_L, | ||
| 676 | .enb_clr_reg = CLK_OUT_ENB_CLR_L, | ||
| 677 | .rst_reg = RST_DEVICES_L, | ||
| 678 | .rst_set_reg = RST_DEVICES_SET_L, | ||
| 679 | .rst_clr_reg = RST_DEVICES_CLR_L, | ||
| 680 | }; | ||
| 681 | |||
| 682 | static struct tegra_clk_periph_regs periph_h_regs = { | ||
| 683 | .enb_reg = CLK_OUT_ENB_H, | ||
| 684 | .enb_set_reg = CLK_OUT_ENB_SET_H, | ||
| 685 | .enb_clr_reg = CLK_OUT_ENB_CLR_H, | ||
| 686 | .rst_reg = RST_DEVICES_H, | ||
| 687 | .rst_set_reg = RST_DEVICES_SET_H, | ||
| 688 | .rst_clr_reg = RST_DEVICES_CLR_H, | ||
| 689 | }; | ||
| 690 | |||
| 691 | static struct tegra_clk_periph_regs periph_u_regs = { | ||
| 692 | .enb_reg = CLK_OUT_ENB_U, | ||
| 693 | .enb_set_reg = CLK_OUT_ENB_SET_U, | ||
| 694 | .enb_clr_reg = CLK_OUT_ENB_CLR_U, | ||
| 695 | .rst_reg = RST_DEVICES_U, | ||
| 696 | .rst_set_reg = RST_DEVICES_SET_U, | ||
| 697 | .rst_clr_reg = RST_DEVICES_CLR_U, | ||
| 698 | }; | ||
| 699 | |||
| 700 | static struct tegra_clk_periph_regs periph_v_regs = { | ||
| 701 | .enb_reg = CLK_OUT_ENB_V, | ||
| 702 | .enb_set_reg = CLK_OUT_ENB_SET_V, | ||
| 703 | .enb_clr_reg = CLK_OUT_ENB_CLR_V, | ||
| 704 | .rst_reg = RST_DEVICES_V, | ||
| 705 | .rst_set_reg = RST_DEVICES_SET_V, | ||
| 706 | .rst_clr_reg = RST_DEVICES_CLR_V, | ||
| 707 | }; | ||
| 708 | |||
| 709 | static struct tegra_clk_periph_regs periph_w_regs = { | ||
| 710 | .enb_reg = CLK_OUT_ENB_W, | ||
| 711 | .enb_set_reg = CLK_OUT_ENB_SET_W, | ||
| 712 | .enb_clr_reg = CLK_OUT_ENB_CLR_W, | ||
| 713 | .rst_reg = RST_DEVICES_W, | ||
| 714 | .rst_set_reg = RST_DEVICES_SET_W, | ||
| 715 | .rst_clr_reg = RST_DEVICES_CLR_W, | ||
| 716 | }; | ||
| 717 | |||
| 718 | static void tegra30_clk_measure_input_freq(void) | ||
| 719 | { | ||
| 720 | u32 osc_ctrl = readl_relaxed(clk_base + OSC_CTRL); | ||
| 721 | u32 auto_clk_control = osc_ctrl & OSC_CTRL_OSC_FREQ_MASK; | ||
| 722 | u32 pll_ref_div = osc_ctrl & OSC_CTRL_PLL_REF_DIV_MASK; | ||
| 723 | |||
| 724 | switch (auto_clk_control) { | ||
| 725 | case OSC_CTRL_OSC_FREQ_12MHZ: | ||
| 726 | BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); | ||
| 727 | input_freq = 12000000; | ||
| 728 | break; | ||
| 729 | case OSC_CTRL_OSC_FREQ_13MHZ: | ||
| 730 | BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); | ||
| 731 | input_freq = 13000000; | ||
| 732 | break; | ||
| 733 | case OSC_CTRL_OSC_FREQ_19_2MHZ: | ||
| 734 | BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); | ||
| 735 | input_freq = 19200000; | ||
| 736 | break; | ||
| 737 | case OSC_CTRL_OSC_FREQ_26MHZ: | ||
| 738 | BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); | ||
| 739 | input_freq = 26000000; | ||
| 740 | break; | ||
| 741 | case OSC_CTRL_OSC_FREQ_16_8MHZ: | ||
| 742 | BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); | ||
| 743 | input_freq = 16800000; | ||
| 744 | break; | ||
| 745 | case OSC_CTRL_OSC_FREQ_38_4MHZ: | ||
| 746 | BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_2); | ||
| 747 | input_freq = 38400000; | ||
| 748 | break; | ||
| 749 | case OSC_CTRL_OSC_FREQ_48MHZ: | ||
| 750 | BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_4); | ||
| 751 | input_freq = 48000000; | ||
| 752 | break; | ||
| 753 | default: | ||
| 754 | pr_err("Unexpected auto clock control value %d", | ||
| 755 | auto_clk_control); | ||
| 756 | BUG(); | ||
| 757 | return; | ||
| 758 | } | ||
| 759 | } | ||
| 760 | |||
| 761 | static unsigned int tegra30_get_pll_ref_div(void) | ||
| 762 | { | ||
| 763 | u32 pll_ref_div = readl_relaxed(clk_base + OSC_CTRL) & | ||
| 764 | OSC_CTRL_PLL_REF_DIV_MASK; | ||
| 765 | |||
| 766 | switch (pll_ref_div) { | ||
| 767 | case OSC_CTRL_PLL_REF_DIV_1: | ||
| 768 | return 1; | ||
| 769 | case OSC_CTRL_PLL_REF_DIV_2: | ||
| 770 | return 2; | ||
| 771 | case OSC_CTRL_PLL_REF_DIV_4: | ||
| 772 | return 4; | ||
| 773 | default: | ||
| 774 | pr_err("Invalid pll ref divider %d", pll_ref_div); | ||
| 775 | BUG(); | ||
| 776 | } | ||
| 777 | return 0; | ||
| 778 | } | ||
| 779 | |||
| 780 | static void tegra30_utmi_param_configure(void) | ||
| 781 | { | ||
| 782 | u32 reg; | ||
| 783 | int i; | ||
| 784 | |||
| 785 | for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) { | ||
| 786 | if (input_freq == utmi_parameters[i].osc_frequency) | ||
| 787 | break; | ||
| 788 | } | ||
| 789 | |||
| 790 | if (i >= ARRAY_SIZE(utmi_parameters)) { | ||
| 791 | pr_err("%s: Unexpected input rate %lu\n", __func__, input_freq); | ||
| 792 | return; | ||
| 793 | } | ||
| 794 | |||
| 795 | reg = readl_relaxed(clk_base + UTMIP_PLL_CFG2); | ||
| 796 | |||
| 797 | /* Program UTMIP PLL stable and active counts */ | ||
| 798 | reg &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0); | ||
| 799 | reg |= UTMIP_PLL_CFG2_STABLE_COUNT( | ||
| 800 | utmi_parameters[i].stable_count); | ||
| 801 | |||
| 802 | reg &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0); | ||
| 803 | |||
| 804 | reg |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT( | ||
| 805 | utmi_parameters[i].active_delay_count); | ||
| 806 | |||
| 807 | /* Remove power downs from UTMIP PLL control bits */ | ||
| 808 | reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN; | ||
| 809 | reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN; | ||
| 810 | reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN; | ||
| 811 | |||
| 812 | writel_relaxed(reg, clk_base + UTMIP_PLL_CFG2); | ||
| 813 | |||
| 814 | /* Program UTMIP PLL delay and oscillator frequency counts */ | ||
| 815 | reg = readl_relaxed(clk_base + UTMIP_PLL_CFG1); | ||
| 816 | reg &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0); | ||
| 817 | |||
| 818 | reg |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT( | ||
| 819 | utmi_parameters[i].enable_delay_count); | ||
| 820 | |||
| 821 | reg &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0); | ||
| 822 | reg |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT( | ||
| 823 | utmi_parameters[i].xtal_freq_count); | ||
| 824 | |||
| 825 | /* Remove power downs from UTMIP PLL control bits */ | ||
| 826 | reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN; | ||
| 827 | reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN; | ||
| 828 | reg &= ~UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN; | ||
| 829 | |||
| 830 | writel_relaxed(reg, clk_base + UTMIP_PLL_CFG1); | ||
| 831 | } | ||
| 832 | |||
| 833 | static const char *pll_e_parents[] = {"pll_ref", "pll_p"}; | ||
| 834 | |||
| 835 | static void __init tegra30_pll_init(void) | ||
| 836 | { | ||
| 837 | struct clk *clk; | ||
| 838 | |||
| 839 | /* PLLC */ | ||
| 840 | clk = tegra_clk_register_pll("pll_c", "pll_ref", clk_base, pmc_base, 0, | ||
| 841 | 0, &pll_c_params, | ||
| 842 | TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK, | ||
| 843 | pll_c_freq_table, NULL); | ||
| 844 | clk_register_clkdev(clk, "pll_c", NULL); | ||
| 845 | clks[pll_c] = clk; | ||
| 846 | |||
| 847 | /* PLLC_OUT1 */ | ||
| 848 | clk = tegra_clk_register_divider("pll_c_out1_div", "pll_c", | ||
| 849 | clk_base + PLLC_OUT, 0, TEGRA_DIVIDER_ROUND_UP, | ||
| 850 | 8, 8, 1, NULL); | ||
| 851 | clk = tegra_clk_register_pll_out("pll_c_out1", "pll_c_out1_div", | ||
| 852 | clk_base + PLLC_OUT, 1, 0, CLK_SET_RATE_PARENT, | ||
| 853 | 0, NULL); | ||
| 854 | clk_register_clkdev(clk, "pll_c_out1", NULL); | ||
| 855 | clks[pll_c_out1] = clk; | ||
| 856 | |||
| 857 | /* PLLP */ | ||
| 858 | clk = tegra_clk_register_pll("pll_p", "pll_ref", clk_base, pmc_base, 0, | ||
| 859 | 408000000, &pll_p_params, | ||
| 860 | TEGRA_PLL_FIXED | TEGRA_PLL_HAS_CPCON | | ||
| 861 | TEGRA_PLL_USE_LOCK, pll_p_freq_table, NULL); | ||
| 862 | clk_register_clkdev(clk, "pll_p", NULL); | ||
| 863 | clks[pll_p] = clk; | ||
| 864 | |||
| 865 | /* PLLP_OUT1 */ | ||
| 866 | clk = tegra_clk_register_divider("pll_p_out1_div", "pll_p", | ||
| 867 | clk_base + PLLP_OUTA, 0, TEGRA_DIVIDER_FIXED | | ||
| 868 | TEGRA_DIVIDER_ROUND_UP, 8, 8, 1, | ||
| 869 | &pll_div_lock); | ||
| 870 | clk = tegra_clk_register_pll_out("pll_p_out1", "pll_p_out1_div", | ||
| 871 | clk_base + PLLP_OUTA, 1, 0, | ||
| 872 | CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, | ||
| 873 | &pll_div_lock); | ||
| 874 | clk_register_clkdev(clk, "pll_p_out1", NULL); | ||
| 875 | clks[pll_p_out1] = clk; | ||
| 876 | |||
| 877 | /* PLLP_OUT2 */ | ||
| 878 | clk = tegra_clk_register_divider("pll_p_out2_div", "pll_p", | ||
| 879 | clk_base + PLLP_OUTA, 0, TEGRA_DIVIDER_FIXED | | ||
| 880 | TEGRA_DIVIDER_ROUND_UP, 24, 8, 1, | ||
| 881 | &pll_div_lock); | ||
| 882 | clk = tegra_clk_register_pll_out("pll_p_out2", "pll_p_out2_div", | ||
| 883 | clk_base + PLLP_OUTA, 17, 16, | ||
| 884 | CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, | ||
| 885 | &pll_div_lock); | ||
| 886 | clk_register_clkdev(clk, "pll_p_out2", NULL); | ||
| 887 | clks[pll_p_out2] = clk; | ||
| 888 | |||
| 889 | /* PLLP_OUT3 */ | ||
| 890 | clk = tegra_clk_register_divider("pll_p_out3_div", "pll_p", | ||
| 891 | clk_base + PLLP_OUTB, 0, TEGRA_DIVIDER_FIXED | | ||
| 892 | TEGRA_DIVIDER_ROUND_UP, 8, 8, 1, | ||
| 893 | &pll_div_lock); | ||
| 894 | clk = tegra_clk_register_pll_out("pll_p_out3", "pll_p_out3_div", | ||
| 895 | clk_base + PLLP_OUTB, 1, 0, | ||
| 896 | CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, | ||
| 897 | &pll_div_lock); | ||
| 898 | clk_register_clkdev(clk, "pll_p_out3", NULL); | ||
| 899 | clks[pll_p_out3] = clk; | ||
| 900 | |||
| 901 | /* PLLP_OUT4 */ | ||
| 902 | clk = tegra_clk_register_divider("pll_p_out4_div", "pll_p", | ||
| 903 | clk_base + PLLP_OUTB, 0, TEGRA_DIVIDER_FIXED | | ||
| 904 | TEGRA_DIVIDER_ROUND_UP, 24, 8, 1, | ||
| 905 | &pll_div_lock); | ||
| 906 | clk = tegra_clk_register_pll_out("pll_p_out4", "pll_p_out4_div", | ||
| 907 | clk_base + PLLP_OUTB, 17, 16, | ||
| 908 | CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, | ||
| 909 | &pll_div_lock); | ||
| 910 | clk_register_clkdev(clk, "pll_p_out4", NULL); | ||
| 911 | clks[pll_p_out4] = clk; | ||
| 912 | |||
| 913 | /* PLLM */ | ||
| 914 | clk = tegra_clk_register_pll("pll_m", "pll_ref", clk_base, pmc_base, | ||
| 915 | CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE, 0, | ||
| 916 | &pll_m_params, TEGRA_PLLM | TEGRA_PLL_HAS_CPCON | | ||
| 917 | TEGRA_PLL_SET_DCCON | TEGRA_PLL_USE_LOCK, | ||
| 918 | pll_m_freq_table, NULL); | ||
| 919 | clk_register_clkdev(clk, "pll_m", NULL); | ||
| 920 | clks[pll_m] = clk; | ||
| 921 | |||
| 922 | /* PLLM_OUT1 */ | ||
| 923 | clk = tegra_clk_register_divider("pll_m_out1_div", "pll_m", | ||
| 924 | clk_base + PLLM_OUT, 0, TEGRA_DIVIDER_ROUND_UP, | ||
| 925 | 8, 8, 1, NULL); | ||
| 926 | clk = tegra_clk_register_pll_out("pll_m_out1", "pll_m_out1_div", | ||
| 927 | clk_base + PLLM_OUT, 1, 0, CLK_IGNORE_UNUSED | | ||
| 928 | CLK_SET_RATE_PARENT, 0, NULL); | ||
| 929 | clk_register_clkdev(clk, "pll_m_out1", NULL); | ||
| 930 | clks[pll_m_out1] = clk; | ||
| 931 | |||
| 932 | /* PLLX */ | ||
| 933 | clk = tegra_clk_register_pll("pll_x", "pll_ref", clk_base, pmc_base, 0, | ||
| 934 | 0, &pll_x_params, TEGRA_PLL_HAS_CPCON | | ||
| 935 | TEGRA_PLL_SET_DCCON | TEGRA_PLL_USE_LOCK, | ||
| 936 | pll_x_freq_table, NULL); | ||
| 937 | clk_register_clkdev(clk, "pll_x", NULL); | ||
| 938 | clks[pll_x] = clk; | ||
| 939 | |||
| 940 | /* PLLX_OUT0 */ | ||
| 941 | clk = clk_register_fixed_factor(NULL, "pll_x_out0", "pll_x", | ||
| 942 | CLK_SET_RATE_PARENT, 1, 2); | ||
| 943 | clk_register_clkdev(clk, "pll_x_out0", NULL); | ||
| 944 | clks[pll_x_out0] = clk; | ||
| 945 | |||
| 946 | /* PLLU */ | ||
| 947 | clk = tegra_clk_register_pll("pll_u", "pll_ref", clk_base, pmc_base, 0, | ||
| 948 | 0, &pll_u_params, TEGRA_PLLU | TEGRA_PLL_HAS_CPCON | | ||
| 949 | TEGRA_PLL_SET_LFCON | TEGRA_PLL_USE_LOCK, | ||
| 950 | pll_u_freq_table, | ||
| 951 | NULL); | ||
| 952 | clk_register_clkdev(clk, "pll_u", NULL); | ||
| 953 | clks[pll_u] = clk; | ||
| 954 | |||
| 955 | tegra30_utmi_param_configure(); | ||
| 956 | |||
| 957 | /* PLLD */ | ||
| 958 | clk = tegra_clk_register_pll("pll_d", "pll_ref", clk_base, pmc_base, 0, | ||
| 959 | 0, &pll_d_params, TEGRA_PLL_HAS_CPCON | | ||
| 960 | TEGRA_PLL_SET_LFCON | TEGRA_PLL_USE_LOCK, | ||
| 961 | pll_d_freq_table, &pll_d_lock); | ||
| 962 | clk_register_clkdev(clk, "pll_d", NULL); | ||
| 963 | clks[pll_d] = clk; | ||
| 964 | |||
| 965 | /* PLLD_OUT0 */ | ||
| 966 | clk = clk_register_fixed_factor(NULL, "pll_d_out0", "pll_d", | ||
| 967 | CLK_SET_RATE_PARENT, 1, 2); | ||
| 968 | clk_register_clkdev(clk, "pll_d_out0", NULL); | ||
| 969 | clks[pll_d_out0] = clk; | ||
| 970 | |||
| 971 | /* PLLD2 */ | ||
| 972 | clk = tegra_clk_register_pll("pll_d2", "pll_ref", clk_base, pmc_base, 0, | ||
| 973 | 0, &pll_d2_params, TEGRA_PLL_HAS_CPCON | | ||
| 974 | TEGRA_PLL_SET_LFCON | TEGRA_PLL_USE_LOCK, | ||
| 975 | pll_d_freq_table, NULL); | ||
| 976 | clk_register_clkdev(clk, "pll_d2", NULL); | ||
| 977 | clks[pll_d2] = clk; | ||
| 978 | |||
| 979 | /* PLLD2_OUT0 */ | ||
| 980 | clk = clk_register_fixed_factor(NULL, "pll_d2_out0", "pll_d2", | ||
| 981 | CLK_SET_RATE_PARENT, 1, 2); | ||
| 982 | clk_register_clkdev(clk, "pll_d2_out0", NULL); | ||
| 983 | clks[pll_d2_out0] = clk; | ||
| 984 | |||
| 985 | /* PLLA */ | ||
| 986 | clk = tegra_clk_register_pll("pll_a", "pll_p_out1", clk_base, pmc_base, | ||
| 987 | 0, 0, &pll_a_params, TEGRA_PLL_HAS_CPCON | | ||
| 988 | TEGRA_PLL_USE_LOCK, pll_a_freq_table, NULL); | ||
| 989 | clk_register_clkdev(clk, "pll_a", NULL); | ||
| 990 | clks[pll_a] = clk; | ||
| 991 | |||
| 992 | /* PLLA_OUT0 */ | ||
| 993 | clk = tegra_clk_register_divider("pll_a_out0_div", "pll_a", | ||
| 994 | clk_base + PLLA_OUT, 0, TEGRA_DIVIDER_ROUND_UP, | ||
| 995 | 8, 8, 1, NULL); | ||
| 996 | clk = tegra_clk_register_pll_out("pll_a_out0", "pll_a_out0_div", | ||
| 997 | clk_base + PLLA_OUT, 1, 0, CLK_IGNORE_UNUSED | | ||
| 998 | CLK_SET_RATE_PARENT, 0, NULL); | ||
| 999 | clk_register_clkdev(clk, "pll_a_out0", NULL); | ||
| 1000 | clks[pll_a_out0] = clk; | ||
| 1001 | |||
| 1002 | /* PLLE */ | ||
| 1003 | clk = clk_register_mux(NULL, "pll_e_mux", pll_e_parents, | ||
| 1004 | ARRAY_SIZE(pll_e_parents), 0, | ||
| 1005 | clk_base + PLLE_AUX, 2, 1, 0, NULL); | ||
| 1006 | clk = tegra_clk_register_plle("pll_e", "pll_e_mux", clk_base, pmc_base, | ||
| 1007 | CLK_GET_RATE_NOCACHE, 100000000, &pll_e_params, | ||
| 1008 | TEGRA_PLLE_CONFIGURE, pll_e_freq_table, NULL); | ||
| 1009 | clk_register_clkdev(clk, "pll_e", NULL); | ||
| 1010 | clks[pll_e] = clk; | ||
| 1011 | } | ||
| 1012 | |||
| 1013 | static const char *mux_audio_sync_clk[] = { "spdif_in_sync", "i2s0_sync", | ||
| 1014 | "i2s1_sync", "i2s2_sync", "i2s3_sync", "i2s4_sync", "vimclk_sync",}; | ||
| 1015 | static const char *clk_out1_parents[] = { "clk_m", "clk_m_div2", | ||
| 1016 | "clk_m_div4", "extern1", }; | ||
| 1017 | static const char *clk_out2_parents[] = { "clk_m", "clk_m_div2", | ||
| 1018 | "clk_m_div4", "extern2", }; | ||
| 1019 | static const char *clk_out3_parents[] = { "clk_m", "clk_m_div2", | ||
| 1020 | "clk_m_div4", "extern3", }; | ||
| 1021 | |||
| 1022 | static void __init tegra30_audio_clk_init(void) | ||
| 1023 | { | ||
| 1024 | struct clk *clk; | ||
| 1025 | |||
| 1026 | /* spdif_in_sync */ | ||
| 1027 | clk = tegra_clk_register_sync_source("spdif_in_sync", 24000000, | ||
| 1028 | 24000000); | ||
| 1029 | clk_register_clkdev(clk, "spdif_in_sync", NULL); | ||
| 1030 | clks[spdif_in_sync] = clk; | ||
| 1031 | |||
| 1032 | /* i2s0_sync */ | ||
| 1033 | clk = tegra_clk_register_sync_source("i2s0_sync", 24000000, 24000000); | ||
| 1034 | clk_register_clkdev(clk, "i2s0_sync", NULL); | ||
| 1035 | clks[i2s0_sync] = clk; | ||
| 1036 | |||
| 1037 | /* i2s1_sync */ | ||
| 1038 | clk = tegra_clk_register_sync_source("i2s1_sync", 24000000, 24000000); | ||
| 1039 | clk_register_clkdev(clk, "i2s1_sync", NULL); | ||
| 1040 | clks[i2s1_sync] = clk; | ||
| 1041 | |||
| 1042 | /* i2s2_sync */ | ||
| 1043 | clk = tegra_clk_register_sync_source("i2s2_sync", 24000000, 24000000); | ||
| 1044 | clk_register_clkdev(clk, "i2s2_sync", NULL); | ||
| 1045 | clks[i2s2_sync] = clk; | ||
| 1046 | |||
| 1047 | /* i2s3_sync */ | ||
| 1048 | clk = tegra_clk_register_sync_source("i2s3_sync", 24000000, 24000000); | ||
| 1049 | clk_register_clkdev(clk, "i2s3_sync", NULL); | ||
| 1050 | clks[i2s3_sync] = clk; | ||
| 1051 | |||
| 1052 | /* i2s4_sync */ | ||
| 1053 | clk = tegra_clk_register_sync_source("i2s4_sync", 24000000, 24000000); | ||
| 1054 | clk_register_clkdev(clk, "i2s4_sync", NULL); | ||
| 1055 | clks[i2s4_sync] = clk; | ||
| 1056 | |||
| 1057 | /* vimclk_sync */ | ||
| 1058 | clk = tegra_clk_register_sync_source("vimclk_sync", 24000000, 24000000); | ||
| 1059 | clk_register_clkdev(clk, "vimclk_sync", NULL); | ||
| 1060 | clks[vimclk_sync] = clk; | ||
| 1061 | |||
| 1062 | /* audio0 */ | ||
| 1063 | clk = clk_register_mux(NULL, "audio0_mux", mux_audio_sync_clk, | ||
| 1064 | ARRAY_SIZE(mux_audio_sync_clk), 0, | ||
| 1065 | clk_base + AUDIO_SYNC_CLK_I2S0, 0, 3, 0, NULL); | ||
| 1066 | clk = clk_register_gate(NULL, "audio0", "audio0_mux", 0, | ||
| 1067 | clk_base + AUDIO_SYNC_CLK_I2S0, 4, | ||
| 1068 | CLK_GATE_SET_TO_DISABLE, NULL); | ||
| 1069 | clk_register_clkdev(clk, "audio0", NULL); | ||
| 1070 | clks[audio0] = clk; | ||
| 1071 | |||
| 1072 | /* audio1 */ | ||
| 1073 | clk = clk_register_mux(NULL, "audio1_mux", mux_audio_sync_clk, | ||
| 1074 | ARRAY_SIZE(mux_audio_sync_clk), 0, | ||
| 1075 | clk_base + AUDIO_SYNC_CLK_I2S1, 0, 3, 0, NULL); | ||
| 1076 | clk = clk_register_gate(NULL, "audio1", "audio1_mux", 0, | ||
| 1077 | clk_base + AUDIO_SYNC_CLK_I2S1, 4, | ||
| 1078 | CLK_GATE_SET_TO_DISABLE, NULL); | ||
| 1079 | clk_register_clkdev(clk, "audio1", NULL); | ||
| 1080 | clks[audio1] = clk; | ||
| 1081 | |||
| 1082 | /* audio2 */ | ||
| 1083 | clk = clk_register_mux(NULL, "audio2_mux", mux_audio_sync_clk, | ||
| 1084 | ARRAY_SIZE(mux_audio_sync_clk), 0, | ||
| 1085 | clk_base + AUDIO_SYNC_CLK_I2S2, 0, 3, 0, NULL); | ||
| 1086 | clk = clk_register_gate(NULL, "audio2", "audio2_mux", 0, | ||
| 1087 | clk_base + AUDIO_SYNC_CLK_I2S2, 4, | ||
| 1088 | CLK_GATE_SET_TO_DISABLE, NULL); | ||
| 1089 | clk_register_clkdev(clk, "audio2", NULL); | ||
| 1090 | clks[audio2] = clk; | ||
| 1091 | |||
| 1092 | /* audio3 */ | ||
| 1093 | clk = clk_register_mux(NULL, "audio3_mux", mux_audio_sync_clk, | ||
| 1094 | ARRAY_SIZE(mux_audio_sync_clk), 0, | ||
| 1095 | clk_base + AUDIO_SYNC_CLK_I2S3, 0, 3, 0, NULL); | ||
| 1096 | clk = clk_register_gate(NULL, "audio3", "audio3_mux", 0, | ||
| 1097 | clk_base + AUDIO_SYNC_CLK_I2S3, 4, | ||
| 1098 | CLK_GATE_SET_TO_DISABLE, NULL); | ||
| 1099 | clk_register_clkdev(clk, "audio3", NULL); | ||
| 1100 | clks[audio3] = clk; | ||
| 1101 | |||
| 1102 | /* audio4 */ | ||
| 1103 | clk = clk_register_mux(NULL, "audio4_mux", mux_audio_sync_clk, | ||
| 1104 | ARRAY_SIZE(mux_audio_sync_clk), 0, | ||
| 1105 | clk_base + AUDIO_SYNC_CLK_I2S4, 0, 3, 0, NULL); | ||
| 1106 | clk = clk_register_gate(NULL, "audio4", "audio4_mux", 0, | ||
| 1107 | clk_base + AUDIO_SYNC_CLK_I2S4, 4, | ||
| 1108 | CLK_GATE_SET_TO_DISABLE, NULL); | ||
| 1109 | clk_register_clkdev(clk, "audio4", NULL); | ||
| 1110 | clks[audio4] = clk; | ||
| 1111 | |||
| 1112 | /* spdif */ | ||
| 1113 | clk = clk_register_mux(NULL, "spdif_mux", mux_audio_sync_clk, | ||
| 1114 | ARRAY_SIZE(mux_audio_sync_clk), 0, | ||
| 1115 | clk_base + AUDIO_SYNC_CLK_SPDIF, 0, 3, 0, NULL); | ||
| 1116 | clk = clk_register_gate(NULL, "spdif", "spdif_mux", 0, | ||
| 1117 | clk_base + AUDIO_SYNC_CLK_SPDIF, 4, | ||
| 1118 | CLK_GATE_SET_TO_DISABLE, NULL); | ||
| 1119 | clk_register_clkdev(clk, "spdif", NULL); | ||
| 1120 | clks[spdif] = clk; | ||
| 1121 | |||
| 1122 | /* audio0_2x */ | ||
| 1123 | clk = clk_register_fixed_factor(NULL, "audio0_doubler", "audio0", | ||
| 1124 | CLK_SET_RATE_PARENT, 2, 1); | ||
| 1125 | clk = tegra_clk_register_divider("audio0_div", "audio0_doubler", | ||
| 1126 | clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 24, 1, 0, | ||
| 1127 | &clk_doubler_lock); | ||
| 1128 | clk = tegra_clk_register_periph_gate("audio0_2x", "audio0_div", | ||
| 1129 | TEGRA_PERIPH_NO_RESET, clk_base, | ||
| 1130 | CLK_SET_RATE_PARENT, 113, &periph_v_regs, | ||
| 1131 | periph_clk_enb_refcnt); | ||
| 1132 | clk_register_clkdev(clk, "audio0_2x", NULL); | ||
| 1133 | clks[audio0_2x] = clk; | ||
| 1134 | |||
| 1135 | /* audio1_2x */ | ||
| 1136 | clk = clk_register_fixed_factor(NULL, "audio1_doubler", "audio1", | ||
| 1137 | CLK_SET_RATE_PARENT, 2, 1); | ||
| 1138 | clk = tegra_clk_register_divider("audio1_div", "audio1_doubler", | ||
| 1139 | clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 25, 1, 0, | ||
| 1140 | &clk_doubler_lock); | ||
| 1141 | clk = tegra_clk_register_periph_gate("audio1_2x", "audio1_div", | ||
| 1142 | TEGRA_PERIPH_NO_RESET, clk_base, | ||
| 1143 | CLK_SET_RATE_PARENT, 114, &periph_v_regs, | ||
| 1144 | periph_clk_enb_refcnt); | ||
| 1145 | clk_register_clkdev(clk, "audio1_2x", NULL); | ||
| 1146 | clks[audio1_2x] = clk; | ||
| 1147 | |||
| 1148 | /* audio2_2x */ | ||
| 1149 | clk = clk_register_fixed_factor(NULL, "audio2_doubler", "audio2", | ||
| 1150 | CLK_SET_RATE_PARENT, 2, 1); | ||
| 1151 | clk = tegra_clk_register_divider("audio2_div", "audio2_doubler", | ||
| 1152 | clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 26, 1, 0, | ||
| 1153 | &clk_doubler_lock); | ||
| 1154 | clk = tegra_clk_register_periph_gate("audio2_2x", "audio2_div", | ||
| 1155 | TEGRA_PERIPH_NO_RESET, clk_base, | ||
| 1156 | CLK_SET_RATE_PARENT, 115, &periph_v_regs, | ||
| 1157 | periph_clk_enb_refcnt); | ||
| 1158 | clk_register_clkdev(clk, "audio2_2x", NULL); | ||
| 1159 | clks[audio2_2x] = clk; | ||
| 1160 | |||
| 1161 | /* audio3_2x */ | ||
| 1162 | clk = clk_register_fixed_factor(NULL, "audio3_doubler", "audio3", | ||
| 1163 | CLK_SET_RATE_PARENT, 2, 1); | ||
| 1164 | clk = tegra_clk_register_divider("audio3_div", "audio3_doubler", | ||
| 1165 | clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 27, 1, 0, | ||
| 1166 | &clk_doubler_lock); | ||
| 1167 | clk = tegra_clk_register_periph_gate("audio3_2x", "audio3_div", | ||
| 1168 | TEGRA_PERIPH_NO_RESET, clk_base, | ||
| 1169 | CLK_SET_RATE_PARENT, 116, &periph_v_regs, | ||
| 1170 | periph_clk_enb_refcnt); | ||
| 1171 | clk_register_clkdev(clk, "audio3_2x", NULL); | ||
| 1172 | clks[audio3_2x] = clk; | ||
| 1173 | |||
| 1174 | /* audio4_2x */ | ||
| 1175 | clk = clk_register_fixed_factor(NULL, "audio4_doubler", "audio4", | ||
| 1176 | CLK_SET_RATE_PARENT, 2, 1); | ||
| 1177 | clk = tegra_clk_register_divider("audio4_div", "audio4_doubler", | ||
| 1178 | clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 28, 1, 0, | ||
| 1179 | &clk_doubler_lock); | ||
| 1180 | clk = tegra_clk_register_periph_gate("audio4_2x", "audio4_div", | ||
| 1181 | TEGRA_PERIPH_NO_RESET, clk_base, | ||
| 1182 | CLK_SET_RATE_PARENT, 117, &periph_v_regs, | ||
| 1183 | periph_clk_enb_refcnt); | ||
| 1184 | clk_register_clkdev(clk, "audio4_2x", NULL); | ||
| 1185 | clks[audio4_2x] = clk; | ||
| 1186 | |||
| 1187 | /* spdif_2x */ | ||
| 1188 | clk = clk_register_fixed_factor(NULL, "spdif_doubler", "spdif", | ||
| 1189 | CLK_SET_RATE_PARENT, 2, 1); | ||
| 1190 | clk = tegra_clk_register_divider("spdif_div", "spdif_doubler", | ||
| 1191 | clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 29, 1, 0, | ||
| 1192 | &clk_doubler_lock); | ||
| 1193 | clk = tegra_clk_register_periph_gate("spdif_2x", "spdif_div", | ||
| 1194 | TEGRA_PERIPH_NO_RESET, clk_base, | ||
| 1195 | CLK_SET_RATE_PARENT, 118, &periph_v_regs, | ||
| 1196 | periph_clk_enb_refcnt); | ||
| 1197 | clk_register_clkdev(clk, "spdif_2x", NULL); | ||
| 1198 | clks[spdif_2x] = clk; | ||
| 1199 | } | ||
| 1200 | |||
| 1201 | static void __init tegra30_pmc_clk_init(void) | ||
| 1202 | { | ||
| 1203 | struct clk *clk; | ||
| 1204 | |||
| 1205 | /* clk_out_1 */ | ||
| 1206 | clk = clk_register_mux(NULL, "clk_out_1_mux", clk_out1_parents, | ||
| 1207 | ARRAY_SIZE(clk_out1_parents), 0, | ||
| 1208 | pmc_base + PMC_CLK_OUT_CNTRL, 6, 3, 0, | ||
| 1209 | &clk_out_lock); | ||
| 1210 | clks[clk_out_1_mux] = clk; | ||
| 1211 | clk = clk_register_gate(NULL, "clk_out_1", "clk_out_1_mux", 0, | ||
| 1212 | pmc_base + PMC_CLK_OUT_CNTRL, 2, 0, | ||
| 1213 | &clk_out_lock); | ||
| 1214 | clk_register_clkdev(clk, "extern1", "clk_out_1"); | ||
| 1215 | clks[clk_out_1] = clk; | ||
| 1216 | |||
| 1217 | /* clk_out_2 */ | ||
| 1218 | clk = clk_register_mux(NULL, "clk_out_2_mux", clk_out2_parents, | ||
| 1219 | ARRAY_SIZE(clk_out1_parents), 0, | ||
| 1220 | pmc_base + PMC_CLK_OUT_CNTRL, 14, 3, 0, | ||
| 1221 | &clk_out_lock); | ||
| 1222 | clk = clk_register_gate(NULL, "clk_out_2", "clk_out_2_mux", 0, | ||
| 1223 | pmc_base + PMC_CLK_OUT_CNTRL, 10, 0, | ||
| 1224 | &clk_out_lock); | ||
| 1225 | clk_register_clkdev(clk, "extern2", "clk_out_2"); | ||
| 1226 | clks[clk_out_2] = clk; | ||
| 1227 | |||
| 1228 | /* clk_out_3 */ | ||
| 1229 | clk = clk_register_mux(NULL, "clk_out_3_mux", clk_out3_parents, | ||
| 1230 | ARRAY_SIZE(clk_out1_parents), 0, | ||
| 1231 | pmc_base + PMC_CLK_OUT_CNTRL, 22, 3, 0, | ||
| 1232 | &clk_out_lock); | ||
| 1233 | clk = clk_register_gate(NULL, "clk_out_3", "clk_out_3_mux", 0, | ||
| 1234 | pmc_base + PMC_CLK_OUT_CNTRL, 18, 0, | ||
| 1235 | &clk_out_lock); | ||
| 1236 | clk_register_clkdev(clk, "extern3", "clk_out_3"); | ||
| 1237 | clks[clk_out_3] = clk; | ||
| 1238 | |||
| 1239 | /* blink */ | ||
| 1240 | writel_relaxed(0, pmc_base + PMC_BLINK_TIMER); | ||
| 1241 | clk = clk_register_gate(NULL, "blink_override", "clk_32k", 0, | ||
| 1242 | pmc_base + PMC_DPD_PADS_ORIDE, | ||
| 1243 | PMC_DPD_PADS_ORIDE_BLINK_ENB, 0, NULL); | ||
| 1244 | clk = clk_register_gate(NULL, "blink", "blink_override", 0, | ||
| 1245 | pmc_base + PMC_CTRL, | ||
| 1246 | PMC_CTRL_BLINK_ENB, 0, NULL); | ||
| 1247 | clk_register_clkdev(clk, "blink", NULL); | ||
| 1248 | clks[blink] = clk; | ||
| 1249 | |||
| 1250 | } | ||
| 1251 | |||
| 1252 | const char *cclk_g_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m", | ||
| 1253 | "pll_p_cclkg", "pll_p_out4_cclkg", | ||
| 1254 | "pll_p_out3_cclkg", "unused", "pll_x" }; | ||
| 1255 | const char *cclk_lp_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m", | ||
| 1256 | "pll_p_cclklp", "pll_p_out4_cclklp", | ||
| 1257 | "pll_p_out3_cclklp", "unused", "pll_x", | ||
| 1258 | "pll_x_out0" }; | ||
| 1259 | const char *sclk_parents[] = { "clk_m", "pll_c_out1", "pll_p_out4", | ||
| 1260 | "pll_p_out3", "pll_p_out2", "unused", | ||
| 1261 | "clk_32k", "pll_m_out1" }; | ||
| 1262 | |||
| 1263 | static void __init tegra30_super_clk_init(void) | ||
| 1264 | { | ||
| 1265 | struct clk *clk; | ||
| 1266 | |||
| 1267 | /* | ||
| 1268 | * Clock input to cclk_g divided from pll_p using | ||
| 1269 | * U71 divider of cclk_g. | ||
| 1270 | */ | ||
| 1271 | clk = tegra_clk_register_divider("pll_p_cclkg", "pll_p", | ||
| 1272 | clk_base + SUPER_CCLKG_DIVIDER, 0, | ||
| 1273 | TEGRA_DIVIDER_INT, 16, 8, 1, NULL); | ||
| 1274 | clk_register_clkdev(clk, "pll_p_cclkg", NULL); | ||
| 1275 | |||
| 1276 | /* | ||
| 1277 | * Clock input to cclk_g divided from pll_p_out3 using | ||
| 1278 | * U71 divider of cclk_g. | ||
| 1279 | */ | ||
| 1280 | clk = tegra_clk_register_divider("pll_p_out3_cclkg", "pll_p_out3", | ||
| 1281 | clk_base + SUPER_CCLKG_DIVIDER, 0, | ||
| 1282 | TEGRA_DIVIDER_INT, 16, 8, 1, NULL); | ||
| 1283 | clk_register_clkdev(clk, "pll_p_out3_cclkg", NULL); | ||
| 1284 | |||
| 1285 | /* | ||
| 1286 | * Clock input to cclk_g divided from pll_p_out4 using | ||
| 1287 | * U71 divider of cclk_g. | ||
| 1288 | */ | ||
| 1289 | clk = tegra_clk_register_divider("pll_p_out4_cclkg", "pll_p_out4", | ||
| 1290 | clk_base + SUPER_CCLKG_DIVIDER, 0, | ||
| 1291 | TEGRA_DIVIDER_INT, 16, 8, 1, NULL); | ||
| 1292 | clk_register_clkdev(clk, "pll_p_out4_cclkg", NULL); | ||
| 1293 | |||
| 1294 | /* CCLKG */ | ||
| 1295 | clk = tegra_clk_register_super_mux("cclk_g", cclk_g_parents, | ||
| 1296 | ARRAY_SIZE(cclk_g_parents), | ||
| 1297 | CLK_SET_RATE_PARENT, | ||
| 1298 | clk_base + CCLKG_BURST_POLICY, | ||
| 1299 | 0, 4, 0, 0, NULL); | ||
| 1300 | clk_register_clkdev(clk, "cclk_g", NULL); | ||
| 1301 | clks[cclk_g] = clk; | ||
| 1302 | |||
| 1303 | /* | ||
| 1304 | * Clock input to cclk_lp divided from pll_p using | ||
| 1305 | * U71 divider of cclk_lp. | ||
| 1306 | */ | ||
| 1307 | clk = tegra_clk_register_divider("pll_p_cclklp", "pll_p", | ||
| 1308 | clk_base + SUPER_CCLKLP_DIVIDER, 0, | ||
| 1309 | TEGRA_DIVIDER_INT, 16, 8, 1, NULL); | ||
| 1310 | clk_register_clkdev(clk, "pll_p_cclklp", NULL); | ||
| 1311 | |||
| 1312 | /* | ||
| 1313 | * Clock input to cclk_lp divided from pll_p_out3 using | ||
| 1314 | * U71 divider of cclk_lp. | ||
| 1315 | */ | ||
| 1316 | clk = tegra_clk_register_divider("pll_p_out3_cclklp", "pll_p_out3", | ||
| 1317 | clk_base + SUPER_CCLKG_DIVIDER, 0, | ||
| 1318 | TEGRA_DIVIDER_INT, 16, 8, 1, NULL); | ||
| 1319 | clk_register_clkdev(clk, "pll_p_out3_cclklp", NULL); | ||
| 1320 | |||
| 1321 | /* | ||
| 1322 | * Clock input to cclk_lp divided from pll_p_out4 using | ||
| 1323 | * U71 divider of cclk_lp. | ||
| 1324 | */ | ||
| 1325 | clk = tegra_clk_register_divider("pll_p_out4_cclklp", "pll_p_out4", | ||
| 1326 | clk_base + SUPER_CCLKLP_DIVIDER, 0, | ||
| 1327 | TEGRA_DIVIDER_INT, 16, 8, 1, NULL); | ||
| 1328 | clk_register_clkdev(clk, "pll_p_out4_cclklp", NULL); | ||
| 1329 | |||
| 1330 | /* CCLKLP */ | ||
| 1331 | clk = tegra_clk_register_super_mux("cclk_lp", cclk_lp_parents, | ||
| 1332 | ARRAY_SIZE(cclk_lp_parents), | ||
| 1333 | CLK_SET_RATE_PARENT, | ||
| 1334 | clk_base + CCLKLP_BURST_POLICY, | ||
| 1335 | TEGRA_DIVIDER_2, 4, 8, 9, | ||
| 1336 | NULL); | ||
| 1337 | clk_register_clkdev(clk, "cclk_lp", NULL); | ||
| 1338 | clks[cclk_lp] = clk; | ||
| 1339 | |||
| 1340 | /* SCLK */ | ||
| 1341 | clk = tegra_clk_register_super_mux("sclk", sclk_parents, | ||
| 1342 | ARRAY_SIZE(sclk_parents), | ||
| 1343 | CLK_SET_RATE_PARENT, | ||
| 1344 | clk_base + SCLK_BURST_POLICY, | ||
| 1345 | 0, 4, 0, 0, NULL); | ||
| 1346 | clk_register_clkdev(clk, "sclk", NULL); | ||
| 1347 | clks[sclk] = clk; | ||
| 1348 | |||
| 1349 | /* HCLK */ | ||
| 1350 | clk = clk_register_divider(NULL, "hclk_div", "sclk", 0, | ||
| 1351 | clk_base + SYSTEM_CLK_RATE, 4, 2, 0, NULL); | ||
| 1352 | clk = clk_register_gate(NULL, "hclk", "hclk_div", CLK_SET_RATE_PARENT, | ||
| 1353 | clk_base + SYSTEM_CLK_RATE, 7, | ||
| 1354 | CLK_GATE_SET_TO_DISABLE, NULL); | ||
| 1355 | clk_register_clkdev(clk, "hclk", NULL); | ||
| 1356 | clks[hclk] = clk; | ||
| 1357 | |||
| 1358 | /* PCLK */ | ||
| 1359 | clk = clk_register_divider(NULL, "pclk_div", "hclk", 0, | ||
| 1360 | clk_base + SYSTEM_CLK_RATE, 0, 2, 0, NULL); | ||
| 1361 | clk = clk_register_gate(NULL, "pclk", "pclk_div", CLK_SET_RATE_PARENT, | ||
| 1362 | clk_base + SYSTEM_CLK_RATE, 3, | ||
| 1363 | CLK_GATE_SET_TO_DISABLE, NULL); | ||
| 1364 | clk_register_clkdev(clk, "pclk", NULL); | ||
| 1365 | clks[pclk] = clk; | ||
| 1366 | |||
| 1367 | /* twd */ | ||
| 1368 | clk = clk_register_fixed_factor(NULL, "twd", "cclk_g", | ||
| 1369 | CLK_SET_RATE_PARENT, 1, 2); | ||
| 1370 | clk_register_clkdev(clk, "twd", NULL); | ||
| 1371 | clks[twd] = clk; | ||
| 1372 | } | ||
| 1373 | |||
| 1374 | static const char *mux_pllacp_clkm[] = { "pll_a_out0", "unused", "pll_p", | ||
| 1375 | "clk_m" }; | ||
| 1376 | static const char *mux_pllpcm_clkm[] = { "pll_p", "pll_c", "pll_m", "clk_m" }; | ||
| 1377 | static const char *mux_pllmcp_clkm[] = { "pll_m", "pll_c", "pll_p", "clk_m" }; | ||
| 1378 | static const char *i2s0_parents[] = { "pll_a_out0", "audio0_2x", "pll_p", | ||
| 1379 | "clk_m" }; | ||
| 1380 | static const char *i2s1_parents[] = { "pll_a_out0", "audio1_2x", "pll_p", | ||
| 1381 | "clk_m" }; | ||
| 1382 | static const char *i2s2_parents[] = { "pll_a_out0", "audio2_2x", "pll_p", | ||
| 1383 | "clk_m" }; | ||
| 1384 | static const char *i2s3_parents[] = { "pll_a_out0", "audio3_2x", "pll_p", | ||
| 1385 | "clk_m" }; | ||
| 1386 | static const char *i2s4_parents[] = { "pll_a_out0", "audio4_2x", "pll_p", | ||
| 1387 | "clk_m" }; | ||
| 1388 | static const char *spdif_out_parents[] = { "pll_a_out0", "spdif_2x", "pll_p", | ||
| 1389 | "clk_m" }; | ||
| 1390 | static const char *spdif_in_parents[] = { "pll_p", "pll_c", "pll_m" }; | ||
| 1391 | static const char *mux_pllpc_clk32k_clkm[] = { "pll_p", "pll_c", "clk_32k", | ||
| 1392 | "clk_m" }; | ||
| 1393 | static const char *mux_pllpc_clkm_clk32k[] = { "pll_p", "pll_c", "clk_m", | ||
| 1394 | "clk_32k" }; | ||
| 1395 | static const char *mux_pllmcpa[] = { "pll_m", "pll_c", "pll_p", "pll_a_out0" }; | ||
| 1396 | static const char *mux_pllpdc_clkm[] = { "pll_p", "pll_d_out0", "pll_c", | ||
| 1397 | "clk_m" }; | ||
| 1398 | static const char *mux_pllp_clkm[] = { "pll_p", "unused", "unused", "clk_m" }; | ||
| 1399 | static const char *mux_pllpmdacd2_clkm[] = { "pll_p", "pll_m", "pll_d_out0", | ||
| 1400 | "pll_a_out0", "pll_c", | ||
| 1401 | "pll_d2_out0", "clk_m" }; | ||
| 1402 | static const char *mux_plla_clk32k_pllp_clkm_plle[] = { "pll_a_out0", | ||
| 1403 | "clk_32k", "pll_p", | ||
| 1404 | "clk_m", "pll_e" }; | ||
| 1405 | static const char *mux_plld_out0_plld2_out0[] = { "pll_d_out0", | ||
| 1406 | "pll_d2_out0" }; | ||
| 1407 | |||
| 1408 | static struct tegra_periph_init_data tegra_periph_clk_list[] = { | ||
| 1409 | TEGRA_INIT_DATA_MUX("i2s0", NULL, "tegra30-i2s.0", i2s0_parents, CLK_SOURCE_I2S0, 30, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2s0), | ||
| 1410 | TEGRA_INIT_DATA_MUX("i2s1", NULL, "tegra30-i2s.1", i2s1_parents, CLK_SOURCE_I2S1, 11, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2s1), | ||
| 1411 | TEGRA_INIT_DATA_MUX("i2s2", NULL, "tegra30-i2s.2", i2s2_parents, CLK_SOURCE_I2S2, 18, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2s2), | ||
| 1412 | TEGRA_INIT_DATA_MUX("i2s3", NULL, "tegra30-i2s.3", i2s3_parents, CLK_SOURCE_I2S3, 101, &periph_v_regs, TEGRA_PERIPH_ON_APB, i2s3), | ||
| 1413 | TEGRA_INIT_DATA_MUX("i2s4", NULL, "tegra30-i2s.4", i2s4_parents, CLK_SOURCE_I2S4, 102, &periph_v_regs, TEGRA_PERIPH_ON_APB, i2s4), | ||
| 1414 | TEGRA_INIT_DATA_MUX("spdif_out", "spdif_out", "tegra30-spdif", spdif_out_parents, CLK_SOURCE_SPDIF_OUT, 10, &periph_l_regs, TEGRA_PERIPH_ON_APB, spdif_out), | ||
| 1415 | TEGRA_INIT_DATA_MUX("spdif_in", "spdif_in", "tegra30-spdif", spdif_in_parents, CLK_SOURCE_SPDIF_IN, 10, &periph_l_regs, TEGRA_PERIPH_ON_APB, spdif_in), | ||
| 1416 | TEGRA_INIT_DATA_MUX("d_audio", "d_audio", "tegra30-ahub", mux_pllacp_clkm, CLK_SOURCE_D_AUDIO, 106, &periph_v_regs, 0, d_audio), | ||
| 1417 | TEGRA_INIT_DATA_MUX("dam0", NULL, "tegra30-dam.0", mux_pllacp_clkm, CLK_SOURCE_DAM0, 108, &periph_v_regs, 0, dam0), | ||
| 1418 | TEGRA_INIT_DATA_MUX("dam1", NULL, "tegra30-dam.1", mux_pllacp_clkm, CLK_SOURCE_DAM1, 109, &periph_v_regs, 0, dam1), | ||
| 1419 | TEGRA_INIT_DATA_MUX("dam2", NULL, "tegra30-dam.2", mux_pllacp_clkm, CLK_SOURCE_DAM2, 110, &periph_v_regs, 0, dam2), | ||
| 1420 | TEGRA_INIT_DATA_MUX("hda", "hda", "tegra30-hda", mux_pllpcm_clkm, CLK_SOURCE_HDA, 125, &periph_v_regs, 0, hda), | ||
| 1421 | TEGRA_INIT_DATA_MUX("hda2codec_2x", "hda2codec", "tegra30-hda", mux_pllpcm_clkm, CLK_SOURCE_HDA2CODEC_2X, 111, &periph_v_regs, 0, hda2codec_2x), | ||
| 1422 | TEGRA_INIT_DATA_MUX("sbc1", NULL, "spi_tegra.0", mux_pllpcm_clkm, CLK_SOURCE_SBC1, 41, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc1), | ||
| 1423 | TEGRA_INIT_DATA_MUX("sbc2", NULL, "spi_tegra.1", mux_pllpcm_clkm, CLK_SOURCE_SBC2, 44, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc2), | ||
| 1424 | TEGRA_INIT_DATA_MUX("sbc3", NULL, "spi_tegra.2", mux_pllpcm_clkm, CLK_SOURCE_SBC3, 46, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc3), | ||
| 1425 | TEGRA_INIT_DATA_MUX("sbc4", NULL, "spi_tegra.3", mux_pllpcm_clkm, CLK_SOURCE_SBC4, 68, &periph_u_regs, TEGRA_PERIPH_ON_APB, sbc4), | ||
| 1426 | TEGRA_INIT_DATA_MUX("sbc5", NULL, "spi_tegra.4", mux_pllpcm_clkm, CLK_SOURCE_SBC5, 104, &periph_v_regs, TEGRA_PERIPH_ON_APB, sbc5), | ||
| 1427 | TEGRA_INIT_DATA_MUX("sbc6", NULL, "spi_tegra.5", mux_pllpcm_clkm, CLK_SOURCE_SBC6, 105, &periph_v_regs, TEGRA_PERIPH_ON_APB, sbc6), | ||
| 1428 | TEGRA_INIT_DATA_MUX("sata_oob", NULL, "tegra_sata_oob", mux_pllpcm_clkm, CLK_SOURCE_SATA_OOB, 123, &periph_v_regs, TEGRA_PERIPH_ON_APB, sata_oob), | ||
| 1429 | TEGRA_INIT_DATA_MUX("sata", NULL, "tegra_sata", mux_pllpcm_clkm, CLK_SOURCE_SATA, 124, &periph_v_regs, TEGRA_PERIPH_ON_APB, sata), | ||
| 1430 | TEGRA_INIT_DATA_MUX("ndflash", NULL, "tegra_nand", mux_pllpcm_clkm, CLK_SOURCE_NDFLASH, 13, &periph_l_regs, TEGRA_PERIPH_ON_APB, ndflash), | ||
| 1431 | TEGRA_INIT_DATA_MUX("ndspeed", NULL, "tegra_nand_speed", mux_pllpcm_clkm, CLK_SOURCE_NDSPEED, 80, &periph_u_regs, TEGRA_PERIPH_ON_APB, ndspeed), | ||
| 1432 | TEGRA_INIT_DATA_MUX("vfir", NULL, "vfir", mux_pllpcm_clkm, CLK_SOURCE_VFIR, 7, &periph_l_regs, TEGRA_PERIPH_ON_APB, vfir), | ||
| 1433 | TEGRA_INIT_DATA_MUX("csite", NULL, "csite", mux_pllpcm_clkm, CLK_SOURCE_CSITE, 73, &periph_u_regs, TEGRA_PERIPH_ON_APB, csite), | ||
| 1434 | TEGRA_INIT_DATA_MUX("la", NULL, "la", mux_pllpcm_clkm, CLK_SOURCE_LA, 76, &periph_u_regs, TEGRA_PERIPH_ON_APB, la), | ||
| 1435 | TEGRA_INIT_DATA_MUX("owr", NULL, "tegra_w1", mux_pllpcm_clkm, CLK_SOURCE_OWR, 71, &periph_u_regs, TEGRA_PERIPH_ON_APB, owr), | ||
| 1436 | TEGRA_INIT_DATA_MUX("mipi", NULL, "mipi", mux_pllpcm_clkm, CLK_SOURCE_MIPI, 50, &periph_h_regs, TEGRA_PERIPH_ON_APB, mipi), | ||
| 1437 | TEGRA_INIT_DATA_MUX("tsensor", NULL, "tegra-tsensor", mux_pllpc_clkm_clk32k, CLK_SOURCE_TSENSOR, 100, &periph_v_regs, TEGRA_PERIPH_ON_APB, tsensor), | ||
| 1438 | TEGRA_INIT_DATA_MUX("i2cslow", NULL, "i2cslow", mux_pllpc_clk32k_clkm, CLK_SOURCE_I2CSLOW, 81, &periph_u_regs, TEGRA_PERIPH_ON_APB, i2cslow), | ||
| 1439 | TEGRA_INIT_DATA_INT("vde", NULL, "vde", mux_pllpcm_clkm, CLK_SOURCE_VDE, 61, &periph_h_regs, 0, vde), | ||
| 1440 | TEGRA_INIT_DATA_INT("vi", "vi", "tegra_camera", mux_pllmcpa, CLK_SOURCE_VI, 20, &periph_l_regs, 0, vi), | ||
| 1441 | TEGRA_INIT_DATA_INT("epp", NULL, "epp", mux_pllmcpa, CLK_SOURCE_EPP, 19, &periph_l_regs, 0, epp), | ||
| 1442 | TEGRA_INIT_DATA_INT("mpe", NULL, "mpe", mux_pllmcpa, CLK_SOURCE_MPE, 60, &periph_h_regs, 0, mpe), | ||
| 1443 | TEGRA_INIT_DATA_INT("host1x", NULL, "host1x", mux_pllmcpa, CLK_SOURCE_HOST1X, 28, &periph_l_regs, 0, host1x), | ||
| 1444 | TEGRA_INIT_DATA_INT("3d", NULL, "3d", mux_pllmcpa, CLK_SOURCE_3D, 24, &periph_l_regs, TEGRA_PERIPH_MANUAL_RESET, gr3d), | ||
| 1445 | TEGRA_INIT_DATA_INT("3d2", NULL, "3d2", mux_pllmcpa, CLK_SOURCE_3D2, 98, &periph_v_regs, TEGRA_PERIPH_MANUAL_RESET, gr3d2), | ||
| 1446 | TEGRA_INIT_DATA_INT("2d", NULL, "2d", mux_pllmcpa, CLK_SOURCE_2D, 21, &periph_l_regs, 0, gr2d), | ||
| 1447 | TEGRA_INIT_DATA_INT("se", NULL, "se", mux_pllpcm_clkm, CLK_SOURCE_SE, 127, &periph_v_regs, 0, se), | ||
| 1448 | TEGRA_INIT_DATA_MUX("mselect", NULL, "mselect", mux_pllp_clkm, CLK_SOURCE_MSELECT, 99, &periph_v_regs, 0, mselect), | ||
| 1449 | TEGRA_INIT_DATA_MUX("nor", NULL, "tegra-nor", mux_pllpcm_clkm, CLK_SOURCE_NOR, 42, &periph_h_regs, 0, nor), | ||
| 1450 | TEGRA_INIT_DATA_MUX("sdmmc1", NULL, "sdhci-tegra.0", mux_pllpcm_clkm, CLK_SOURCE_SDMMC1, 14, &periph_l_regs, 0, sdmmc1), | ||
| 1451 | TEGRA_INIT_DATA_MUX("sdmmc2", NULL, "sdhci-tegra.1", mux_pllpcm_clkm, CLK_SOURCE_SDMMC2, 9, &periph_l_regs, 0, sdmmc2), | ||
| 1452 | TEGRA_INIT_DATA_MUX("sdmmc3", NULL, "sdhci-tegra.2", mux_pllpcm_clkm, CLK_SOURCE_SDMMC3, 69, &periph_u_regs, 0, sdmmc3), | ||
| 1453 | TEGRA_INIT_DATA_MUX("sdmmc4", NULL, "sdhci-tegra.3", mux_pllpcm_clkm, CLK_SOURCE_SDMMC4, 15, &periph_l_regs, 0, sdmmc4), | ||
| 1454 | TEGRA_INIT_DATA_MUX("cve", NULL, "cve", mux_pllpdc_clkm, CLK_SOURCE_CVE, 49, &periph_h_regs, 0, cve), | ||
| 1455 | TEGRA_INIT_DATA_MUX("tvo", NULL, "tvo", mux_pllpdc_clkm, CLK_SOURCE_TVO, 49, &periph_h_regs, 0, tvo), | ||
| 1456 | TEGRA_INIT_DATA_MUX("tvdac", NULL, "tvdac", mux_pllpdc_clkm, CLK_SOURCE_TVDAC, 53, &periph_h_regs, 0, tvdac), | ||
| 1457 | TEGRA_INIT_DATA_MUX("actmon", NULL, "actmon", mux_pllpc_clk32k_clkm, CLK_SOURCE_ACTMON, 119, &periph_v_regs, 0, actmon), | ||
| 1458 | TEGRA_INIT_DATA_MUX("vi_sensor", "vi_sensor", "tegra_camera", mux_pllmcpa, CLK_SOURCE_VI_SENSOR, 20, &periph_l_regs, TEGRA_PERIPH_NO_RESET, vi_sensor), | ||
| 1459 | TEGRA_INIT_DATA_DIV16("i2c1", "div-clk", "tegra-i2c.0", mux_pllp_clkm, CLK_SOURCE_I2C1, 12, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2c1), | ||
| 1460 | TEGRA_INIT_DATA_DIV16("i2c2", "div-clk", "tegra-i2c.1", mux_pllp_clkm, CLK_SOURCE_I2C2, 54, &periph_h_regs, TEGRA_PERIPH_ON_APB, i2c2), | ||
| 1461 | TEGRA_INIT_DATA_DIV16("i2c3", "div-clk", "tegra-i2c.2", mux_pllp_clkm, CLK_SOURCE_I2C3, 67, &periph_u_regs, TEGRA_PERIPH_ON_APB, i2c3), | ||
| 1462 | TEGRA_INIT_DATA_DIV16("i2c4", "div-clk", "tegra-i2c.3", mux_pllp_clkm, CLK_SOURCE_I2C4, 103, &periph_v_regs, TEGRA_PERIPH_ON_APB, i2c4), | ||
| 1463 | TEGRA_INIT_DATA_DIV16("i2c5", "div-clk", "tegra-i2c.4", mux_pllp_clkm, CLK_SOURCE_I2C5, 47, &periph_h_regs, TEGRA_PERIPH_ON_APB, i2c5), | ||
| 1464 | TEGRA_INIT_DATA_UART("uarta", NULL, "tegra_uart.0", mux_pllpcm_clkm, CLK_SOURCE_UARTA, 6, &periph_l_regs, uarta), | ||
| 1465 | TEGRA_INIT_DATA_UART("uartb", NULL, "tegra_uart.1", mux_pllpcm_clkm, CLK_SOURCE_UARTB, 7, &periph_l_regs, uartb), | ||
| 1466 | TEGRA_INIT_DATA_UART("uartc", NULL, "tegra_uart.2", mux_pllpcm_clkm, CLK_SOURCE_UARTC, 55, &periph_h_regs, uartc), | ||
| 1467 | TEGRA_INIT_DATA_UART("uartd", NULL, "tegra_uart.3", mux_pllpcm_clkm, CLK_SOURCE_UARTD, 65, &periph_u_regs, uartd), | ||
| 1468 | TEGRA_INIT_DATA_UART("uarte", NULL, "tegra_uart.4", mux_pllpcm_clkm, CLK_SOURCE_UARTE, 66, &periph_u_regs, uarte), | ||
| 1469 | TEGRA_INIT_DATA_MUX8("hdmi", NULL, "hdmi", mux_pllpmdacd2_clkm, CLK_SOURCE_HDMI, 51, &periph_h_regs, 0, hdmi), | ||
| 1470 | TEGRA_INIT_DATA_MUX8("extern1", NULL, "extern1", mux_plla_clk32k_pllp_clkm_plle, CLK_SOURCE_EXTERN1, 120, &periph_v_regs, 0, extern1), | ||
| 1471 | TEGRA_INIT_DATA_MUX8("extern2", NULL, "extern2", mux_plla_clk32k_pllp_clkm_plle, CLK_SOURCE_EXTERN2, 121, &periph_v_regs, 0, extern2), | ||
| 1472 | TEGRA_INIT_DATA_MUX8("extern3", NULL, "extern3", mux_plla_clk32k_pllp_clkm_plle, CLK_SOURCE_EXTERN3, 122, &periph_v_regs, 0, extern3), | ||
| 1473 | TEGRA_INIT_DATA("pwm", NULL, "pwm", mux_pllpc_clk32k_clkm, CLK_SOURCE_PWM, 28, 2, 0, 0, 8, 1, 0, &periph_l_regs, 17, periph_clk_enb_refcnt, 0, pwm), | ||
| 1474 | }; | ||
| 1475 | |||
| 1476 | static struct tegra_periph_init_data tegra_periph_nodiv_clk_list[] = { | ||
| 1477 | TEGRA_INIT_DATA_NODIV("disp1", NULL, "tegradc.0", mux_pllpmdacd2_clkm, CLK_SOURCE_DISP1, 29, 3, 27, &periph_l_regs, 0, disp1), | ||
| 1478 | TEGRA_INIT_DATA_NODIV("disp2", NULL, "tegradc.1", mux_pllpmdacd2_clkm, CLK_SOURCE_DISP2, 29, 3, 26, &periph_l_regs, 0, disp2), | ||
| 1479 | TEGRA_INIT_DATA_NODIV("dsib", NULL, "tegradc.1", mux_plld_out0_plld2_out0, CLK_SOURCE_DSIB, 25, 1, 82, &periph_u_regs, 0, dsib), | ||
| 1480 | }; | ||
| 1481 | |||
| 1482 | static void __init tegra30_periph_clk_init(void) | ||
| 1483 | { | ||
| 1484 | struct tegra_periph_init_data *data; | ||
| 1485 | struct clk *clk; | ||
| 1486 | int i; | ||
| 1487 | |||
| 1488 | /* apbdma */ | ||
| 1489 | clk = tegra_clk_register_periph_gate("apbdma", "clk_m", 0, clk_base, 0, 34, | ||
| 1490 | &periph_h_regs, periph_clk_enb_refcnt); | ||
| 1491 | clk_register_clkdev(clk, NULL, "tegra-apbdma"); | ||
| 1492 | clks[apbdma] = clk; | ||
| 1493 | |||
| 1494 | /* rtc */ | ||
| 1495 | clk = tegra_clk_register_periph_gate("rtc", "clk_32k", | ||
| 1496 | TEGRA_PERIPH_NO_RESET | TEGRA_PERIPH_ON_APB, | ||
| 1497 | clk_base, 0, 4, &periph_l_regs, | ||
| 1498 | periph_clk_enb_refcnt); | ||
| 1499 | clk_register_clkdev(clk, NULL, "rtc-tegra"); | ||
| 1500 | clks[rtc] = clk; | ||
| 1501 | |||
| 1502 | /* timer */ | ||
| 1503 | clk = tegra_clk_register_periph_gate("timer", "clk_m", 0, clk_base, 0, | ||
| 1504 | 5, &periph_l_regs, periph_clk_enb_refcnt); | ||
| 1505 | clk_register_clkdev(clk, NULL, "timer"); | ||
| 1506 | clks[timer] = clk; | ||
| 1507 | |||
| 1508 | /* kbc */ | ||
| 1509 | clk = tegra_clk_register_periph_gate("kbc", "clk_32k", | ||
| 1510 | TEGRA_PERIPH_NO_RESET | TEGRA_PERIPH_ON_APB, | ||
| 1511 | clk_base, 0, 36, &periph_h_regs, | ||
| 1512 | periph_clk_enb_refcnt); | ||
| 1513 | clk_register_clkdev(clk, NULL, "tegra-kbc"); | ||
| 1514 | clks[kbc] = clk; | ||
| 1515 | |||
| 1516 | /* csus */ | ||
| 1517 | clk = tegra_clk_register_periph_gate("csus", "clk_m", | ||
| 1518 | TEGRA_PERIPH_NO_RESET | TEGRA_PERIPH_ON_APB, | ||
| 1519 | clk_base, 0, 92, &periph_u_regs, | ||
| 1520 | periph_clk_enb_refcnt); | ||
| 1521 | clk_register_clkdev(clk, "csus", "tengra_camera"); | ||
| 1522 | clks[csus] = clk; | ||
| 1523 | |||
| 1524 | /* vcp */ | ||
| 1525 | clk = tegra_clk_register_periph_gate("vcp", "clk_m", 0, clk_base, 0, 29, | ||
| 1526 | &periph_l_regs, periph_clk_enb_refcnt); | ||
| 1527 | clk_register_clkdev(clk, "vcp", "tegra-avp"); | ||
| 1528 | clks[vcp] = clk; | ||
| 1529 | |||
| 1530 | /* bsea */ | ||
| 1531 | clk = tegra_clk_register_periph_gate("bsea", "clk_m", 0, clk_base, 0, | ||
| 1532 | 62, &periph_h_regs, periph_clk_enb_refcnt); | ||
| 1533 | clk_register_clkdev(clk, "bsea", "tegra-avp"); | ||
| 1534 | clks[bsea] = clk; | ||
| 1535 | |||
| 1536 | /* bsev */ | ||
| 1537 | clk = tegra_clk_register_periph_gate("bsev", "clk_m", 0, clk_base, 0, | ||
| 1538 | 63, &periph_h_regs, periph_clk_enb_refcnt); | ||
| 1539 | clk_register_clkdev(clk, "bsev", "tegra-aes"); | ||
| 1540 | clks[bsev] = clk; | ||
| 1541 | |||
| 1542 | /* usbd */ | ||
| 1543 | clk = tegra_clk_register_periph_gate("usbd", "clk_m", 0, clk_base, 0, | ||
| 1544 | 22, &periph_l_regs, periph_clk_enb_refcnt); | ||
| 1545 | clk_register_clkdev(clk, NULL, "fsl-tegra-udc"); | ||
| 1546 | clks[usbd] = clk; | ||
| 1547 | |||
| 1548 | /* usb2 */ | ||
| 1549 | clk = tegra_clk_register_periph_gate("usb2", "clk_m", 0, clk_base, 0, | ||
| 1550 | 58, &periph_h_regs, periph_clk_enb_refcnt); | ||
| 1551 | clk_register_clkdev(clk, NULL, "tegra-ehci.1"); | ||
| 1552 | clks[usb2] = clk; | ||
| 1553 | |||
| 1554 | /* usb3 */ | ||
| 1555 | clk = tegra_clk_register_periph_gate("usb3", "clk_m", 0, clk_base, 0, | ||
| 1556 | 59, &periph_h_regs, periph_clk_enb_refcnt); | ||
| 1557 | clk_register_clkdev(clk, NULL, "tegra-ehci.2"); | ||
| 1558 | clks[usb3] = clk; | ||
| 1559 | |||
| 1560 | /* dsia */ | ||
| 1561 | clk = tegra_clk_register_periph_gate("dsia", "pll_d_out0", 0, clk_base, | ||
| 1562 | 0, 48, &periph_h_regs, | ||
| 1563 | periph_clk_enb_refcnt); | ||
| 1564 | clk_register_clkdev(clk, "dsia", "tegradc.0"); | ||
| 1565 | clks[dsia] = clk; | ||
| 1566 | |||
| 1567 | /* csi */ | ||
| 1568 | clk = tegra_clk_register_periph_gate("csi", "pll_p_out3", 0, clk_base, | ||
| 1569 | 0, 52, &periph_h_regs, | ||
| 1570 | periph_clk_enb_refcnt); | ||
| 1571 | clk_register_clkdev(clk, "csi", "tegra_camera"); | ||
| 1572 | clks[csi] = clk; | ||
| 1573 | |||
| 1574 | /* isp */ | ||
| 1575 | clk = tegra_clk_register_periph_gate("isp", "clk_m", 0, clk_base, 0, 23, | ||
| 1576 | &periph_l_regs, periph_clk_enb_refcnt); | ||
| 1577 | clk_register_clkdev(clk, "isp", "tegra_camera"); | ||
| 1578 | clks[isp] = clk; | ||
| 1579 | |||
| 1580 | /* pcie */ | ||
| 1581 | clk = tegra_clk_register_periph_gate("pcie", "clk_m", 0, clk_base, 0, | ||
| 1582 | 70, &periph_u_regs, periph_clk_enb_refcnt); | ||
| 1583 | clk_register_clkdev(clk, "pcie", "tegra-pcie"); | ||
| 1584 | clks[pcie] = clk; | ||
| 1585 | |||
| 1586 | /* afi */ | ||
| 1587 | clk = tegra_clk_register_periph_gate("afi", "clk_m", 0, clk_base, 0, 72, | ||
| 1588 | &periph_u_regs, periph_clk_enb_refcnt); | ||
| 1589 | clk_register_clkdev(clk, "afi", "tegra-pcie"); | ||
| 1590 | clks[afi] = clk; | ||
| 1591 | |||
| 1592 | /* kfuse */ | ||
| 1593 | clk = tegra_clk_register_periph_gate("kfuse", "clk_m", | ||
| 1594 | TEGRA_PERIPH_ON_APB, | ||
| 1595 | clk_base, 0, 40, &periph_h_regs, | ||
| 1596 | periph_clk_enb_refcnt); | ||
| 1597 | clk_register_clkdev(clk, NULL, "kfuse-tegra"); | ||
| 1598 | clks[kfuse] = clk; | ||
| 1599 | |||
| 1600 | /* fuse */ | ||
| 1601 | clk = tegra_clk_register_periph_gate("fuse", "clk_m", | ||
| 1602 | TEGRA_PERIPH_ON_APB, | ||
| 1603 | clk_base, 0, 39, &periph_h_regs, | ||
| 1604 | periph_clk_enb_refcnt); | ||
| 1605 | clk_register_clkdev(clk, "fuse", "fuse-tegra"); | ||
| 1606 | clks[fuse] = clk; | ||
| 1607 | |||
| 1608 | /* fuse_burn */ | ||
| 1609 | clk = tegra_clk_register_periph_gate("fuse_burn", "clk_m", | ||
| 1610 | TEGRA_PERIPH_ON_APB, | ||
| 1611 | clk_base, 0, 39, &periph_h_regs, | ||
| 1612 | periph_clk_enb_refcnt); | ||
| 1613 | clk_register_clkdev(clk, "fuse_burn", "fuse-tegra"); | ||
| 1614 | clks[fuse_burn] = clk; | ||
| 1615 | |||
| 1616 | /* apbif */ | ||
| 1617 | clk = tegra_clk_register_periph_gate("apbif", "clk_m", 0, | ||
| 1618 | clk_base, 0, 107, &periph_v_regs, | ||
| 1619 | periph_clk_enb_refcnt); | ||
| 1620 | clk_register_clkdev(clk, "apbif", "tegra30-ahub"); | ||
| 1621 | clks[apbif] = clk; | ||
| 1622 | |||
| 1623 | /* hda2hdmi */ | ||
| 1624 | clk = tegra_clk_register_periph_gate("hda2hdmi", "clk_m", | ||
| 1625 | TEGRA_PERIPH_ON_APB, | ||
| 1626 | clk_base, 0, 128, &periph_w_regs, | ||
| 1627 | periph_clk_enb_refcnt); | ||
| 1628 | clk_register_clkdev(clk, "hda2hdmi", "tegra30-hda"); | ||
| 1629 | clks[hda2hdmi] = clk; | ||
| 1630 | |||
| 1631 | /* sata_cold */ | ||
| 1632 | clk = tegra_clk_register_periph_gate("sata_cold", "clk_m", | ||
| 1633 | TEGRA_PERIPH_ON_APB, | ||
| 1634 | clk_base, 0, 129, &periph_w_regs, | ||
| 1635 | periph_clk_enb_refcnt); | ||
| 1636 | clk_register_clkdev(clk, NULL, "tegra_sata_cold"); | ||
| 1637 | clks[sata_cold] = clk; | ||
| 1638 | |||
| 1639 | /* dtv */ | ||
| 1640 | clk = tegra_clk_register_periph_gate("dtv", "clk_m", | ||
| 1641 | TEGRA_PERIPH_ON_APB, | ||
| 1642 | clk_base, 0, 79, &periph_u_regs, | ||
| 1643 | periph_clk_enb_refcnt); | ||
| 1644 | clk_register_clkdev(clk, NULL, "dtv"); | ||
| 1645 | clks[dtv] = clk; | ||
| 1646 | |||
| 1647 | /* emc */ | ||
| 1648 | clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm, | ||
| 1649 | ARRAY_SIZE(mux_pllmcp_clkm), 0, | ||
| 1650 | clk_base + CLK_SOURCE_EMC, | ||
| 1651 | 30, 2, 0, NULL); | ||
| 1652 | clk = tegra_clk_register_periph_gate("emc", "emc_mux", 0, clk_base, 0, | ||
| 1653 | 57, &periph_h_regs, periph_clk_enb_refcnt); | ||
| 1654 | clk_register_clkdev(clk, "emc", NULL); | ||
| 1655 | clks[emc] = clk; | ||
| 1656 | |||
| 1657 | for (i = 0; i < ARRAY_SIZE(tegra_periph_clk_list); i++) { | ||
| 1658 | data = &tegra_periph_clk_list[i]; | ||
| 1659 | clk = tegra_clk_register_periph(data->name, data->parent_names, | ||
| 1660 | data->num_parents, &data->periph, | ||
| 1661 | clk_base, data->offset); | ||
| 1662 | clk_register_clkdev(clk, data->con_id, data->dev_id); | ||
| 1663 | clks[data->clk_id] = clk; | ||
| 1664 | } | ||
| 1665 | |||
| 1666 | for (i = 0; i < ARRAY_SIZE(tegra_periph_nodiv_clk_list); i++) { | ||
| 1667 | data = &tegra_periph_nodiv_clk_list[i]; | ||
| 1668 | clk = tegra_clk_register_periph_nodiv(data->name, | ||
| 1669 | data->parent_names, | ||
| 1670 | data->num_parents, &data->periph, | ||
| 1671 | clk_base, data->offset); | ||
| 1672 | clk_register_clkdev(clk, data->con_id, data->dev_id); | ||
| 1673 | clks[data->clk_id] = clk; | ||
| 1674 | } | ||
| 1675 | } | ||
| 1676 | |||
| 1677 | static void __init tegra30_fixed_clk_init(void) | ||
| 1678 | { | ||
| 1679 | struct clk *clk; | ||
| 1680 | |||
| 1681 | /* clk_32k */ | ||
| 1682 | clk = clk_register_fixed_rate(NULL, "clk_32k", NULL, CLK_IS_ROOT, | ||
| 1683 | 32768); | ||
| 1684 | clk_register_clkdev(clk, "clk_32k", NULL); | ||
| 1685 | clks[clk_32k] = clk; | ||
| 1686 | |||
| 1687 | /* clk_m_div2 */ | ||
| 1688 | clk = clk_register_fixed_factor(NULL, "clk_m_div2", "clk_m", | ||
| 1689 | CLK_SET_RATE_PARENT, 1, 2); | ||
| 1690 | clk_register_clkdev(clk, "clk_m_div2", NULL); | ||
| 1691 | clks[clk_m_div2] = clk; | ||
| 1692 | |||
| 1693 | /* clk_m_div4 */ | ||
| 1694 | clk = clk_register_fixed_factor(NULL, "clk_m_div4", "clk_m", | ||
| 1695 | CLK_SET_RATE_PARENT, 1, 4); | ||
| 1696 | clk_register_clkdev(clk, "clk_m_div4", NULL); | ||
| 1697 | clks[clk_m_div4] = clk; | ||
| 1698 | |||
| 1699 | /* cml0 */ | ||
| 1700 | clk = clk_register_gate(NULL, "cml0", "pll_e", 0, clk_base + PLLE_AUX, | ||
| 1701 | 0, 0, &cml_lock); | ||
| 1702 | clk_register_clkdev(clk, "cml0", NULL); | ||
| 1703 | clks[cml0] = clk; | ||
| 1704 | |||
| 1705 | /* cml1 */ | ||
| 1706 | clk = clk_register_gate(NULL, "cml1", "pll_e", 0, clk_base + PLLE_AUX, | ||
| 1707 | 1, 0, &cml_lock); | ||
| 1708 | clk_register_clkdev(clk, "cml1", NULL); | ||
| 1709 | clks[cml1] = clk; | ||
| 1710 | |||
| 1711 | /* pciex */ | ||
| 1712 | clk = clk_register_fixed_rate(NULL, "pciex", "pll_e", 0, 100000000); | ||
| 1713 | clk_register_clkdev(clk, "pciex", NULL); | ||
| 1714 | clks[pciex] = clk; | ||
| 1715 | } | ||
| 1716 | |||
| 1717 | static void __init tegra30_osc_clk_init(void) | ||
| 1718 | { | ||
| 1719 | struct clk *clk; | ||
| 1720 | unsigned int pll_ref_div; | ||
| 1721 | |||
| 1722 | tegra30_clk_measure_input_freq(); | ||
| 1723 | |||
| 1724 | /* clk_m */ | ||
| 1725 | clk = clk_register_fixed_rate(NULL, "clk_m", NULL, CLK_IS_ROOT, | ||
| 1726 | input_freq); | ||
| 1727 | clk_register_clkdev(clk, "clk_m", NULL); | ||
| 1728 | clks[clk_m] = clk; | ||
| 1729 | |||
| 1730 | /* pll_ref */ | ||
| 1731 | pll_ref_div = tegra30_get_pll_ref_div(); | ||
| 1732 | clk = clk_register_fixed_factor(NULL, "pll_ref", "clk_m", | ||
| 1733 | CLK_SET_RATE_PARENT, 1, pll_ref_div); | ||
| 1734 | clk_register_clkdev(clk, "pll_ref", NULL); | ||
| 1735 | clks[pll_ref] = clk; | ||
| 1736 | } | ||
| 1737 | |||
| 1738 | /* Tegra30 CPU clock and reset control functions */ | ||
| 1739 | static void tegra30_wait_cpu_in_reset(u32 cpu) | ||
| 1740 | { | ||
| 1741 | unsigned int reg; | ||
| 1742 | |||
| 1743 | do { | ||
| 1744 | reg = readl(clk_base + | ||
| 1745 | TEGRA30_CLK_RST_CONTROLLER_CPU_CMPLX_STATUS); | ||
| 1746 | cpu_relax(); | ||
| 1747 | } while (!(reg & (1 << cpu))); /* check CPU been reset or not */ | ||
| 1748 | |||
| 1749 | return; | ||
| 1750 | } | ||
| 1751 | |||
| 1752 | static void tegra30_put_cpu_in_reset(u32 cpu) | ||
| 1753 | { | ||
| 1754 | writel(CPU_RESET(cpu), | ||
| 1755 | clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET); | ||
| 1756 | dmb(); | ||
| 1757 | } | ||
| 1758 | |||
| 1759 | static void tegra30_cpu_out_of_reset(u32 cpu) | ||
| 1760 | { | ||
| 1761 | writel(CPU_RESET(cpu), | ||
| 1762 | clk_base + TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR); | ||
| 1763 | wmb(); | ||
| 1764 | } | ||
| 1765 | |||
| 1766 | |||
| 1767 | static void tegra30_enable_cpu_clock(u32 cpu) | ||
| 1768 | { | ||
| 1769 | unsigned int reg; | ||
| 1770 | |||
| 1771 | writel(CPU_CLOCK(cpu), | ||
| 1772 | clk_base + TEGRA30_CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR); | ||
| 1773 | reg = readl(clk_base + | ||
| 1774 | TEGRA30_CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR); | ||
| 1775 | } | ||
| 1776 | |||
| 1777 | static void tegra30_disable_cpu_clock(u32 cpu) | ||
| 1778 | { | ||
| 1779 | |||
| 1780 | unsigned int reg; | ||
| 1781 | |||
| 1782 | reg = readl(clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); | ||
| 1783 | writel(reg | CPU_CLOCK(cpu), | ||
| 1784 | clk_base + TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX); | ||
| 1785 | } | ||
| 1786 | |||
| 1787 | #ifdef CONFIG_PM_SLEEP | ||
| 1788 | static bool tegra30_cpu_rail_off_ready(void) | ||
| 1789 | { | ||
| 1790 | unsigned int cpu_rst_status; | ||
| 1791 | int cpu_pwr_status; | ||
| 1792 | |||
| 1793 | cpu_rst_status = readl(clk_base + | ||
| 1794 | TEGRA30_CLK_RST_CONTROLLER_CPU_CMPLX_STATUS); | ||
| 1795 | cpu_pwr_status = tegra_powergate_is_powered(TEGRA_POWERGATE_CPU1) || | ||
| 1796 | tegra_powergate_is_powered(TEGRA_POWERGATE_CPU2) || | ||
| 1797 | tegra_powergate_is_powered(TEGRA_POWERGATE_CPU3); | ||
| 1798 | |||
| 1799 | if (((cpu_rst_status & 0xE) != 0xE) || cpu_pwr_status) | ||
| 1800 | return false; | ||
| 1801 | |||
| 1802 | return true; | ||
| 1803 | } | ||
| 1804 | |||
| 1805 | static void tegra30_cpu_clock_suspend(void) | ||
| 1806 | { | ||
| 1807 | /* switch coresite to clk_m, save off original source */ | ||
| 1808 | tegra30_cpu_clk_sctx.clk_csite_src = | ||
| 1809 | readl(clk_base + CLK_RESET_SOURCE_CSITE); | ||
| 1810 | writel(3<<30, clk_base + CLK_RESET_SOURCE_CSITE); | ||
| 1811 | |||
| 1812 | tegra30_cpu_clk_sctx.cpu_burst = | ||
| 1813 | readl(clk_base + CLK_RESET_CCLK_BURST); | ||
| 1814 | tegra30_cpu_clk_sctx.pllx_base = | ||
| 1815 | readl(clk_base + CLK_RESET_PLLX_BASE); | ||
| 1816 | tegra30_cpu_clk_sctx.pllx_misc = | ||
| 1817 | readl(clk_base + CLK_RESET_PLLX_MISC); | ||
| 1818 | tegra30_cpu_clk_sctx.cclk_divider = | ||
| 1819 | readl(clk_base + CLK_RESET_CCLK_DIVIDER); | ||
| 1820 | } | ||
| 1821 | |||
| 1822 | static void tegra30_cpu_clock_resume(void) | ||
| 1823 | { | ||
| 1824 | unsigned int reg, policy; | ||
| 1825 | |||
| 1826 | /* Is CPU complex already running on PLLX? */ | ||
| 1827 | reg = readl(clk_base + CLK_RESET_CCLK_BURST); | ||
| 1828 | policy = (reg >> CLK_RESET_CCLK_BURST_POLICY_SHIFT) & 0xF; | ||
| 1829 | |||
| 1830 | if (policy == CLK_RESET_CCLK_IDLE_POLICY) | ||
| 1831 | reg = (reg >> CLK_RESET_CCLK_IDLE_POLICY_SHIFT) & 0xF; | ||
| 1832 | else if (policy == CLK_RESET_CCLK_RUN_POLICY) | ||
| 1833 | reg = (reg >> CLK_RESET_CCLK_RUN_POLICY_SHIFT) & 0xF; | ||
| 1834 | else | ||
| 1835 | BUG(); | ||
| 1836 | |||
| 1837 | if (reg != CLK_RESET_CCLK_BURST_POLICY_PLLX) { | ||
| 1838 | /* restore PLLX settings if CPU is on different PLL */ | ||
| 1839 | writel(tegra30_cpu_clk_sctx.pllx_misc, | ||
| 1840 | clk_base + CLK_RESET_PLLX_MISC); | ||
| 1841 | writel(tegra30_cpu_clk_sctx.pllx_base, | ||
| 1842 | clk_base + CLK_RESET_PLLX_BASE); | ||
| 1843 | |||
| 1844 | /* wait for PLL stabilization if PLLX was enabled */ | ||
| 1845 | if (tegra30_cpu_clk_sctx.pllx_base & (1 << 30)) | ||
| 1846 | udelay(300); | ||
| 1847 | } | ||
| 1848 | |||
| 1849 | /* | ||
| 1850 | * Restore original burst policy setting for calls resulting from CPU | ||
| 1851 | * LP2 in idle or system suspend. | ||
| 1852 | */ | ||
| 1853 | writel(tegra30_cpu_clk_sctx.cclk_divider, | ||
| 1854 | clk_base + CLK_RESET_CCLK_DIVIDER); | ||
| 1855 | writel(tegra30_cpu_clk_sctx.cpu_burst, | ||
| 1856 | clk_base + CLK_RESET_CCLK_BURST); | ||
| 1857 | |||
| 1858 | writel(tegra30_cpu_clk_sctx.clk_csite_src, | ||
| 1859 | clk_base + CLK_RESET_SOURCE_CSITE); | ||
| 1860 | } | ||
| 1861 | #endif | ||
| 1862 | |||
| 1863 | static struct tegra_cpu_car_ops tegra30_cpu_car_ops = { | ||
| 1864 | .wait_for_reset = tegra30_wait_cpu_in_reset, | ||
| 1865 | .put_in_reset = tegra30_put_cpu_in_reset, | ||
| 1866 | .out_of_reset = tegra30_cpu_out_of_reset, | ||
| 1867 | .enable_clock = tegra30_enable_cpu_clock, | ||
| 1868 | .disable_clock = tegra30_disable_cpu_clock, | ||
| 1869 | #ifdef CONFIG_PM_SLEEP | ||
| 1870 | .rail_off_ready = tegra30_cpu_rail_off_ready, | ||
| 1871 | .suspend = tegra30_cpu_clock_suspend, | ||
| 1872 | .resume = tegra30_cpu_clock_resume, | ||
| 1873 | #endif | ||
| 1874 | }; | ||
| 1875 | |||
| 1876 | static __initdata struct tegra_clk_init_table init_table[] = { | ||
| 1877 | {uarta, pll_p, 408000000, 1}, | ||
| 1878 | {pll_a, clk_max, 564480000, 1}, | ||
| 1879 | {pll_a_out0, clk_max, 11289600, 1}, | ||
| 1880 | {extern1, pll_a_out0, 0, 1}, | ||
| 1881 | {clk_out_1_mux, extern1, 0, 0}, | ||
| 1882 | {clk_out_1, clk_max, 0, 1}, | ||
| 1883 | {blink, clk_max, 0, 1}, | ||
| 1884 | {i2s0, pll_a_out0, 11289600, 0}, | ||
| 1885 | {i2s1, pll_a_out0, 11289600, 0}, | ||
| 1886 | {i2s2, pll_a_out0, 11289600, 0}, | ||
| 1887 | {i2s3, pll_a_out0, 11289600, 0}, | ||
| 1888 | {i2s4, pll_a_out0, 11289600, 0}, | ||
| 1889 | {sdmmc1, pll_p, 48000000, 0}, | ||
| 1890 | {sdmmc2, pll_p, 48000000, 0}, | ||
| 1891 | {sdmmc3, pll_p, 48000000, 0}, | ||
| 1892 | {pll_m, clk_max, 0, 1}, | ||
| 1893 | {pclk, clk_max, 0, 1}, | ||
| 1894 | {csite, clk_max, 0, 1}, | ||
| 1895 | {emc, clk_max, 0, 1}, | ||
| 1896 | {mselect, clk_max, 0, 1}, | ||
| 1897 | {sbc1, pll_p, 100000000, 0}, | ||
| 1898 | {sbc2, pll_p, 100000000, 0}, | ||
| 1899 | {sbc3, pll_p, 100000000, 0}, | ||
| 1900 | {sbc4, pll_p, 100000000, 0}, | ||
| 1901 | {sbc5, pll_p, 100000000, 0}, | ||
| 1902 | {sbc6, pll_p, 100000000, 0}, | ||
| 1903 | {host1x, pll_c, 150000000, 0}, | ||
| 1904 | {disp1, pll_p, 600000000, 0}, | ||
| 1905 | {disp2, pll_p, 600000000, 0}, | ||
| 1906 | {twd, clk_max, 0, 1}, | ||
| 1907 | {clk_max, clk_max, 0, 0}, /* This MUST be the last entry. */ | ||
| 1908 | }; | ||
| 1909 | |||
| 1910 | /* | ||
| 1911 | * Some clocks may be used by different drivers depending on the board | ||
| 1912 | * configuration. List those here to register them twice in the clock lookup | ||
| 1913 | * table under two names. | ||
| 1914 | */ | ||
| 1915 | static struct tegra_clk_duplicate tegra_clk_duplicates[] = { | ||
| 1916 | TEGRA_CLK_DUPLICATE(usbd, "utmip-pad", NULL), | ||
| 1917 | TEGRA_CLK_DUPLICATE(usbd, "tegra-ehci.0", NULL), | ||
| 1918 | TEGRA_CLK_DUPLICATE(usbd, "tegra-otg", NULL), | ||
| 1919 | TEGRA_CLK_DUPLICATE(bsev, "tegra-avp", "bsev"), | ||
| 1920 | TEGRA_CLK_DUPLICATE(bsev, "nvavp", "bsev"), | ||
| 1921 | TEGRA_CLK_DUPLICATE(vde, "tegra-aes", "vde"), | ||
| 1922 | TEGRA_CLK_DUPLICATE(bsea, "tegra-aes", "bsea"), | ||
| 1923 | TEGRA_CLK_DUPLICATE(bsea, "nvavp", "bsea"), | ||
| 1924 | TEGRA_CLK_DUPLICATE(cml1, "tegra_sata_cml", NULL), | ||
| 1925 | TEGRA_CLK_DUPLICATE(cml0, "tegra_pcie", "cml"), | ||
| 1926 | TEGRA_CLK_DUPLICATE(pciex, "tegra_pcie", "pciex"), | ||
| 1927 | TEGRA_CLK_DUPLICATE(twd, "smp_twd", NULL), | ||
| 1928 | TEGRA_CLK_DUPLICATE(vcp, "nvavp", "vcp"), | ||
| 1929 | TEGRA_CLK_DUPLICATE(clk_max, NULL, NULL), /* MUST be the last entry */ | ||
| 1930 | }; | ||
| 1931 | |||
| 1932 | static const struct of_device_id pmc_match[] __initconst = { | ||
| 1933 | { .compatible = "nvidia,tegra30-pmc" }, | ||
| 1934 | {}, | ||
| 1935 | }; | ||
| 1936 | |||
| 1937 | void __init tegra30_clock_init(struct device_node *np) | ||
| 1938 | { | ||
| 1939 | struct device_node *node; | ||
| 1940 | int i; | ||
| 1941 | |||
| 1942 | clk_base = of_iomap(np, 0); | ||
| 1943 | if (!clk_base) { | ||
| 1944 | pr_err("ioremap tegra30 CAR failed\n"); | ||
| 1945 | return; | ||
| 1946 | } | ||
| 1947 | |||
| 1948 | node = of_find_matching_node(NULL, pmc_match); | ||
| 1949 | if (!node) { | ||
| 1950 | pr_err("Failed to find pmc node\n"); | ||
| 1951 | BUG(); | ||
| 1952 | } | ||
| 1953 | |||
| 1954 | pmc_base = of_iomap(node, 0); | ||
| 1955 | if (!pmc_base) { | ||
| 1956 | pr_err("Can't map pmc registers\n"); | ||
| 1957 | BUG(); | ||
| 1958 | } | ||
| 1959 | |||
| 1960 | tegra30_osc_clk_init(); | ||
| 1961 | tegra30_fixed_clk_init(); | ||
| 1962 | tegra30_pll_init(); | ||
| 1963 | tegra30_super_clk_init(); | ||
| 1964 | tegra30_periph_clk_init(); | ||
| 1965 | tegra30_audio_clk_init(); | ||
| 1966 | tegra30_pmc_clk_init(); | ||
| 1967 | |||
| 1968 | for (i = 0; i < ARRAY_SIZE(clks); i++) { | ||
| 1969 | if (IS_ERR(clks[i])) { | ||
| 1970 | pr_err("Tegra30 clk %d: register failed with %ld\n", | ||
| 1971 | i, PTR_ERR(clks[i])); | ||
| 1972 | BUG(); | ||
| 1973 | } | ||
| 1974 | if (!clks[i]) | ||
| 1975 | clks[i] = ERR_PTR(-EINVAL); | ||
| 1976 | } | ||
| 1977 | |||
| 1978 | tegra_init_dup_clks(tegra_clk_duplicates, clks, clk_max); | ||
| 1979 | |||
| 1980 | clk_data.clks = clks; | ||
| 1981 | clk_data.clk_num = ARRAY_SIZE(clks); | ||
| 1982 | of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); | ||
| 1983 | |||
| 1984 | tegra_init_from_table(init_table, clks, clk_max); | ||
| 1985 | |||
| 1986 | tegra_cpu_car_ops = &tegra30_cpu_car_ops; | ||
| 1987 | } | ||
diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c new file mode 100644 index 000000000000..a603b9af0ad3 --- /dev/null +++ b/drivers/clk/tegra/clk.c | |||
| @@ -0,0 +1,85 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/clk.h> | ||
| 18 | #include <linux/clk-provider.h> | ||
| 19 | #include <linux/of.h> | ||
| 20 | #include <linux/clk/tegra.h> | ||
| 21 | |||
| 22 | #include "clk.h" | ||
| 23 | |||
| 24 | /* Global data of Tegra CPU CAR ops */ | ||
| 25 | struct tegra_cpu_car_ops *tegra_cpu_car_ops; | ||
| 26 | |||
| 27 | void __init tegra_init_dup_clks(struct tegra_clk_duplicate *dup_list, | ||
| 28 | struct clk *clks[], int clk_max) | ||
| 29 | { | ||
| 30 | struct clk *clk; | ||
| 31 | |||
| 32 | for (; dup_list->clk_id < clk_max; dup_list++) { | ||
| 33 | clk = clks[dup_list->clk_id]; | ||
| 34 | dup_list->lookup.clk = clk; | ||
| 35 | clkdev_add(&dup_list->lookup); | ||
| 36 | } | ||
| 37 | } | ||
| 38 | |||
| 39 | void __init tegra_init_from_table(struct tegra_clk_init_table *tbl, | ||
| 40 | struct clk *clks[], int clk_max) | ||
| 41 | { | ||
| 42 | struct clk *clk; | ||
| 43 | |||
| 44 | for (; tbl->clk_id < clk_max; tbl++) { | ||
| 45 | clk = clks[tbl->clk_id]; | ||
| 46 | if (IS_ERR_OR_NULL(clk)) | ||
| 47 | return; | ||
| 48 | |||
| 49 | if (tbl->parent_id < clk_max) { | ||
| 50 | struct clk *parent = clks[tbl->parent_id]; | ||
| 51 | if (clk_set_parent(clk, parent)) { | ||
| 52 | pr_err("%s: Failed to set parent %s of %s\n", | ||
| 53 | __func__, __clk_get_name(parent), | ||
| 54 | __clk_get_name(clk)); | ||
| 55 | WARN_ON(1); | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | if (tbl->rate) | ||
| 60 | if (clk_set_rate(clk, tbl->rate)) { | ||
| 61 | pr_err("%s: Failed to set rate %lu of %s\n", | ||
| 62 | __func__, tbl->rate, | ||
| 63 | __clk_get_name(clk)); | ||
| 64 | WARN_ON(1); | ||
| 65 | } | ||
| 66 | |||
| 67 | if (tbl->state) | ||
| 68 | if (clk_prepare_enable(clk)) { | ||
| 69 | pr_err("%s: Failed to enable %s\n", __func__, | ||
| 70 | __clk_get_name(clk)); | ||
| 71 | WARN_ON(1); | ||
| 72 | } | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | static const struct of_device_id tegra_dt_clk_match[] = { | ||
| 77 | { .compatible = "nvidia,tegra20-car", .data = tegra20_clock_init }, | ||
| 78 | { .compatible = "nvidia,tegra30-car", .data = tegra30_clock_init }, | ||
| 79 | { } | ||
| 80 | }; | ||
| 81 | |||
| 82 | void __init tegra_clocks_init(void) | ||
| 83 | { | ||
| 84 | of_clk_init(tegra_dt_clk_match); | ||
| 85 | } | ||
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h new file mode 100644 index 000000000000..0744731c6229 --- /dev/null +++ b/drivers/clk/tegra/clk.h | |||
| @@ -0,0 +1,502 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #ifndef __TEGRA_CLK_H | ||
| 18 | #define __TEGRA_CLK_H | ||
| 19 | |||
| 20 | #include <linux/clk-provider.h> | ||
| 21 | #include <linux/clkdev.h> | ||
| 22 | |||
| 23 | /** | ||
| 24 | * struct tegra_clk_sync_source - external clock source from codec | ||
| 25 | * | ||
| 26 | * @hw: handle between common and hardware-specific interfaces | ||
| 27 | * @rate: input frequency from source | ||
| 28 | * @max_rate: max rate allowed | ||
| 29 | */ | ||
| 30 | struct tegra_clk_sync_source { | ||
| 31 | struct clk_hw hw; | ||
| 32 | unsigned long rate; | ||
| 33 | unsigned long max_rate; | ||
| 34 | }; | ||
| 35 | |||
| 36 | #define to_clk_sync_source(_hw) \ | ||
| 37 | container_of(_hw, struct tegra_clk_sync_source, hw) | ||
| 38 | |||
| 39 | extern const struct clk_ops tegra_clk_sync_source_ops; | ||
| 40 | struct clk *tegra_clk_register_sync_source(const char *name, | ||
| 41 | unsigned long fixed_rate, unsigned long max_rate); | ||
| 42 | |||
| 43 | /** | ||
| 44 | * struct tegra_clk_frac_div - fractional divider clock | ||
| 45 | * | ||
| 46 | * @hw: handle between common and hardware-specific interfaces | ||
| 47 | * @reg: register containing divider | ||
| 48 | * @flags: hardware-specific flags | ||
| 49 | * @shift: shift to the divider bit field | ||
| 50 | * @width: width of the divider bit field | ||
| 51 | * @frac_width: width of the fractional bit field | ||
| 52 | * @lock: register lock | ||
| 53 | * | ||
| 54 | * Flags: | ||
| 55 | * TEGRA_DIVIDER_ROUND_UP - This flags indicates to round up the divider value. | ||
| 56 | * TEGRA_DIVIDER_FIXED - Fixed rate PLL dividers has addition override bit, this | ||
| 57 | * flag indicates that this divider is for fixed rate PLL. | ||
| 58 | * TEGRA_DIVIDER_INT - Some modules can not cope with the duty cycle when | ||
| 59 | * fraction bit is set. This flags indicates to calculate divider for which | ||
| 60 | * fracton bit will be zero. | ||
| 61 | * TEGRA_DIVIDER_UART - UART module divider has additional enable bit which is | ||
| 62 | * set when divider value is not 0. This flags indicates that the divider | ||
| 63 | * is for UART module. | ||
| 64 | */ | ||
| 65 | struct tegra_clk_frac_div { | ||
| 66 | struct clk_hw hw; | ||
| 67 | void __iomem *reg; | ||
| 68 | u8 flags; | ||
| 69 | u8 shift; | ||
| 70 | u8 width; | ||
| 71 | u8 frac_width; | ||
| 72 | spinlock_t *lock; | ||
| 73 | }; | ||
| 74 | |||
| 75 | #define to_clk_frac_div(_hw) container_of(_hw, struct tegra_clk_frac_div, hw) | ||
| 76 | |||
| 77 | #define TEGRA_DIVIDER_ROUND_UP BIT(0) | ||
| 78 | #define TEGRA_DIVIDER_FIXED BIT(1) | ||
| 79 | #define TEGRA_DIVIDER_INT BIT(2) | ||
| 80 | #define TEGRA_DIVIDER_UART BIT(3) | ||
| 81 | |||
| 82 | extern const struct clk_ops tegra_clk_frac_div_ops; | ||
| 83 | struct clk *tegra_clk_register_divider(const char *name, | ||
| 84 | const char *parent_name, void __iomem *reg, | ||
| 85 | unsigned long flags, u8 clk_divider_flags, u8 shift, u8 width, | ||
| 86 | u8 frac_width, spinlock_t *lock); | ||
| 87 | |||
| 88 | /* | ||
| 89 | * Tegra PLL: | ||
| 90 | * | ||
| 91 | * In general, there are 3 requirements for each PLL | ||
| 92 | * that SW needs to be comply with. | ||
| 93 | * (1) Input frequency range (REF). | ||
| 94 | * (2) Comparison frequency range (CF). CF = REF/DIVM. | ||
| 95 | * (3) VCO frequency range (VCO). VCO = CF * DIVN. | ||
| 96 | * | ||
| 97 | * The final PLL output frequency (FO) = VCO >> DIVP. | ||
| 98 | */ | ||
| 99 | |||
| 100 | /** | ||
| 101 | * struct tegra_clk_pll_freq_table - PLL frequecy table | ||
| 102 | * | ||
| 103 | * @input_rate: input rate from source | ||
| 104 | * @output_rate: output rate from PLL for the input rate | ||
| 105 | * @n: feedback divider | ||
| 106 | * @m: input divider | ||
| 107 | * @p: post divider | ||
| 108 | * @cpcon: charge pump current | ||
| 109 | */ | ||
| 110 | struct tegra_clk_pll_freq_table { | ||
| 111 | unsigned long input_rate; | ||
| 112 | unsigned long output_rate; | ||
| 113 | u16 n; | ||
| 114 | u16 m; | ||
| 115 | u8 p; | ||
| 116 | u8 cpcon; | ||
| 117 | }; | ||
| 118 | |||
| 119 | /** | ||
| 120 | * struct clk_pll_params - PLL parameters | ||
| 121 | * | ||
| 122 | * @input_min: Minimum input frequency | ||
| 123 | * @input_max: Maximum input frequency | ||
| 124 | * @cf_min: Minimum comparison frequency | ||
| 125 | * @cf_max: Maximum comparison frequency | ||
| 126 | * @vco_min: Minimum VCO frequency | ||
| 127 | * @vco_max: Maximum VCO frequency | ||
| 128 | * @base_reg: PLL base reg offset | ||
| 129 | * @misc_reg: PLL misc reg offset | ||
| 130 | * @lock_reg: PLL lock reg offset | ||
| 131 | * @lock_bit_idx: Bit index for PLL lock status | ||
| 132 | * @lock_enable_bit_idx: Bit index to enable PLL lock | ||
| 133 | * @lock_delay: Delay in us if PLL lock is not used | ||
| 134 | */ | ||
| 135 | struct tegra_clk_pll_params { | ||
| 136 | unsigned long input_min; | ||
| 137 | unsigned long input_max; | ||
| 138 | unsigned long cf_min; | ||
| 139 | unsigned long cf_max; | ||
| 140 | unsigned long vco_min; | ||
| 141 | unsigned long vco_max; | ||
| 142 | |||
| 143 | u32 base_reg; | ||
| 144 | u32 misc_reg; | ||
| 145 | u32 lock_reg; | ||
| 146 | u32 lock_bit_idx; | ||
| 147 | u32 lock_enable_bit_idx; | ||
| 148 | int lock_delay; | ||
| 149 | }; | ||
| 150 | |||
| 151 | /** | ||
| 152 | * struct tegra_clk_pll - Tegra PLL clock | ||
| 153 | * | ||
| 154 | * @hw: handle between common and hardware-specifix interfaces | ||
| 155 | * @clk_base: address of CAR controller | ||
| 156 | * @pmc: address of PMC, required to read override bits | ||
| 157 | * @freq_table: array of frequencies supported by PLL | ||
| 158 | * @params: PLL parameters | ||
| 159 | * @flags: PLL flags | ||
| 160 | * @fixed_rate: PLL rate if it is fixed | ||
| 161 | * @lock: register lock | ||
| 162 | * @divn_shift: shift to the feedback divider bit field | ||
| 163 | * @divn_width: width of the feedback divider bit field | ||
| 164 | * @divm_shift: shift to the input divider bit field | ||
| 165 | * @divm_width: width of the input divider bit field | ||
| 166 | * @divp_shift: shift to the post divider bit field | ||
| 167 | * @divp_width: width of the post divider bit field | ||
| 168 | * | ||
| 169 | * Flags: | ||
| 170 | * TEGRA_PLL_USE_LOCK - This flag indicated to use lock bits for | ||
| 171 | * PLL locking. If not set it will use lock_delay value to wait. | ||
| 172 | * TEGRA_PLL_HAS_CPCON - This flag indicates that CPCON value needs | ||
| 173 | * to be programmed to change output frequency of the PLL. | ||
| 174 | * TEGRA_PLL_SET_LFCON - This flag indicates that LFCON value needs | ||
| 175 | * to be programmed to change output frequency of the PLL. | ||
| 176 | * TEGRA_PLL_SET_DCCON - This flag indicates that DCCON value needs | ||
| 177 | * to be programmed to change output frequency of the PLL. | ||
| 178 | * TEGRA_PLLU - PLLU has inverted post divider. This flags indicated | ||
| 179 | * that it is PLLU and invert post divider value. | ||
| 180 | * TEGRA_PLLM - PLLM has additional override settings in PMC. This | ||
| 181 | * flag indicates that it is PLLM and use override settings. | ||
| 182 | * TEGRA_PLL_FIXED - We are not supposed to change output frequency | ||
| 183 | * of some plls. | ||
| 184 | * TEGRA_PLLE_CONFIGURE - Configure PLLE when enabling. | ||
| 185 | */ | ||
| 186 | struct tegra_clk_pll { | ||
| 187 | struct clk_hw hw; | ||
| 188 | void __iomem *clk_base; | ||
| 189 | void __iomem *pmc; | ||
| 190 | u8 flags; | ||
| 191 | unsigned long fixed_rate; | ||
| 192 | spinlock_t *lock; | ||
| 193 | u8 divn_shift; | ||
| 194 | u8 divn_width; | ||
| 195 | u8 divm_shift; | ||
| 196 | u8 divm_width; | ||
| 197 | u8 divp_shift; | ||
| 198 | u8 divp_width; | ||
| 199 | struct tegra_clk_pll_freq_table *freq_table; | ||
| 200 | struct tegra_clk_pll_params *params; | ||
| 201 | }; | ||
| 202 | |||
| 203 | #define to_clk_pll(_hw) container_of(_hw, struct tegra_clk_pll, hw) | ||
| 204 | |||
| 205 | #define TEGRA_PLL_USE_LOCK BIT(0) | ||
| 206 | #define TEGRA_PLL_HAS_CPCON BIT(1) | ||
| 207 | #define TEGRA_PLL_SET_LFCON BIT(2) | ||
| 208 | #define TEGRA_PLL_SET_DCCON BIT(3) | ||
| 209 | #define TEGRA_PLLU BIT(4) | ||
| 210 | #define TEGRA_PLLM BIT(5) | ||
| 211 | #define TEGRA_PLL_FIXED BIT(6) | ||
| 212 | #define TEGRA_PLLE_CONFIGURE BIT(7) | ||
| 213 | |||
| 214 | extern const struct clk_ops tegra_clk_pll_ops; | ||
| 215 | extern const struct clk_ops tegra_clk_plle_ops; | ||
| 216 | struct clk *tegra_clk_register_pll(const char *name, const char *parent_name, | ||
| 217 | void __iomem *clk_base, void __iomem *pmc, | ||
| 218 | unsigned long flags, unsigned long fixed_rate, | ||
| 219 | struct tegra_clk_pll_params *pll_params, u8 pll_flags, | ||
| 220 | struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock); | ||
| 221 | struct clk *tegra_clk_register_plle(const char *name, const char *parent_name, | ||
| 222 | void __iomem *clk_base, void __iomem *pmc, | ||
| 223 | unsigned long flags, unsigned long fixed_rate, | ||
| 224 | struct tegra_clk_pll_params *pll_params, u8 pll_flags, | ||
| 225 | struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock); | ||
| 226 | |||
| 227 | /** | ||
| 228 | * struct tegra_clk_pll_out - PLL divider down clock | ||
| 229 | * | ||
| 230 | * @hw: handle between common and hardware-specific interfaces | ||
| 231 | * @reg: register containing the PLL divider | ||
| 232 | * @enb_bit_idx: bit to enable/disable PLL divider | ||
| 233 | * @rst_bit_idx: bit to reset PLL divider | ||
| 234 | * @lock: register lock | ||
| 235 | * @flags: hardware-specific flags | ||
| 236 | */ | ||
| 237 | struct tegra_clk_pll_out { | ||
| 238 | struct clk_hw hw; | ||
| 239 | void __iomem *reg; | ||
| 240 | u8 enb_bit_idx; | ||
| 241 | u8 rst_bit_idx; | ||
| 242 | spinlock_t *lock; | ||
| 243 | u8 flags; | ||
| 244 | }; | ||
| 245 | |||
| 246 | #define to_clk_pll_out(_hw) container_of(_hw, struct tegra_clk_pll_out, hw) | ||
| 247 | |||
| 248 | extern const struct clk_ops tegra_clk_pll_out_ops; | ||
| 249 | struct clk *tegra_clk_register_pll_out(const char *name, | ||
| 250 | const char *parent_name, void __iomem *reg, u8 enb_bit_idx, | ||
| 251 | u8 rst_bit_idx, unsigned long flags, u8 pll_div_flags, | ||
| 252 | spinlock_t *lock); | ||
| 253 | |||
| 254 | /** | ||
| 255 | * struct tegra_clk_periph_regs - Registers controlling peripheral clock | ||
| 256 | * | ||
| 257 | * @enb_reg: read the enable status | ||
| 258 | * @enb_set_reg: write 1 to enable clock | ||
| 259 | * @enb_clr_reg: write 1 to disable clock | ||
| 260 | * @rst_reg: read the reset status | ||
| 261 | * @rst_set_reg: write 1 to assert the reset of peripheral | ||
| 262 | * @rst_clr_reg: write 1 to deassert the reset of peripheral | ||
| 263 | */ | ||
| 264 | struct tegra_clk_periph_regs { | ||
| 265 | u32 enb_reg; | ||
| 266 | u32 enb_set_reg; | ||
| 267 | u32 enb_clr_reg; | ||
| 268 | u32 rst_reg; | ||
| 269 | u32 rst_set_reg; | ||
| 270 | u32 rst_clr_reg; | ||
| 271 | }; | ||
| 272 | |||
| 273 | /** | ||
| 274 | * struct tegra_clk_periph_gate - peripheral gate clock | ||
| 275 | * | ||
| 276 | * @magic: magic number to validate type | ||
| 277 | * @hw: handle between common and hardware-specific interfaces | ||
| 278 | * @clk_base: address of CAR controller | ||
| 279 | * @regs: Registers to control the peripheral | ||
| 280 | * @flags: hardware-specific flags | ||
| 281 | * @clk_num: Clock number | ||
| 282 | * @enable_refcnt: array to maintain reference count of the clock | ||
| 283 | * | ||
| 284 | * Flags: | ||
| 285 | * TEGRA_PERIPH_NO_RESET - This flag indicates that reset is not allowed | ||
| 286 | * for this module. | ||
| 287 | * TEGRA_PERIPH_MANUAL_RESET - This flag indicates not to reset module | ||
| 288 | * after clock enable and driver for the module is responsible for | ||
| 289 | * doing reset. | ||
| 290 | * TEGRA_PERIPH_ON_APB - If peripheral is in the APB bus then read the | ||
| 291 | * bus to flush the write operation in apb bus. This flag indicates | ||
| 292 | * that this peripheral is in apb bus. | ||
| 293 | */ | ||
| 294 | struct tegra_clk_periph_gate { | ||
| 295 | u32 magic; | ||
| 296 | struct clk_hw hw; | ||
| 297 | void __iomem *clk_base; | ||
| 298 | u8 flags; | ||
| 299 | int clk_num; | ||
| 300 | int *enable_refcnt; | ||
| 301 | struct tegra_clk_periph_regs *regs; | ||
| 302 | }; | ||
| 303 | |||
| 304 | #define to_clk_periph_gate(_hw) \ | ||
| 305 | container_of(_hw, struct tegra_clk_periph_gate, hw) | ||
| 306 | |||
| 307 | #define TEGRA_CLK_PERIPH_GATE_MAGIC 0x17760309 | ||
| 308 | |||
| 309 | #define TEGRA_PERIPH_NO_RESET BIT(0) | ||
| 310 | #define TEGRA_PERIPH_MANUAL_RESET BIT(1) | ||
| 311 | #define TEGRA_PERIPH_ON_APB BIT(2) | ||
| 312 | |||
| 313 | void tegra_periph_reset(struct tegra_clk_periph_gate *gate, bool assert); | ||
| 314 | extern const struct clk_ops tegra_clk_periph_gate_ops; | ||
| 315 | struct clk *tegra_clk_register_periph_gate(const char *name, | ||
| 316 | const char *parent_name, u8 gate_flags, void __iomem *clk_base, | ||
| 317 | unsigned long flags, int clk_num, | ||
| 318 | struct tegra_clk_periph_regs *pregs, int *enable_refcnt); | ||
| 319 | |||
| 320 | /** | ||
| 321 | * struct clk-periph - peripheral clock | ||
| 322 | * | ||
| 323 | * @magic: magic number to validate type | ||
| 324 | * @hw: handle between common and hardware-specific interfaces | ||
| 325 | * @mux: mux clock | ||
| 326 | * @divider: divider clock | ||
| 327 | * @gate: gate clock | ||
| 328 | * @mux_ops: mux clock ops | ||
| 329 | * @div_ops: divider clock ops | ||
| 330 | * @gate_ops: gate clock ops | ||
| 331 | */ | ||
| 332 | struct tegra_clk_periph { | ||
| 333 | u32 magic; | ||
| 334 | struct clk_hw hw; | ||
| 335 | struct clk_mux mux; | ||
| 336 | struct tegra_clk_frac_div divider; | ||
| 337 | struct tegra_clk_periph_gate gate; | ||
| 338 | |||
| 339 | const struct clk_ops *mux_ops; | ||
| 340 | const struct clk_ops *div_ops; | ||
| 341 | const struct clk_ops *gate_ops; | ||
| 342 | }; | ||
| 343 | |||
| 344 | #define to_clk_periph(_hw) container_of(_hw, struct tegra_clk_periph, hw) | ||
| 345 | |||
| 346 | #define TEGRA_CLK_PERIPH_MAGIC 0x18221223 | ||
| 347 | |||
| 348 | extern const struct clk_ops tegra_clk_periph_ops; | ||
| 349 | struct clk *tegra_clk_register_periph(const char *name, | ||
| 350 | const char **parent_names, int num_parents, | ||
| 351 | struct tegra_clk_periph *periph, void __iomem *clk_base, | ||
| 352 | u32 offset); | ||
| 353 | struct clk *tegra_clk_register_periph_nodiv(const char *name, | ||
| 354 | const char **parent_names, int num_parents, | ||
| 355 | struct tegra_clk_periph *periph, void __iomem *clk_base, | ||
| 356 | u32 offset); | ||
| 357 | |||
| 358 | #define TEGRA_CLK_PERIPH(_mux_shift, _mux_width, _mux_flags, \ | ||
| 359 | _div_shift, _div_width, _div_frac_width, \ | ||
| 360 | _div_flags, _clk_num, _enb_refcnt, _regs, \ | ||
| 361 | _gate_flags) \ | ||
| 362 | { \ | ||
| 363 | .mux = { \ | ||
| 364 | .flags = _mux_flags, \ | ||
| 365 | .shift = _mux_shift, \ | ||
| 366 | .width = _mux_width, \ | ||
| 367 | }, \ | ||
| 368 | .divider = { \ | ||
| 369 | .flags = _div_flags, \ | ||
| 370 | .shift = _div_shift, \ | ||
| 371 | .width = _div_width, \ | ||
| 372 | .frac_width = _div_frac_width, \ | ||
| 373 | }, \ | ||
| 374 | .gate = { \ | ||
| 375 | .flags = _gate_flags, \ | ||
| 376 | .clk_num = _clk_num, \ | ||
| 377 | .enable_refcnt = _enb_refcnt, \ | ||
| 378 | .regs = _regs, \ | ||
| 379 | }, \ | ||
| 380 | .mux_ops = &clk_mux_ops, \ | ||
| 381 | .div_ops = &tegra_clk_frac_div_ops, \ | ||
| 382 | .gate_ops = &tegra_clk_periph_gate_ops, \ | ||
| 383 | } | ||
| 384 | |||
| 385 | struct tegra_periph_init_data { | ||
| 386 | const char *name; | ||
| 387 | int clk_id; | ||
| 388 | const char **parent_names; | ||
| 389 | int num_parents; | ||
| 390 | struct tegra_clk_periph periph; | ||
| 391 | u32 offset; | ||
| 392 | const char *con_id; | ||
| 393 | const char *dev_id; | ||
| 394 | }; | ||
| 395 | |||
| 396 | #define TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parent_names, _offset, \ | ||
| 397 | _mux_shift, _mux_width, _mux_flags, _div_shift, \ | ||
| 398 | _div_width, _div_frac_width, _div_flags, _regs, \ | ||
| 399 | _clk_num, _enb_refcnt, _gate_flags, _clk_id) \ | ||
| 400 | { \ | ||
| 401 | .name = _name, \ | ||
| 402 | .clk_id = _clk_id, \ | ||
| 403 | .parent_names = _parent_names, \ | ||
| 404 | .num_parents = ARRAY_SIZE(_parent_names), \ | ||
| 405 | .periph = TEGRA_CLK_PERIPH(_mux_shift, _mux_width, \ | ||
| 406 | _mux_flags, _div_shift, \ | ||
| 407 | _div_width, _div_frac_width, \ | ||
| 408 | _div_flags, _clk_num, \ | ||
| 409 | _enb_refcnt, _regs, \ | ||
| 410 | _gate_flags), \ | ||
| 411 | .offset = _offset, \ | ||
| 412 | .con_id = _con_id, \ | ||
| 413 | .dev_id = _dev_id, \ | ||
| 414 | } | ||
| 415 | |||
| 416 | /** | ||
| 417 | * struct clk_super_mux - super clock | ||
| 418 | * | ||
| 419 | * @hw: handle between common and hardware-specific interfaces | ||
| 420 | * @reg: register controlling multiplexer | ||
| 421 | * @width: width of the multiplexer bit field | ||
| 422 | * @flags: hardware-specific flags | ||
| 423 | * @div2_index: bit controlling divide-by-2 | ||
| 424 | * @pllx_index: PLLX index in the parent list | ||
| 425 | * @lock: register lock | ||
| 426 | * | ||
| 427 | * Flags: | ||
| 428 | * TEGRA_DIVIDER_2 - LP cluster has additional divider. This flag indicates | ||
| 429 | * that this is LP cluster clock. | ||
| 430 | */ | ||
| 431 | struct tegra_clk_super_mux { | ||
| 432 | struct clk_hw hw; | ||
| 433 | void __iomem *reg; | ||
| 434 | u8 width; | ||
| 435 | u8 flags; | ||
| 436 | u8 div2_index; | ||
| 437 | u8 pllx_index; | ||
| 438 | spinlock_t *lock; | ||
| 439 | }; | ||
| 440 | |||
| 441 | #define to_clk_super_mux(_hw) container_of(_hw, struct tegra_clk_super_mux, hw) | ||
| 442 | |||
| 443 | #define TEGRA_DIVIDER_2 BIT(0) | ||
| 444 | |||
| 445 | extern const struct clk_ops tegra_clk_super_ops; | ||
| 446 | struct clk *tegra_clk_register_super_mux(const char *name, | ||
| 447 | const char **parent_names, u8 num_parents, | ||
| 448 | unsigned long flags, void __iomem *reg, u8 clk_super_flags, | ||
| 449 | u8 width, u8 pllx_index, u8 div2_index, spinlock_t *lock); | ||
| 450 | |||
| 451 | /** | ||
| 452 | * struct clk_init_tabel - clock initialization table | ||
| 453 | * @clk_id: clock id as mentioned in device tree bindings | ||
| 454 | * @parent_id: parent clock id as mentioned in device tree bindings | ||
| 455 | * @rate: rate to set | ||
| 456 | * @state: enable/disable | ||
| 457 | */ | ||
| 458 | struct tegra_clk_init_table { | ||
| 459 | unsigned int clk_id; | ||
| 460 | unsigned int parent_id; | ||
| 461 | unsigned long rate; | ||
| 462 | int state; | ||
| 463 | }; | ||
| 464 | |||
| 465 | /** | ||
| 466 | * struct clk_duplicate - duplicate clocks | ||
| 467 | * @clk_id: clock id as mentioned in device tree bindings | ||
| 468 | * @lookup: duplicate lookup entry for the clock | ||
| 469 | */ | ||
| 470 | struct tegra_clk_duplicate { | ||
| 471 | int clk_id; | ||
| 472 | struct clk_lookup lookup; | ||
| 473 | }; | ||
| 474 | |||
| 475 | #define TEGRA_CLK_DUPLICATE(_clk_id, _dev, _con) \ | ||
| 476 | { \ | ||
| 477 | .clk_id = _clk_id, \ | ||
| 478 | .lookup = { \ | ||
| 479 | .dev_id = _dev, \ | ||
| 480 | .con_id = _con, \ | ||
| 481 | }, \ | ||
| 482 | } | ||
| 483 | |||
| 484 | void tegra_init_from_table(struct tegra_clk_init_table *tbl, | ||
| 485 | struct clk *clks[], int clk_max); | ||
| 486 | |||
| 487 | void tegra_init_dup_clks(struct tegra_clk_duplicate *dup_list, | ||
| 488 | struct clk *clks[], int clk_max); | ||
| 489 | |||
| 490 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | ||
| 491 | void tegra20_clock_init(struct device_node *np); | ||
| 492 | #else | ||
| 493 | static inline void tegra20_clock_init(struct device_node *np) {} | ||
| 494 | #endif /* CONFIG_ARCH_TEGRA_2x_SOC */ | ||
| 495 | |||
| 496 | #ifdef CONFIG_ARCH_TEGRA_3x_SOC | ||
| 497 | void tegra30_clock_init(struct device_node *np); | ||
| 498 | #else | ||
| 499 | static inline void tegra30_clock_init(struct device_node *np) {} | ||
| 500 | #endif /* CONFIG_ARCH_TEGRA_3x_SOC */ | ||
| 501 | |||
| 502 | #endif /* TEGRA_CLK_H */ | ||
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index a32b7a9c65d3..7d978c1bd528 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig | |||
| @@ -28,6 +28,9 @@ config ARMADA_370_XP_TIMER | |||
| 28 | config SUNXI_TIMER | 28 | config SUNXI_TIMER |
| 29 | bool | 29 | bool |
| 30 | 30 | ||
| 31 | config VT8500_TIMER | ||
| 32 | bool | ||
| 33 | |||
| 31 | config CLKSRC_NOMADIK_MTU | 34 | config CLKSRC_NOMADIK_MTU |
| 32 | bool | 35 | bool |
| 33 | depends on (ARCH_NOMADIK || ARCH_U8500) | 36 | depends on (ARCH_NOMADIK || ARCH_U8500) |
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index a33f79240217..596c45c2f192 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile | |||
| @@ -17,5 +17,7 @@ obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o | |||
| 17 | obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o | 17 | obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o |
| 18 | obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o | 18 | obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o |
| 19 | obj-$(CONFIG_SUNXI_TIMER) += sunxi_timer.o | 19 | obj-$(CONFIG_SUNXI_TIMER) += sunxi_timer.o |
| 20 | obj-$(CONFIG_ARCH_TEGRA) += tegra20_timer.o | ||
| 21 | obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o | ||
| 20 | 22 | ||
| 21 | obj-$(CONFIG_CLKSRC_ARM_GENERIC) += arm_generic.o | 23 | obj-$(CONFIG_CLKSRC_ARM_GENERIC) += arm_generic.o |
diff --git a/drivers/clocksource/cs5535-clockevt.c b/drivers/clocksource/cs5535-clockevt.c index d9279385304d..ea210482dd20 100644 --- a/drivers/clocksource/cs5535-clockevt.c +++ b/drivers/clocksource/cs5535-clockevt.c | |||
| @@ -100,7 +100,6 @@ static struct clock_event_device cs5535_clockevent = { | |||
| 100 | .set_mode = mfgpt_set_mode, | 100 | .set_mode = mfgpt_set_mode, |
| 101 | .set_next_event = mfgpt_next_event, | 101 | .set_next_event = mfgpt_next_event, |
| 102 | .rating = 250, | 102 | .rating = 250, |
| 103 | .shift = 32 | ||
| 104 | }; | 103 | }; |
| 105 | 104 | ||
| 106 | static irqreturn_t mfgpt_tick(int irq, void *dev_id) | 105 | static irqreturn_t mfgpt_tick(int irq, void *dev_id) |
| @@ -169,17 +168,11 @@ static int __init cs5535_mfgpt_init(void) | |||
| 169 | cs5535_mfgpt_write(cs5535_event_clock, MFGPT_REG_SETUP, val); | 168 | cs5535_mfgpt_write(cs5535_event_clock, MFGPT_REG_SETUP, val); |
| 170 | 169 | ||
| 171 | /* Set up the clock event */ | 170 | /* Set up the clock event */ |
| 172 | cs5535_clockevent.mult = div_sc(MFGPT_HZ, NSEC_PER_SEC, | ||
| 173 | cs5535_clockevent.shift); | ||
| 174 | cs5535_clockevent.min_delta_ns = clockevent_delta2ns(0xF, | ||
| 175 | &cs5535_clockevent); | ||
| 176 | cs5535_clockevent.max_delta_ns = clockevent_delta2ns(0xFFFE, | ||
| 177 | &cs5535_clockevent); | ||
| 178 | |||
| 179 | printk(KERN_INFO DRV_NAME | 171 | printk(KERN_INFO DRV_NAME |
| 180 | ": Registering MFGPT timer as a clock event, using IRQ %d\n", | 172 | ": Registering MFGPT timer as a clock event, using IRQ %d\n", |
| 181 | timer_irq); | 173 | timer_irq); |
| 182 | clockevents_register_device(&cs5535_clockevent); | 174 | clockevents_config_and_register(&cs5535_clockevent, MFGPT_HZ, |
| 175 | 0xF, 0xFFFE); | ||
| 183 | 176 | ||
| 184 | return 0; | 177 | return 0; |
| 185 | 178 | ||
diff --git a/drivers/clocksource/sunxi_timer.c b/drivers/clocksource/sunxi_timer.c index 6c2ed56e8b14..0ce85e29769b 100644 --- a/drivers/clocksource/sunxi_timer.c +++ b/drivers/clocksource/sunxi_timer.c | |||
| @@ -74,7 +74,6 @@ static int sunxi_clkevt_next_event(unsigned long evt, | |||
| 74 | 74 | ||
| 75 | static struct clock_event_device sunxi_clockevent = { | 75 | static struct clock_event_device sunxi_clockevent = { |
| 76 | .name = "sunxi_tick", | 76 | .name = "sunxi_tick", |
| 77 | .shift = 32, | ||
| 78 | .rating = 300, | 77 | .rating = 300, |
| 79 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | 78 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, |
| 80 | .set_mode = sunxi_clkevt_mode, | 79 | .set_mode = sunxi_clkevt_mode, |
| @@ -154,14 +153,8 @@ void __init sunxi_timer_init(void) | |||
| 154 | val = readl(timer_base + TIMER_CTL_REG); | 153 | val = readl(timer_base + TIMER_CTL_REG); |
| 155 | writel(val | TIMER_CTL_ENABLE, timer_base + TIMER_CTL_REG); | 154 | writel(val | TIMER_CTL_ENABLE, timer_base + TIMER_CTL_REG); |
| 156 | 155 | ||
| 157 | sunxi_clockevent.mult = div_sc(rate / TIMER_SCAL, | ||
| 158 | NSEC_PER_SEC, | ||
| 159 | sunxi_clockevent.shift); | ||
| 160 | sunxi_clockevent.max_delta_ns = clockevent_delta2ns(0xff, | ||
| 161 | &sunxi_clockevent); | ||
| 162 | sunxi_clockevent.min_delta_ns = clockevent_delta2ns(0x1, | ||
| 163 | &sunxi_clockevent); | ||
| 164 | sunxi_clockevent.cpumask = cpumask_of(0); | 156 | sunxi_clockevent.cpumask = cpumask_of(0); |
| 165 | 157 | ||
| 166 | clockevents_register_device(&sunxi_clockevent); | 158 | clockevents_config_and_register(&sunxi_clockevent, rate / TIMER_SCAL, |
| 159 | 0x1, 0xff); | ||
| 167 | } | 160 | } |
diff --git a/drivers/clocksource/tcb_clksrc.c b/drivers/clocksource/tcb_clksrc.c index 32cb929b8eb6..8a6187225dd0 100644 --- a/drivers/clocksource/tcb_clksrc.c +++ b/drivers/clocksource/tcb_clksrc.c | |||
| @@ -157,7 +157,6 @@ static struct tc_clkevt_device clkevt = { | |||
| 157 | .name = "tc_clkevt", | 157 | .name = "tc_clkevt", |
| 158 | .features = CLOCK_EVT_FEAT_PERIODIC | 158 | .features = CLOCK_EVT_FEAT_PERIODIC |
| 159 | | CLOCK_EVT_FEAT_ONESHOT, | 159 | | CLOCK_EVT_FEAT_ONESHOT, |
| 160 | .shift = 32, | ||
| 161 | /* Should be lower than at91rm9200's system timer */ | 160 | /* Should be lower than at91rm9200's system timer */ |
| 162 | .rating = 125, | 161 | .rating = 125, |
| 163 | .set_next_event = tc_next_event, | 162 | .set_next_event = tc_next_event, |
| @@ -196,13 +195,9 @@ static void __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx) | |||
| 196 | 195 | ||
| 197 | timer_clock = clk32k_divisor_idx; | 196 | timer_clock = clk32k_divisor_idx; |
| 198 | 197 | ||
| 199 | clkevt.clkevt.mult = div_sc(32768, NSEC_PER_SEC, clkevt.clkevt.shift); | ||
| 200 | clkevt.clkevt.max_delta_ns | ||
| 201 | = clockevent_delta2ns(0xffff, &clkevt.clkevt); | ||
| 202 | clkevt.clkevt.min_delta_ns = clockevent_delta2ns(1, &clkevt.clkevt) + 1; | ||
| 203 | clkevt.clkevt.cpumask = cpumask_of(0); | 198 | clkevt.clkevt.cpumask = cpumask_of(0); |
| 204 | 199 | ||
| 205 | clockevents_register_device(&clkevt.clkevt); | 200 | clockevents_config_and_register(&clkevt.clkevt, 32768, 1, 0xffff); |
| 206 | 201 | ||
| 207 | setup_irq(irq, &tc_irqaction); | 202 | setup_irq(irq, &tc_irqaction); |
| 208 | } | 203 | } |
diff --git a/drivers/clocksource/tegra20_timer.c b/drivers/clocksource/tegra20_timer.c new file mode 100644 index 000000000000..0bde03feb095 --- /dev/null +++ b/drivers/clocksource/tegra20_timer.c | |||
| @@ -0,0 +1,281 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2010 Google, Inc. | ||
| 3 | * | ||
| 4 | * Author: | ||
| 5 | * Colin Cross <ccross@google.com> | ||
| 6 | * | ||
| 7 | * This software is licensed under the terms of the GNU General Public | ||
| 8 | * License version 2, as published by the Free Software Foundation, and | ||
| 9 | * may be copied, distributed, and modified under those terms. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | */ | ||
| 17 | |||
| 18 | #include <linux/init.h> | ||
| 19 | #include <linux/err.h> | ||
| 20 | #include <linux/time.h> | ||
| 21 | #include <linux/interrupt.h> | ||
| 22 | #include <linux/irq.h> | ||
| 23 | #include <linux/clockchips.h> | ||
| 24 | #include <linux/clocksource.h> | ||
| 25 | #include <linux/clk.h> | ||
| 26 | #include <linux/io.h> | ||
| 27 | #include <linux/of_address.h> | ||
| 28 | #include <linux/of_irq.h> | ||
| 29 | |||
| 30 | #include <asm/mach/time.h> | ||
| 31 | #include <asm/smp_twd.h> | ||
| 32 | #include <asm/sched_clock.h> | ||
| 33 | |||
| 34 | #define RTC_SECONDS 0x08 | ||
| 35 | #define RTC_SHADOW_SECONDS 0x0c | ||
| 36 | #define RTC_MILLISECONDS 0x10 | ||
| 37 | |||
| 38 | #define TIMERUS_CNTR_1US 0x10 | ||
| 39 | #define TIMERUS_USEC_CFG 0x14 | ||
| 40 | #define TIMERUS_CNTR_FREEZE 0x4c | ||
| 41 | |||
| 42 | #define TIMER1_BASE 0x0 | ||
| 43 | #define TIMER2_BASE 0x8 | ||
| 44 | #define TIMER3_BASE 0x50 | ||
| 45 | #define TIMER4_BASE 0x58 | ||
| 46 | |||
| 47 | #define TIMER_PTV 0x0 | ||
| 48 | #define TIMER_PCR 0x4 | ||
| 49 | |||
| 50 | static void __iomem *timer_reg_base; | ||
| 51 | static void __iomem *rtc_base; | ||
| 52 | |||
| 53 | static struct timespec persistent_ts; | ||
| 54 | static u64 persistent_ms, last_persistent_ms; | ||
| 55 | |||
| 56 | #define timer_writel(value, reg) \ | ||
| 57 | __raw_writel(value, timer_reg_base + (reg)) | ||
| 58 | #define timer_readl(reg) \ | ||
| 59 | __raw_readl(timer_reg_base + (reg)) | ||
| 60 | |||
| 61 | static int tegra_timer_set_next_event(unsigned long cycles, | ||
| 62 | struct clock_event_device *evt) | ||
| 63 | { | ||
| 64 | u32 reg; | ||
| 65 | |||
| 66 | reg = 0x80000000 | ((cycles > 1) ? (cycles-1) : 0); | ||
| 67 | timer_writel(reg, TIMER3_BASE + TIMER_PTV); | ||
| 68 | |||
| 69 | return 0; | ||
| 70 | } | ||
| 71 | |||
| 72 | static void tegra_timer_set_mode(enum clock_event_mode mode, | ||
| 73 | struct clock_event_device *evt) | ||
| 74 | { | ||
| 75 | u32 reg; | ||
| 76 | |||
| 77 | timer_writel(0, TIMER3_BASE + TIMER_PTV); | ||
| 78 | |||
| 79 | switch (mode) { | ||
| 80 | case CLOCK_EVT_MODE_PERIODIC: | ||
| 81 | reg = 0xC0000000 | ((1000000/HZ)-1); | ||
| 82 | timer_writel(reg, TIMER3_BASE + TIMER_PTV); | ||
| 83 | break; | ||
| 84 | case CLOCK_EVT_MODE_ONESHOT: | ||
| 85 | break; | ||
| 86 | case CLOCK_EVT_MODE_UNUSED: | ||
| 87 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
| 88 | case CLOCK_EVT_MODE_RESUME: | ||
| 89 | break; | ||
| 90 | } | ||
| 91 | } | ||
| 92 | |||
| 93 | static struct clock_event_device tegra_clockevent = { | ||
| 94 | .name = "timer0", | ||
| 95 | .rating = 300, | ||
| 96 | .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, | ||
| 97 | .set_next_event = tegra_timer_set_next_event, | ||
| 98 | .set_mode = tegra_timer_set_mode, | ||
| 99 | }; | ||
| 100 | |||
| 101 | static u32 notrace tegra_read_sched_clock(void) | ||
| 102 | { | ||
| 103 | return timer_readl(TIMERUS_CNTR_1US); | ||
| 104 | } | ||
| 105 | |||
| 106 | /* | ||
| 107 | * tegra_rtc_read - Reads the Tegra RTC registers | ||
| 108 | * Care must be taken that this funciton is not called while the | ||
| 109 | * tegra_rtc driver could be executing to avoid race conditions | ||
| 110 | * on the RTC shadow register | ||
| 111 | */ | ||
| 112 | static u64 tegra_rtc_read_ms(void) | ||
| 113 | { | ||
| 114 | u32 ms = readl(rtc_base + RTC_MILLISECONDS); | ||
| 115 | u32 s = readl(rtc_base + RTC_SHADOW_SECONDS); | ||
| 116 | return (u64)s * MSEC_PER_SEC + ms; | ||
| 117 | } | ||
| 118 | |||
| 119 | /* | ||
| 120 | * tegra_read_persistent_clock - Return time from a persistent clock. | ||
| 121 | * | ||
| 122 | * Reads the time from a source which isn't disabled during PM, the | ||
| 123 | * 32k sync timer. Convert the cycles elapsed since last read into | ||
| 124 | * nsecs and adds to a monotonically increasing timespec. | ||
| 125 | * Care must be taken that this funciton is not called while the | ||
| 126 | * tegra_rtc driver could be executing to avoid race conditions | ||
| 127 | * on the RTC shadow register | ||
| 128 | */ | ||
| 129 | static void tegra_read_persistent_clock(struct timespec *ts) | ||
| 130 | { | ||
| 131 | u64 delta; | ||
| 132 | struct timespec *tsp = &persistent_ts; | ||
| 133 | |||
| 134 | last_persistent_ms = persistent_ms; | ||
| 135 | persistent_ms = tegra_rtc_read_ms(); | ||
| 136 | delta = persistent_ms - last_persistent_ms; | ||
| 137 | |||
| 138 | timespec_add_ns(tsp, delta * NSEC_PER_MSEC); | ||
| 139 | *ts = *tsp; | ||
| 140 | } | ||
| 141 | |||
| 142 | static irqreturn_t tegra_timer_interrupt(int irq, void *dev_id) | ||
| 143 | { | ||
| 144 | struct clock_event_device *evt = (struct clock_event_device *)dev_id; | ||
| 145 | timer_writel(1<<30, TIMER3_BASE + TIMER_PCR); | ||
| 146 | evt->event_handler(evt); | ||
| 147 | return IRQ_HANDLED; | ||
| 148 | } | ||
| 149 | |||
| 150 | static struct irqaction tegra_timer_irq = { | ||
| 151 | .name = "timer0", | ||
| 152 | .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_TRIGGER_HIGH, | ||
| 153 | .handler = tegra_timer_interrupt, | ||
| 154 | .dev_id = &tegra_clockevent, | ||
| 155 | }; | ||
| 156 | |||
| 157 | static const struct of_device_id timer_match[] __initconst = { | ||
| 158 | { .compatible = "nvidia,tegra20-timer" }, | ||
| 159 | {} | ||
| 160 | }; | ||
| 161 | |||
| 162 | static const struct of_device_id rtc_match[] __initconst = { | ||
| 163 | { .compatible = "nvidia,tegra20-rtc" }, | ||
| 164 | {} | ||
| 165 | }; | ||
| 166 | |||
| 167 | static void __init tegra20_init_timer(void) | ||
| 168 | { | ||
| 169 | struct device_node *np; | ||
| 170 | struct clk *clk; | ||
| 171 | unsigned long rate; | ||
| 172 | int ret; | ||
| 173 | |||
| 174 | np = of_find_matching_node(NULL, timer_match); | ||
| 175 | if (!np) { | ||
| 176 | pr_err("Failed to find timer DT node\n"); | ||
| 177 | BUG(); | ||
| 178 | } | ||
| 179 | |||
| 180 | timer_reg_base = of_iomap(np, 0); | ||
| 181 | if (!timer_reg_base) { | ||
| 182 | pr_err("Can't map timer registers\n"); | ||
| 183 | BUG(); | ||
| 184 | } | ||
| 185 | |||
| 186 | tegra_timer_irq.irq = irq_of_parse_and_map(np, 2); | ||
| 187 | if (tegra_timer_irq.irq <= 0) { | ||
| 188 | pr_err("Failed to map timer IRQ\n"); | ||
| 189 | BUG(); | ||
| 190 | } | ||
| 191 | |||
| 192 | clk = clk_get_sys("timer", NULL); | ||
| 193 | if (IS_ERR(clk)) { | ||
| 194 | pr_warn("Unable to get timer clock. Assuming 12Mhz input clock.\n"); | ||
| 195 | rate = 12000000; | ||
| 196 | } else { | ||
| 197 | clk_prepare_enable(clk); | ||
| 198 | rate = clk_get_rate(clk); | ||
| 199 | } | ||
| 200 | |||
| 201 | of_node_put(np); | ||
| 202 | |||
| 203 | np = of_find_matching_node(NULL, rtc_match); | ||
| 204 | if (!np) { | ||
| 205 | pr_err("Failed to find RTC DT node\n"); | ||
| 206 | BUG(); | ||
| 207 | } | ||
| 208 | |||
| 209 | rtc_base = of_iomap(np, 0); | ||
| 210 | if (!rtc_base) { | ||
| 211 | pr_err("Can't map RTC registers"); | ||
| 212 | BUG(); | ||
| 213 | } | ||
| 214 | |||
| 215 | /* | ||
| 216 | * rtc registers are used by read_persistent_clock, keep the rtc clock | ||
| 217 | * enabled | ||
| 218 | */ | ||
| 219 | clk = clk_get_sys("rtc-tegra", NULL); | ||
| 220 | if (IS_ERR(clk)) | ||
| 221 | pr_warn("Unable to get rtc-tegra clock\n"); | ||
| 222 | else | ||
| 223 | clk_prepare_enable(clk); | ||
| 224 | |||
| 225 | of_node_put(np); | ||
| 226 | |||
| 227 | switch (rate) { | ||
| 228 | case 12000000: | ||
| 229 | timer_writel(0x000b, TIMERUS_USEC_CFG); | ||
| 230 | break; | ||
| 231 | case 13000000: | ||
| 232 | timer_writel(0x000c, TIMERUS_USEC_CFG); | ||
| 233 | break; | ||
| 234 | case 19200000: | ||
| 235 | timer_writel(0x045f, TIMERUS_USEC_CFG); | ||
| 236 | break; | ||
| 237 | case 26000000: | ||
| 238 | timer_writel(0x0019, TIMERUS_USEC_CFG); | ||
| 239 | break; | ||
| 240 | default: | ||
| 241 | WARN(1, "Unknown clock rate"); | ||
| 242 | } | ||
| 243 | |||
| 244 | setup_sched_clock(tegra_read_sched_clock, 32, 1000000); | ||
| 245 | |||
| 246 | if (clocksource_mmio_init(timer_reg_base + TIMERUS_CNTR_1US, | ||
| 247 | "timer_us", 1000000, 300, 32, clocksource_mmio_readl_up)) { | ||
| 248 | pr_err("Failed to register clocksource\n"); | ||
| 249 | BUG(); | ||
| 250 | } | ||
| 251 | |||
| 252 | ret = setup_irq(tegra_timer_irq.irq, &tegra_timer_irq); | ||
| 253 | if (ret) { | ||
| 254 | pr_err("Failed to register timer IRQ: %d\n", ret); | ||
| 255 | BUG(); | ||
| 256 | } | ||
| 257 | |||
| 258 | tegra_clockevent.cpumask = cpu_all_mask; | ||
| 259 | tegra_clockevent.irq = tegra_timer_irq.irq; | ||
| 260 | clockevents_config_and_register(&tegra_clockevent, 1000000, | ||
| 261 | 0x1, 0x1fffffff); | ||
| 262 | #ifdef CONFIG_HAVE_ARM_TWD | ||
| 263 | twd_local_timer_of_register(); | ||
| 264 | #endif | ||
| 265 | register_persistent_clock(NULL, tegra_read_persistent_clock); | ||
| 266 | } | ||
| 267 | CLOCKSOURCE_OF_DECLARE(tegra20, "nvidia,tegra20-timer", tegra20_init_timer); | ||
| 268 | |||
| 269 | #ifdef CONFIG_PM | ||
| 270 | static u32 usec_config; | ||
| 271 | |||
| 272 | void tegra_timer_suspend(void) | ||
| 273 | { | ||
| 274 | usec_config = timer_readl(TIMERUS_USEC_CFG); | ||
| 275 | } | ||
| 276 | |||
| 277 | void tegra_timer_resume(void) | ||
| 278 | { | ||
| 279 | timer_writel(usec_config, TIMERUS_USEC_CFG); | ||
| 280 | } | ||
| 281 | #endif | ||
diff --git a/drivers/clocksource/vt8500_timer.c b/drivers/clocksource/vt8500_timer.c new file mode 100644 index 000000000000..ed66cf07d3c6 --- /dev/null +++ b/drivers/clocksource/vt8500_timer.c | |||
| @@ -0,0 +1,179 @@ | |||
| 1 | /* | ||
| 2 | * arch/arm/mach-vt8500/timer.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz> | ||
| 5 | * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License as published by | ||
| 9 | * the Free Software Foundation; either version 2 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 20 | */ | ||
| 21 | |||
| 22 | /* | ||
| 23 | * This file is copied and modified from the original timer.c provided by | ||
| 24 | * Alexey Charkov. Minor changes have been made for Device Tree Support. | ||
| 25 | */ | ||
| 26 | |||
| 27 | #include <linux/io.h> | ||
| 28 | #include <linux/irq.h> | ||
| 29 | #include <linux/interrupt.h> | ||
| 30 | #include <linux/clocksource.h> | ||
| 31 | #include <linux/clockchips.h> | ||
| 32 | #include <linux/delay.h> | ||
| 33 | #include <asm/mach/time.h> | ||
| 34 | |||
| 35 | #include <linux/of.h> | ||
| 36 | #include <linux/of_address.h> | ||
| 37 | #include <linux/of_irq.h> | ||
| 38 | |||
| 39 | #define VT8500_TIMER_OFFSET 0x0100 | ||
| 40 | #define VT8500_TIMER_HZ 3000000 | ||
| 41 | #define TIMER_MATCH_VAL 0x0000 | ||
| 42 | #define TIMER_COUNT_VAL 0x0010 | ||
| 43 | #define TIMER_STATUS_VAL 0x0014 | ||
| 44 | #define TIMER_IER_VAL 0x001c /* interrupt enable */ | ||
| 45 | #define TIMER_CTRL_VAL 0x0020 | ||
| 46 | #define TIMER_AS_VAL 0x0024 /* access status */ | ||
| 47 | #define TIMER_COUNT_R_ACTIVE (1 << 5) /* not ready for read */ | ||
| 48 | #define TIMER_COUNT_W_ACTIVE (1 << 4) /* not ready for write */ | ||
| 49 | #define TIMER_MATCH_W_ACTIVE (1 << 0) /* not ready for write */ | ||
| 50 | |||
| 51 | #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t) | ||
| 52 | |||
| 53 | static void __iomem *regbase; | ||
| 54 | |||
| 55 | static cycle_t vt8500_timer_read(struct clocksource *cs) | ||
| 56 | { | ||
| 57 | int loops = msecs_to_loops(10); | ||
| 58 | writel(3, regbase + TIMER_CTRL_VAL); | ||
| 59 | while ((readl((regbase + TIMER_AS_VAL)) & TIMER_COUNT_R_ACTIVE) | ||
| 60 | && --loops) | ||
| 61 | cpu_relax(); | ||
| 62 | return readl(regbase + TIMER_COUNT_VAL); | ||
| 63 | } | ||
| 64 | |||
| 65 | static struct clocksource clocksource = { | ||
| 66 | .name = "vt8500_timer", | ||
| 67 | .rating = 200, | ||
| 68 | .read = vt8500_timer_read, | ||
| 69 | .mask = CLOCKSOURCE_MASK(32), | ||
| 70 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
| 71 | }; | ||
| 72 | |||
| 73 | static int vt8500_timer_set_next_event(unsigned long cycles, | ||
| 74 | struct clock_event_device *evt) | ||
| 75 | { | ||
| 76 | int loops = msecs_to_loops(10); | ||
| 77 | cycle_t alarm = clocksource.read(&clocksource) + cycles; | ||
| 78 | while ((readl(regbase + TIMER_AS_VAL) & TIMER_MATCH_W_ACTIVE) | ||
| 79 | && --loops) | ||
| 80 | cpu_relax(); | ||
| 81 | writel((unsigned long)alarm, regbase + TIMER_MATCH_VAL); | ||
| 82 | |||
| 83 | if ((signed)(alarm - clocksource.read(&clocksource)) <= 16) | ||
| 84 | return -ETIME; | ||
| 85 | |||
| 86 | writel(1, regbase + TIMER_IER_VAL); | ||
| 87 | |||
| 88 | return 0; | ||
| 89 | } | ||
| 90 | |||
| 91 | static void vt8500_timer_set_mode(enum clock_event_mode mode, | ||
| 92 | struct clock_event_device *evt) | ||
| 93 | { | ||
| 94 | switch (mode) { | ||
| 95 | case CLOCK_EVT_MODE_RESUME: | ||
| 96 | case CLOCK_EVT_MODE_PERIODIC: | ||
| 97 | break; | ||
| 98 | case CLOCK_EVT_MODE_ONESHOT: | ||
| 99 | case CLOCK_EVT_MODE_UNUSED: | ||
| 100 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
| 101 | writel(readl(regbase + TIMER_CTRL_VAL) | 1, | ||
| 102 | regbase + TIMER_CTRL_VAL); | ||
| 103 | writel(0, regbase + TIMER_IER_VAL); | ||
| 104 | break; | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | static struct clock_event_device clockevent = { | ||
| 109 | .name = "vt8500_timer", | ||
| 110 | .features = CLOCK_EVT_FEAT_ONESHOT, | ||
| 111 | .rating = 200, | ||
| 112 | .set_next_event = vt8500_timer_set_next_event, | ||
| 113 | .set_mode = vt8500_timer_set_mode, | ||
| 114 | }; | ||
| 115 | |||
| 116 | static irqreturn_t vt8500_timer_interrupt(int irq, void *dev_id) | ||
| 117 | { | ||
| 118 | struct clock_event_device *evt = dev_id; | ||
| 119 | writel(0xf, regbase + TIMER_STATUS_VAL); | ||
| 120 | evt->event_handler(evt); | ||
| 121 | |||
| 122 | return IRQ_HANDLED; | ||
| 123 | } | ||
| 124 | |||
| 125 | static struct irqaction irq = { | ||
| 126 | .name = "vt8500_timer", | ||
| 127 | .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, | ||
| 128 | .handler = vt8500_timer_interrupt, | ||
| 129 | .dev_id = &clockevent, | ||
| 130 | }; | ||
| 131 | |||
| 132 | static struct of_device_id vt8500_timer_ids[] = { | ||
| 133 | { .compatible = "via,vt8500-timer" }, | ||
| 134 | { } | ||
| 135 | }; | ||
| 136 | |||
| 137 | void __init vt8500_timer_init(void) | ||
| 138 | { | ||
| 139 | struct device_node *np; | ||
| 140 | int timer_irq; | ||
| 141 | |||
| 142 | np = of_find_matching_node(NULL, vt8500_timer_ids); | ||
| 143 | if (!np) { | ||
| 144 | pr_err("%s: Timer description missing from Device Tree\n", | ||
| 145 | __func__); | ||
| 146 | return; | ||
| 147 | } | ||
| 148 | regbase = of_iomap(np, 0); | ||
| 149 | if (!regbase) { | ||
| 150 | pr_err("%s: Missing iobase description in Device Tree\n", | ||
| 151 | __func__); | ||
| 152 | of_node_put(np); | ||
| 153 | return; | ||
| 154 | } | ||
| 155 | timer_irq = irq_of_parse_and_map(np, 0); | ||
| 156 | if (!timer_irq) { | ||
| 157 | pr_err("%s: Missing irq description in Device Tree\n", | ||
| 158 | __func__); | ||
| 159 | of_node_put(np); | ||
| 160 | return; | ||
| 161 | } | ||
| 162 | |||
| 163 | writel(1, regbase + TIMER_CTRL_VAL); | ||
| 164 | writel(0xf, regbase + TIMER_STATUS_VAL); | ||
| 165 | writel(~0, regbase + TIMER_MATCH_VAL); | ||
| 166 | |||
| 167 | if (clocksource_register_hz(&clocksource, VT8500_TIMER_HZ)) | ||
| 168 | pr_err("%s: vt8500_timer_init: clocksource_register failed for %s\n", | ||
| 169 | __func__, clocksource.name); | ||
| 170 | |||
| 171 | clockevent.cpumask = cpumask_of(0); | ||
| 172 | |||
| 173 | if (setup_irq(timer_irq, &irq)) | ||
| 174 | pr_err("%s: setup_irq failed for %s\n", __func__, | ||
| 175 | clockevent.name); | ||
| 176 | clockevents_config_and_register(&clockevent, VT8500_TIMER_HZ, | ||
| 177 | 4, 0xf0000000); | ||
| 178 | } | ||
| 179 | |||
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/Kconfig b/drivers/cpuidle/Kconfig index c4cc27e5c8a5..071e2c3eec4f 100644 --- a/drivers/cpuidle/Kconfig +++ b/drivers/cpuidle/Kconfig | |||
| @@ -39,4 +39,10 @@ config CPU_IDLE_CALXEDA | |||
| 39 | help | 39 | help |
| 40 | Select this to enable cpuidle on Calxeda processors. | 40 | Select this to enable cpuidle on Calxeda processors. |
| 41 | 41 | ||
| 42 | config CPU_IDLE_KIRKWOOD | ||
| 43 | bool "CPU Idle Driver for Kirkwood processors" | ||
| 44 | depends on ARCH_KIRKWOOD | ||
| 45 | help | ||
| 46 | Select this to enable cpuidle on Kirkwood processors. | ||
| 47 | |||
| 42 | endif | 48 | endif |
diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile index 03ee87482c71..24c6e7d945ed 100644 --- a/drivers/cpuidle/Makefile +++ b/drivers/cpuidle/Makefile | |||
| @@ -6,3 +6,4 @@ obj-y += cpuidle.o driver.o governor.o sysfs.o governors/ | |||
| 6 | obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o | 6 | obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o |
| 7 | 7 | ||
| 8 | obj-$(CONFIG_CPU_IDLE_CALXEDA) += cpuidle-calxeda.o | 8 | obj-$(CONFIG_CPU_IDLE_CALXEDA) += cpuidle-calxeda.o |
| 9 | obj-$(CONFIG_CPU_IDLE_KIRKWOOD) += cpuidle-kirkwood.o | ||
diff --git a/drivers/cpuidle/cpuidle-kirkwood.c b/drivers/cpuidle/cpuidle-kirkwood.c new file mode 100644 index 000000000000..670aa1e55cd6 --- /dev/null +++ b/drivers/cpuidle/cpuidle-kirkwood.c | |||
| @@ -0,0 +1,106 @@ | |||
| 1 | /* | ||
| 2 | * arch/arm/mach-kirkwood/cpuidle.c | ||
| 3 | * | ||
| 4 | * CPU idle Marvell Kirkwood SoCs | ||
| 5 | * | ||
| 6 | * This file is licensed under the terms of the GNU General Public | ||
| 7 | * License version 2. This program is licensed "as is" without any | ||
| 8 | * warranty of any kind, whether express or implied. | ||
| 9 | * | ||
| 10 | * The cpu idle uses wait-for-interrupt and DDR self refresh in order | ||
| 11 | * to implement two idle states - | ||
| 12 | * #1 wait-for-interrupt | ||
| 13 | * #2 wait-for-interrupt and DDR self refresh | ||
| 14 | */ | ||
| 15 | |||
| 16 | #include <linux/kernel.h> | ||
| 17 | #include <linux/module.h> | ||
| 18 | #include <linux/init.h> | ||
| 19 | #include <linux/platform_device.h> | ||
| 20 | #include <linux/cpuidle.h> | ||
| 21 | #include <linux/io.h> | ||
| 22 | #include <linux/export.h> | ||
| 23 | #include <asm/proc-fns.h> | ||
| 24 | #include <asm/cpuidle.h> | ||
| 25 | |||
| 26 | #define KIRKWOOD_MAX_STATES 2 | ||
| 27 | |||
| 28 | static void __iomem *ddr_operation_base; | ||
| 29 | |||
| 30 | /* Actual code that puts the SoC in different idle states */ | ||
| 31 | static int kirkwood_enter_idle(struct cpuidle_device *dev, | ||
| 32 | struct cpuidle_driver *drv, | ||
| 33 | int index) | ||
| 34 | { | ||
| 35 | writel(0x7, ddr_operation_base); | ||
| 36 | cpu_do_idle(); | ||
| 37 | |||
| 38 | return index; | ||
| 39 | } | ||
| 40 | |||
| 41 | static struct cpuidle_driver kirkwood_idle_driver = { | ||
| 42 | .name = "kirkwood_idle", | ||
| 43 | .owner = THIS_MODULE, | ||
| 44 | .en_core_tk_irqen = 1, | ||
| 45 | .states[0] = ARM_CPUIDLE_WFI_STATE, | ||
| 46 | .states[1] = { | ||
| 47 | .enter = kirkwood_enter_idle, | ||
| 48 | .exit_latency = 10, | ||
| 49 | .target_residency = 100000, | ||
| 50 | .flags = CPUIDLE_FLAG_TIME_VALID, | ||
| 51 | .name = "DDR SR", | ||
| 52 | .desc = "WFI and DDR Self Refresh", | ||
| 53 | }, | ||
| 54 | .state_count = KIRKWOOD_MAX_STATES, | ||
| 55 | }; | ||
| 56 | static struct cpuidle_device *device; | ||
| 57 | |||
| 58 | static DEFINE_PER_CPU(struct cpuidle_device, kirkwood_cpuidle_device); | ||
| 59 | |||
| 60 | /* Initialize CPU idle by registering the idle states */ | ||
| 61 | static int kirkwood_cpuidle_probe(struct platform_device *pdev) | ||
| 62 | { | ||
| 63 | struct resource *res; | ||
| 64 | |||
| 65 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 66 | if (res == NULL) | ||
| 67 | return -EINVAL; | ||
| 68 | |||
| 69 | ddr_operation_base = devm_request_and_ioremap(&pdev->dev, res); | ||
| 70 | if (!ddr_operation_base) | ||
| 71 | return -EADDRNOTAVAIL; | ||
| 72 | |||
| 73 | device = &per_cpu(kirkwood_cpuidle_device, smp_processor_id()); | ||
| 74 | device->state_count = KIRKWOOD_MAX_STATES; | ||
| 75 | |||
| 76 | cpuidle_register_driver(&kirkwood_idle_driver); | ||
| 77 | if (cpuidle_register_device(device)) { | ||
| 78 | pr_err("kirkwood_init_cpuidle: Failed registering\n"); | ||
| 79 | return -EIO; | ||
| 80 | } | ||
| 81 | return 0; | ||
| 82 | } | ||
| 83 | |||
| 84 | int kirkwood_cpuidle_remove(struct platform_device *pdev) | ||
| 85 | { | ||
| 86 | cpuidle_unregister_device(device); | ||
| 87 | cpuidle_unregister_driver(&kirkwood_idle_driver); | ||
| 88 | |||
| 89 | return 0; | ||
| 90 | } | ||
| 91 | |||
| 92 | static struct platform_driver kirkwood_cpuidle_driver = { | ||
| 93 | .probe = kirkwood_cpuidle_probe, | ||
| 94 | .remove = kirkwood_cpuidle_remove, | ||
| 95 | .driver = { | ||
| 96 | .name = "kirkwood_cpuidle", | ||
| 97 | .owner = THIS_MODULE, | ||
| 98 | }, | ||
| 99 | }; | ||
| 100 | |||
| 101 | module_platform_driver(kirkwood_cpuidle_driver); | ||
| 102 | |||
| 103 | MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>"); | ||
| 104 | MODULE_DESCRIPTION("Kirkwood cpu idle driver"); | ||
| 105 | MODULE_LICENSE("GPL v2"); | ||
| 106 | MODULE_ALIAS("platform:kirkwood-cpuidle"); | ||
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..2a02c11890ec 100644 --- a/drivers/dma/tegra20-apb-dma.c +++ b/drivers/dma/tegra20-apb-dma.c | |||
| @@ -31,8 +31,8 @@ | |||
| 31 | #include <linux/platform_device.h> | 31 | #include <linux/platform_device.h> |
| 32 | #include <linux/pm_runtime.h> | 32 | #include <linux/pm_runtime.h> |
| 33 | #include <linux/slab.h> | 33 | #include <linux/slab.h> |
| 34 | #include <linux/clk/tegra.h> | ||
| 34 | 35 | ||
| 35 | #include <mach/clk.h> | ||
| 36 | #include "dmaengine.h" | 36 | #include "dmaengine.h" |
| 37 | 37 | ||
| 38 | #define TEGRA_APBDMA_GENERAL 0x0 | 38 | #define TEGRA_APBDMA_GENERAL 0x0 |
| @@ -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/edac/edac_mc.c b/drivers/edac/edac_mc.c index 281f566a5513..d1e9eb191f2b 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c | |||
| @@ -340,7 +340,7 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, | |||
| 340 | /* | 340 | /* |
| 341 | * Alocate and fill the csrow/channels structs | 341 | * Alocate and fill the csrow/channels structs |
| 342 | */ | 342 | */ |
| 343 | mci->csrows = kcalloc(sizeof(*mci->csrows), tot_csrows, GFP_KERNEL); | 343 | mci->csrows = kcalloc(tot_csrows, sizeof(*mci->csrows), GFP_KERNEL); |
| 344 | if (!mci->csrows) | 344 | if (!mci->csrows) |
| 345 | goto error; | 345 | goto error; |
| 346 | for (row = 0; row < tot_csrows; row++) { | 346 | for (row = 0; row < tot_csrows; row++) { |
| @@ -351,7 +351,7 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, | |||
| 351 | csr->csrow_idx = row; | 351 | csr->csrow_idx = row; |
| 352 | csr->mci = mci; | 352 | csr->mci = mci; |
| 353 | csr->nr_channels = tot_channels; | 353 | csr->nr_channels = tot_channels; |
| 354 | csr->channels = kcalloc(sizeof(*csr->channels), tot_channels, | 354 | csr->channels = kcalloc(tot_channels, sizeof(*csr->channels), |
| 355 | GFP_KERNEL); | 355 | GFP_KERNEL); |
| 356 | if (!csr->channels) | 356 | if (!csr->channels) |
| 357 | goto error; | 357 | goto error; |
| @@ -369,7 +369,7 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, | |||
| 369 | /* | 369 | /* |
| 370 | * Allocate and fill the dimm structs | 370 | * Allocate and fill the dimm structs |
| 371 | */ | 371 | */ |
| 372 | mci->dimms = kcalloc(sizeof(*mci->dimms), tot_dimms, GFP_KERNEL); | 372 | mci->dimms = kcalloc(tot_dimms, sizeof(*mci->dimms), GFP_KERNEL); |
| 373 | if (!mci->dimms) | 373 | if (!mci->dimms) |
| 374 | goto error; | 374 | goto error; |
| 375 | 375 | ||
diff --git a/drivers/edac/edac_pci_sysfs.c b/drivers/edac/edac_pci_sysfs.c index dc6e905ee1a5..0056c4dae9d5 100644 --- a/drivers/edac/edac_pci_sysfs.c +++ b/drivers/edac/edac_pci_sysfs.c | |||
| @@ -256,7 +256,7 @@ static ssize_t edac_pci_dev_store(struct kobject *kobj, | |||
| 256 | struct edac_pci_dev_attribute *edac_pci_dev; | 256 | struct edac_pci_dev_attribute *edac_pci_dev; |
| 257 | edac_pci_dev = (struct edac_pci_dev_attribute *)attr; | 257 | edac_pci_dev = (struct edac_pci_dev_attribute *)attr; |
| 258 | 258 | ||
| 259 | if (edac_pci_dev->show) | 259 | if (edac_pci_dev->store) |
| 260 | return edac_pci_dev->store(edac_pci_dev->value, buffer, count); | 260 | return edac_pci_dev->store(edac_pci_dev->value, buffer, count); |
| 261 | return -EIO; | 261 | return -EIO; |
| 262 | } | 262 | } |
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index fd3ae6290d71..982f1f5f5742 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c | |||
| @@ -471,7 +471,7 @@ void __init dmi_scan_machine(void) | |||
| 471 | char __iomem *p, *q; | 471 | char __iomem *p, *q; |
| 472 | int rc; | 472 | int rc; |
| 473 | 473 | ||
| 474 | if (efi_enabled) { | 474 | if (efi_enabled(EFI_CONFIG_TABLES)) { |
| 475 | if (efi.smbios == EFI_INVALID_TABLE_ADDR) | 475 | if (efi.smbios == EFI_INVALID_TABLE_ADDR) |
| 476 | goto error; | 476 | goto error; |
| 477 | 477 | ||
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index 7b1c37497c9a..f5596db0cf58 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c | |||
| @@ -674,7 +674,7 @@ static int efi_status_to_err(efi_status_t status) | |||
| 674 | err = -EACCES; | 674 | err = -EACCES; |
| 675 | break; | 675 | break; |
| 676 | case EFI_NOT_FOUND: | 676 | case EFI_NOT_FOUND: |
| 677 | err = -ENOENT; | 677 | err = -EIO; |
| 678 | break; | 678 | break; |
| 679 | default: | 679 | default: |
| 680 | err = -EINVAL; | 680 | err = -EINVAL; |
| @@ -793,6 +793,7 @@ static ssize_t efivarfs_file_write(struct file *file, | |||
| 793 | spin_unlock(&efivars->lock); | 793 | spin_unlock(&efivars->lock); |
| 794 | efivar_unregister(var); | 794 | efivar_unregister(var); |
| 795 | drop_nlink(inode); | 795 | drop_nlink(inode); |
| 796 | d_delete(file->f_dentry); | ||
| 796 | dput(file->f_dentry); | 797 | dput(file->f_dentry); |
| 797 | 798 | ||
| 798 | } else { | 799 | } else { |
| @@ -994,7 +995,7 @@ static int efivarfs_unlink(struct inode *dir, struct dentry *dentry) | |||
| 994 | list_del(&var->list); | 995 | list_del(&var->list); |
| 995 | spin_unlock(&efivars->lock); | 996 | spin_unlock(&efivars->lock); |
| 996 | efivar_unregister(var); | 997 | efivar_unregister(var); |
| 997 | drop_nlink(dir); | 998 | drop_nlink(dentry->d_inode); |
| 998 | dput(dentry); | 999 | dput(dentry); |
| 999 | return 0; | 1000 | return 0; |
| 1000 | } | 1001 | } |
| @@ -1782,7 +1783,7 @@ efivars_init(void) | |||
| 1782 | printk(KERN_INFO "EFI Variables Facility v%s %s\n", EFIVARS_VERSION, | 1783 | printk(KERN_INFO "EFI Variables Facility v%s %s\n", EFIVARS_VERSION, |
| 1783 | EFIVARS_DATE); | 1784 | EFIVARS_DATE); |
| 1784 | 1785 | ||
| 1785 | if (!efi_enabled) | 1786 | if (!efi_enabled(EFI_RUNTIME_SERVICES)) |
| 1786 | return 0; | 1787 | return 0; |
| 1787 | 1788 | ||
| 1788 | /* For now we'll register the efi directory at /sys/firmware/efi */ | 1789 | /* For now we'll register the efi directory at /sys/firmware/efi */ |
| @@ -1822,7 +1823,7 @@ err_put: | |||
| 1822 | static void __exit | 1823 | static void __exit |
| 1823 | efivars_exit(void) | 1824 | efivars_exit(void) |
| 1824 | { | 1825 | { |
| 1825 | if (efi_enabled) { | 1826 | if (efi_enabled(EFI_RUNTIME_SERVICES)) { |
| 1826 | unregister_efivars(&__efivars); | 1827 | unregister_efivars(&__efivars); |
| 1827 | kobject_put(efi_kobj); | 1828 | kobject_put(efi_kobj); |
| 1828 | } | 1829 | } |
diff --git a/drivers/firmware/iscsi_ibft_find.c b/drivers/firmware/iscsi_ibft_find.c index 4da4eb9ae926..2224f1dc074b 100644 --- a/drivers/firmware/iscsi_ibft_find.c +++ b/drivers/firmware/iscsi_ibft_find.c | |||
| @@ -99,7 +99,7 @@ unsigned long __init find_ibft_region(unsigned long *sizep) | |||
| 99 | /* iBFT 1.03 section 1.4.3.1 mandates that UEFI machines will | 99 | /* iBFT 1.03 section 1.4.3.1 mandates that UEFI machines will |
| 100 | * only use ACPI for this */ | 100 | * only use ACPI for this */ |
| 101 | 101 | ||
| 102 | if (!efi_enabled) | 102 | if (!efi_enabled(EFI_BOOT)) |
| 103 | find_ibft_in_mem(); | 103 | find_ibft_in_mem(); |
| 104 | 104 | ||
| 105 | if (ibft_addr) { | 105 | if (ibft_addr) { |
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/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index 1d1f1e5e33f0..046bcda36abe 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig | |||
| @@ -24,7 +24,7 @@ config DRM_EXYNOS_DMABUF | |||
| 24 | 24 | ||
| 25 | config DRM_EXYNOS_FIMD | 25 | config DRM_EXYNOS_FIMD |
| 26 | bool "Exynos DRM FIMD" | 26 | bool "Exynos DRM FIMD" |
| 27 | depends on DRM_EXYNOS && !FB_S3C | 27 | depends on DRM_EXYNOS && !FB_S3C && !ARCH_MULTIPLATFORM |
| 28 | help | 28 | help |
| 29 | Choose this option if you want to use Exynos FIMD for DRM. | 29 | Choose this option if you want to use Exynos FIMD for DRM. |
| 30 | 30 | ||
| @@ -48,7 +48,7 @@ config DRM_EXYNOS_G2D | |||
| 48 | 48 | ||
| 49 | config DRM_EXYNOS_IPP | 49 | config DRM_EXYNOS_IPP |
| 50 | bool "Exynos DRM IPP" | 50 | bool "Exynos DRM IPP" |
| 51 | depends on DRM_EXYNOS | 51 | depends on DRM_EXYNOS && !ARCH_MULTIPLATFORM |
| 52 | help | 52 | help |
| 53 | Choose this option if you want to use IPP feature for DRM. | 53 | Choose this option if you want to use IPP feature for DRM. |
| 54 | 54 | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c b/drivers/gpu/drm/exynos/exynos_drm_connector.c index ab37437bad8a..4c5b6859c9ea 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_connector.c +++ b/drivers/gpu/drm/exynos/exynos_drm_connector.c | |||
| @@ -18,7 +18,6 @@ | |||
| 18 | #include "exynos_drm_drv.h" | 18 | #include "exynos_drm_drv.h" |
| 19 | #include "exynos_drm_encoder.h" | 19 | #include "exynos_drm_encoder.h" |
| 20 | 20 | ||
| 21 | #define MAX_EDID 256 | ||
| 22 | #define to_exynos_connector(x) container_of(x, struct exynos_drm_connector,\ | 21 | #define to_exynos_connector(x) container_of(x, struct exynos_drm_connector,\ |
| 23 | drm_connector) | 22 | drm_connector) |
| 24 | 23 | ||
| @@ -96,7 +95,9 @@ static int exynos_drm_connector_get_modes(struct drm_connector *connector) | |||
| 96 | to_exynos_connector(connector); | 95 | to_exynos_connector(connector); |
| 97 | struct exynos_drm_manager *manager = exynos_connector->manager; | 96 | struct exynos_drm_manager *manager = exynos_connector->manager; |
| 98 | struct exynos_drm_display_ops *display_ops = manager->display_ops; | 97 | struct exynos_drm_display_ops *display_ops = manager->display_ops; |
| 99 | unsigned int count; | 98 | struct edid *edid = NULL; |
| 99 | unsigned int count = 0; | ||
| 100 | int ret; | ||
| 100 | 101 | ||
| 101 | DRM_DEBUG_KMS("%s\n", __FILE__); | 102 | DRM_DEBUG_KMS("%s\n", __FILE__); |
| 102 | 103 | ||
| @@ -114,27 +115,21 @@ static int exynos_drm_connector_get_modes(struct drm_connector *connector) | |||
| 114 | * because lcd panel has only one mode. | 115 | * because lcd panel has only one mode. |
| 115 | */ | 116 | */ |
| 116 | if (display_ops->get_edid) { | 117 | if (display_ops->get_edid) { |
| 117 | int ret; | 118 | edid = display_ops->get_edid(manager->dev, connector); |
| 118 | void *edid; | 119 | if (IS_ERR_OR_NULL(edid)) { |
| 119 | 120 | ret = PTR_ERR(edid); | |
| 120 | edid = kzalloc(MAX_EDID, GFP_KERNEL); | 121 | edid = NULL; |
| 121 | if (!edid) { | 122 | DRM_ERROR("Panel operation get_edid failed %d\n", ret); |
| 122 | DRM_ERROR("failed to allocate edid\n"); | 123 | goto out; |
| 123 | return 0; | ||
| 124 | } | 124 | } |
| 125 | 125 | ||
| 126 | ret = display_ops->get_edid(manager->dev, connector, | 126 | count = drm_add_edid_modes(connector, edid); |
| 127 | edid, MAX_EDID); | 127 | if (count < 0) { |
| 128 | if (ret < 0) { | 128 | DRM_ERROR("Add edid modes failed %d\n", count); |
| 129 | DRM_ERROR("failed to get edid data.\n"); | 129 | goto out; |
| 130 | kfree(edid); | ||
| 131 | edid = NULL; | ||
| 132 | return 0; | ||
| 133 | } | 130 | } |
| 134 | 131 | ||
| 135 | drm_mode_connector_update_edid_property(connector, edid); | 132 | drm_mode_connector_update_edid_property(connector, edid); |
| 136 | count = drm_add_edid_modes(connector, edid); | ||
| 137 | kfree(edid); | ||
| 138 | } else { | 133 | } else { |
| 139 | struct exynos_drm_panel_info *panel; | 134 | struct exynos_drm_panel_info *panel; |
| 140 | struct drm_display_mode *mode = drm_mode_create(connector->dev); | 135 | struct drm_display_mode *mode = drm_mode_create(connector->dev); |
| @@ -161,6 +156,8 @@ static int exynos_drm_connector_get_modes(struct drm_connector *connector) | |||
| 161 | count = 1; | 156 | count = 1; |
| 162 | } | 157 | } |
| 163 | 158 | ||
| 159 | out: | ||
| 160 | kfree(edid); | ||
| 164 | return count; | 161 | return count; |
| 165 | } | 162 | } |
| 166 | 163 | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c index 9df97714b6c0..ba0a3aa78547 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | struct exynos_drm_dmabuf_attachment { | 19 | struct exynos_drm_dmabuf_attachment { |
| 20 | struct sg_table sgt; | 20 | struct sg_table sgt; |
| 21 | enum dma_data_direction dir; | 21 | enum dma_data_direction dir; |
| 22 | bool is_mapped; | ||
| 22 | }; | 23 | }; |
| 23 | 24 | ||
| 24 | static int exynos_gem_attach_dma_buf(struct dma_buf *dmabuf, | 25 | static int exynos_gem_attach_dma_buf(struct dma_buf *dmabuf, |
| @@ -72,17 +73,10 @@ static struct sg_table * | |||
| 72 | 73 | ||
| 73 | DRM_DEBUG_PRIME("%s\n", __FILE__); | 74 | DRM_DEBUG_PRIME("%s\n", __FILE__); |
| 74 | 75 | ||
| 75 | if (WARN_ON(dir == DMA_NONE)) | ||
| 76 | return ERR_PTR(-EINVAL); | ||
| 77 | |||
| 78 | /* just return current sgt if already requested. */ | 76 | /* just return current sgt if already requested. */ |
| 79 | if (exynos_attach->dir == dir) | 77 | if (exynos_attach->dir == dir && exynos_attach->is_mapped) |
| 80 | return &exynos_attach->sgt; | 78 | return &exynos_attach->sgt; |
| 81 | 79 | ||
| 82 | /* reattaching is not allowed. */ | ||
| 83 | if (WARN_ON(exynos_attach->dir != DMA_NONE)) | ||
| 84 | return ERR_PTR(-EBUSY); | ||
| 85 | |||
| 86 | buf = gem_obj->buffer; | 80 | buf = gem_obj->buffer; |
| 87 | if (!buf) { | 81 | if (!buf) { |
| 88 | DRM_ERROR("buffer is null.\n"); | 82 | DRM_ERROR("buffer is null.\n"); |
| @@ -107,13 +101,17 @@ static struct sg_table * | |||
| 107 | wr = sg_next(wr); | 101 | wr = sg_next(wr); |
| 108 | } | 102 | } |
| 109 | 103 | ||
| 110 | nents = dma_map_sg(attach->dev, sgt->sgl, sgt->orig_nents, dir); | 104 | if (dir != DMA_NONE) { |
| 111 | if (!nents) { | 105 | nents = dma_map_sg(attach->dev, sgt->sgl, sgt->orig_nents, dir); |
| 112 | DRM_ERROR("failed to map sgl with iommu.\n"); | 106 | if (!nents) { |
| 113 | sgt = ERR_PTR(-EIO); | 107 | DRM_ERROR("failed to map sgl with iommu.\n"); |
| 114 | goto err_unlock; | 108 | sg_free_table(sgt); |
| 109 | sgt = ERR_PTR(-EIO); | ||
| 110 | goto err_unlock; | ||
| 111 | } | ||
| 115 | } | 112 | } |
| 116 | 113 | ||
| 114 | exynos_attach->is_mapped = true; | ||
| 117 | exynos_attach->dir = dir; | 115 | exynos_attach->dir = dir; |
| 118 | attach->priv = exynos_attach; | 116 | attach->priv = exynos_attach; |
| 119 | 117 | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index b9e51bc09e81..4606fac7241a 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h | |||
| @@ -148,8 +148,8 @@ struct exynos_drm_overlay { | |||
| 148 | struct exynos_drm_display_ops { | 148 | struct exynos_drm_display_ops { |
| 149 | enum exynos_drm_output_type type; | 149 | enum exynos_drm_output_type type; |
| 150 | bool (*is_connected)(struct device *dev); | 150 | bool (*is_connected)(struct device *dev); |
| 151 | int (*get_edid)(struct device *dev, struct drm_connector *connector, | 151 | struct edid *(*get_edid)(struct device *dev, |
| 152 | u8 *edid, int len); | 152 | struct drm_connector *connector); |
| 153 | void *(*get_panel)(struct device *dev); | 153 | void *(*get_panel)(struct device *dev); |
| 154 | int (*check_timing)(struct device *dev, void *timing); | 154 | int (*check_timing)(struct device *dev, void *timing); |
| 155 | int (*power_on)(struct device *dev, int mode); | 155 | int (*power_on)(struct device *dev, int mode); |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index 36c3905536a6..9a4c08e7453c 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c | |||
| @@ -324,7 +324,7 @@ out: | |||
| 324 | g2d_userptr = NULL; | 324 | g2d_userptr = NULL; |
| 325 | } | 325 | } |
| 326 | 326 | ||
| 327 | dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev, | 327 | static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev, |
| 328 | unsigned long userptr, | 328 | unsigned long userptr, |
| 329 | unsigned long size, | 329 | unsigned long size, |
| 330 | struct drm_file *filp, | 330 | struct drm_file *filp, |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c index 850e9950b7da..28644539b305 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c | |||
| @@ -108,18 +108,17 @@ static bool drm_hdmi_is_connected(struct device *dev) | |||
| 108 | return false; | 108 | return false; |
| 109 | } | 109 | } |
| 110 | 110 | ||
| 111 | static int drm_hdmi_get_edid(struct device *dev, | 111 | static struct edid *drm_hdmi_get_edid(struct device *dev, |
| 112 | struct drm_connector *connector, u8 *edid, int len) | 112 | struct drm_connector *connector) |
| 113 | { | 113 | { |
| 114 | struct drm_hdmi_context *ctx = to_context(dev); | 114 | struct drm_hdmi_context *ctx = to_context(dev); |
| 115 | 115 | ||
| 116 | DRM_DEBUG_KMS("%s\n", __FILE__); | 116 | DRM_DEBUG_KMS("%s\n", __FILE__); |
| 117 | 117 | ||
| 118 | if (hdmi_ops && hdmi_ops->get_edid) | 118 | if (hdmi_ops && hdmi_ops->get_edid) |
| 119 | return hdmi_ops->get_edid(ctx->hdmi_ctx->ctx, connector, edid, | 119 | return hdmi_ops->get_edid(ctx->hdmi_ctx->ctx, connector); |
| 120 | len); | ||
| 121 | 120 | ||
| 122 | return 0; | 121 | return NULL; |
| 123 | } | 122 | } |
| 124 | 123 | ||
| 125 | static int drm_hdmi_check_timing(struct device *dev, void *timing) | 124 | static int drm_hdmi_check_timing(struct device *dev, void *timing) |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h index 784a7e9a766c..d80516fc9ed7 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h +++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h | |||
| @@ -30,8 +30,8 @@ struct exynos_drm_hdmi_context { | |||
| 30 | struct exynos_hdmi_ops { | 30 | struct exynos_hdmi_ops { |
| 31 | /* display */ | 31 | /* display */ |
| 32 | bool (*is_connected)(void *ctx); | 32 | bool (*is_connected)(void *ctx); |
| 33 | int (*get_edid)(void *ctx, struct drm_connector *connector, | 33 | struct edid *(*get_edid)(void *ctx, |
| 34 | u8 *edid, int len); | 34 | struct drm_connector *connector); |
| 35 | int (*check_timing)(void *ctx, void *timing); | 35 | int (*check_timing)(void *ctx, void *timing); |
| 36 | int (*power_on)(void *ctx, int mode); | 36 | int (*power_on)(void *ctx, int mode); |
| 37 | 37 | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c index 0bda96454a02..1a556354e92f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c +++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c | |||
| @@ -869,7 +869,7 @@ static void ipp_put_event(struct drm_exynos_ipp_cmd_node *c_node, | |||
| 869 | } | 869 | } |
| 870 | } | 870 | } |
| 871 | 871 | ||
| 872 | void ipp_handle_cmd_work(struct device *dev, | 872 | static void ipp_handle_cmd_work(struct device *dev, |
| 873 | struct exynos_drm_ippdrv *ippdrv, | 873 | struct exynos_drm_ippdrv *ippdrv, |
| 874 | struct drm_exynos_ipp_cmd_work *cmd_work, | 874 | struct drm_exynos_ipp_cmd_work *cmd_work, |
| 875 | struct drm_exynos_ipp_cmd_node *c_node) | 875 | struct drm_exynos_ipp_cmd_node *c_node) |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_rotator.c b/drivers/gpu/drm/exynos/exynos_drm_rotator.c index e9e83ef688f0..f976e29def6e 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_rotator.c +++ b/drivers/gpu/drm/exynos/exynos_drm_rotator.c | |||
| @@ -734,7 +734,7 @@ static int rotator_remove(struct platform_device *pdev) | |||
| 734 | return 0; | 734 | return 0; |
| 735 | } | 735 | } |
| 736 | 736 | ||
| 737 | struct rot_limit_table rot_limit_tbl = { | 737 | static struct rot_limit_table rot_limit_tbl = { |
| 738 | .ycbcr420_2p = { | 738 | .ycbcr420_2p = { |
| 739 | .min_w = 32, | 739 | .min_w = 32, |
| 740 | .min_h = 32, | 740 | .min_h = 32, |
| @@ -751,7 +751,7 @@ struct rot_limit_table rot_limit_tbl = { | |||
| 751 | }, | 751 | }, |
| 752 | }; | 752 | }; |
| 753 | 753 | ||
| 754 | struct platform_device_id rotator_driver_ids[] = { | 754 | static struct platform_device_id rotator_driver_ids[] = { |
| 755 | { | 755 | { |
| 756 | .name = "exynos-rot", | 756 | .name = "exynos-rot", |
| 757 | .driver_data = (unsigned long)&rot_limit_tbl, | 757 | .driver_data = (unsigned long)&rot_limit_tbl, |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index d0ca3c4e06c6..13ccbd4bcfaa 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c | |||
| @@ -98,10 +98,12 @@ static bool vidi_display_is_connected(struct device *dev) | |||
| 98 | return ctx->connected ? true : false; | 98 | return ctx->connected ? true : false; |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | static int vidi_get_edid(struct device *dev, struct drm_connector *connector, | 101 | static struct edid *vidi_get_edid(struct device *dev, |
| 102 | u8 *edid, int len) | 102 | struct drm_connector *connector) |
| 103 | { | 103 | { |
| 104 | struct vidi_context *ctx = get_vidi_context(dev); | 104 | struct vidi_context *ctx = get_vidi_context(dev); |
| 105 | struct edid *edid; | ||
| 106 | int edid_len; | ||
| 105 | 107 | ||
| 106 | DRM_DEBUG_KMS("%s\n", __FILE__); | 108 | DRM_DEBUG_KMS("%s\n", __FILE__); |
| 107 | 109 | ||
| @@ -111,13 +113,18 @@ static int vidi_get_edid(struct device *dev, struct drm_connector *connector, | |||
| 111 | */ | 113 | */ |
| 112 | if (!ctx->raw_edid) { | 114 | if (!ctx->raw_edid) { |
| 113 | DRM_DEBUG_KMS("raw_edid is null.\n"); | 115 | DRM_DEBUG_KMS("raw_edid is null.\n"); |
| 114 | return -EFAULT; | 116 | return ERR_PTR(-EFAULT); |
| 115 | } | 117 | } |
| 116 | 118 | ||
| 117 | memcpy(edid, ctx->raw_edid, min((1 + ctx->raw_edid->extensions) | 119 | edid_len = (1 + ctx->raw_edid->extensions) * EDID_LENGTH; |
| 118 | * EDID_LENGTH, len)); | 120 | edid = kzalloc(edid_len, GFP_KERNEL); |
| 121 | if (!edid) { | ||
| 122 | DRM_DEBUG_KMS("failed to allocate edid\n"); | ||
| 123 | return ERR_PTR(-ENOMEM); | ||
| 124 | } | ||
| 119 | 125 | ||
| 120 | return 0; | 126 | memcpy(edid, ctx->raw_edid, edid_len); |
| 127 | return edid; | ||
| 121 | } | 128 | } |
| 122 | 129 | ||
| 123 | static void *vidi_get_panel(struct device *dev) | 130 | static void *vidi_get_panel(struct device *dev) |
| @@ -514,7 +521,6 @@ int vidi_connection_ioctl(struct drm_device *drm_dev, void *data, | |||
| 514 | struct exynos_drm_manager *manager; | 521 | struct exynos_drm_manager *manager; |
| 515 | struct exynos_drm_display_ops *display_ops; | 522 | struct exynos_drm_display_ops *display_ops; |
| 516 | struct drm_exynos_vidi_connection *vidi = data; | 523 | struct drm_exynos_vidi_connection *vidi = data; |
| 517 | struct edid *raw_edid; | ||
| 518 | int edid_len; | 524 | int edid_len; |
| 519 | 525 | ||
| 520 | DRM_DEBUG_KMS("%s\n", __FILE__); | 526 | DRM_DEBUG_KMS("%s\n", __FILE__); |
| @@ -551,11 +557,11 @@ int vidi_connection_ioctl(struct drm_device *drm_dev, void *data, | |||
| 551 | } | 557 | } |
| 552 | 558 | ||
| 553 | if (vidi->connection) { | 559 | if (vidi->connection) { |
| 554 | if (!vidi->edid) { | 560 | struct edid *raw_edid = (struct edid *)(uint32_t)vidi->edid; |
| 555 | DRM_DEBUG_KMS("edid data is null.\n"); | 561 | if (!drm_edid_is_valid(raw_edid)) { |
| 562 | DRM_DEBUG_KMS("edid data is invalid.\n"); | ||
| 556 | return -EINVAL; | 563 | return -EINVAL; |
| 557 | } | 564 | } |
| 558 | raw_edid = (struct edid *)(uint32_t)vidi->edid; | ||
| 559 | edid_len = (1 + raw_edid->extensions) * EDID_LENGTH; | 565 | edid_len = (1 + raw_edid->extensions) * EDID_LENGTH; |
| 560 | ctx->raw_edid = kzalloc(edid_len, GFP_KERNEL); | 566 | ctx->raw_edid = kzalloc(edid_len, GFP_KERNEL); |
| 561 | if (!ctx->raw_edid) { | 567 | if (!ctx->raw_edid) { |
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 41ff79d8ac8e..fbab3c468603 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c | |||
| @@ -34,7 +34,6 @@ | |||
| 34 | #include <linux/regulator/consumer.h> | 34 | #include <linux/regulator/consumer.h> |
| 35 | #include <linux/io.h> | 35 | #include <linux/io.h> |
| 36 | #include <linux/of_gpio.h> | 36 | #include <linux/of_gpio.h> |
| 37 | #include <plat/gpio-cfg.h> | ||
| 38 | 37 | ||
| 39 | #include <drm/exynos_drm.h> | 38 | #include <drm/exynos_drm.h> |
| 40 | 39 | ||
| @@ -98,8 +97,7 @@ struct hdmi_context { | |||
| 98 | 97 | ||
| 99 | void __iomem *regs; | 98 | void __iomem *regs; |
| 100 | void *parent_ctx; | 99 | void *parent_ctx; |
| 101 | int external_irq; | 100 | int irq; |
| 102 | int internal_irq; | ||
| 103 | 101 | ||
| 104 | struct i2c_client *ddc_port; | 102 | struct i2c_client *ddc_port; |
| 105 | struct i2c_client *hdmiphy_port; | 103 | struct i2c_client *hdmiphy_port; |
| @@ -1391,8 +1389,7 @@ static bool hdmi_is_connected(void *ctx) | |||
| 1391 | return hdata->hpd; | 1389 | return hdata->hpd; |
| 1392 | } | 1390 | } |
| 1393 | 1391 | ||
| 1394 | static int hdmi_get_edid(void *ctx, struct drm_connector *connector, | 1392 | static struct edid *hdmi_get_edid(void *ctx, struct drm_connector *connector) |
| 1395 | u8 *edid, int len) | ||
| 1396 | { | 1393 | { |
| 1397 | struct edid *raw_edid; | 1394 | struct edid *raw_edid; |
| 1398 | struct hdmi_context *hdata = ctx; | 1395 | struct hdmi_context *hdata = ctx; |
| @@ -1400,22 +1397,18 @@ static int hdmi_get_edid(void *ctx, struct drm_connector *connector, | |||
| 1400 | DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); | 1397 | DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); |
| 1401 | 1398 | ||
| 1402 | if (!hdata->ddc_port) | 1399 | if (!hdata->ddc_port) |
| 1403 | return -ENODEV; | 1400 | return ERR_PTR(-ENODEV); |
| 1404 | 1401 | ||
| 1405 | raw_edid = drm_get_edid(connector, hdata->ddc_port->adapter); | 1402 | raw_edid = drm_get_edid(connector, hdata->ddc_port->adapter); |
| 1406 | if (raw_edid) { | 1403 | if (!raw_edid) |
| 1407 | hdata->dvi_mode = !drm_detect_hdmi_monitor(raw_edid); | 1404 | return ERR_PTR(-ENODEV); |
| 1408 | memcpy(edid, raw_edid, min((1 + raw_edid->extensions) | ||
| 1409 | * EDID_LENGTH, len)); | ||
| 1410 | DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n", | ||
| 1411 | (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"), | ||
| 1412 | raw_edid->width_cm, raw_edid->height_cm); | ||
| 1413 | kfree(raw_edid); | ||
| 1414 | } else { | ||
| 1415 | return -ENODEV; | ||
| 1416 | } | ||
| 1417 | 1405 | ||
| 1418 | return 0; | 1406 | hdata->dvi_mode = !drm_detect_hdmi_monitor(raw_edid); |
| 1407 | DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n", | ||
| 1408 | (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"), | ||
| 1409 | raw_edid->width_cm, raw_edid->height_cm); | ||
| 1410 | |||
| 1411 | return raw_edid; | ||
| 1419 | } | 1412 | } |
| 1420 | 1413 | ||
| 1421 | static int hdmi_v13_check_timing(struct fb_videomode *check_timing) | 1414 | static int hdmi_v13_check_timing(struct fb_videomode *check_timing) |
| @@ -1652,16 +1645,16 @@ static void hdmi_conf_reset(struct hdmi_context *hdata) | |||
| 1652 | 1645 | ||
| 1653 | /* resetting HDMI core */ | 1646 | /* resetting HDMI core */ |
| 1654 | hdmi_reg_writemask(hdata, reg, 0, HDMI_CORE_SW_RSTOUT); | 1647 | hdmi_reg_writemask(hdata, reg, 0, HDMI_CORE_SW_RSTOUT); |
| 1655 | mdelay(10); | 1648 | usleep_range(10000, 12000); |
| 1656 | hdmi_reg_writemask(hdata, reg, ~0, HDMI_CORE_SW_RSTOUT); | 1649 | hdmi_reg_writemask(hdata, reg, ~0, HDMI_CORE_SW_RSTOUT); |
| 1657 | mdelay(10); | 1650 | usleep_range(10000, 12000); |
| 1658 | } | 1651 | } |
| 1659 | 1652 | ||
| 1660 | static void hdmi_conf_init(struct hdmi_context *hdata) | 1653 | static void hdmi_conf_init(struct hdmi_context *hdata) |
| 1661 | { | 1654 | { |
| 1662 | struct hdmi_infoframe infoframe; | 1655 | struct hdmi_infoframe infoframe; |
| 1663 | 1656 | ||
| 1664 | /* disable HPD interrupts */ | 1657 | /* disable HPD interrupts from HDMI IP block, use GPIO instead */ |
| 1665 | hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL | | 1658 | hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL | |
| 1666 | HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG); | 1659 | HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG); |
| 1667 | 1660 | ||
| @@ -1779,7 +1772,7 @@ static void hdmi_v13_timing_apply(struct hdmi_context *hdata) | |||
| 1779 | u32 val = hdmi_reg_read(hdata, HDMI_V13_PHY_STATUS); | 1772 | u32 val = hdmi_reg_read(hdata, HDMI_V13_PHY_STATUS); |
| 1780 | if (val & HDMI_PHY_STATUS_READY) | 1773 | if (val & HDMI_PHY_STATUS_READY) |
| 1781 | break; | 1774 | break; |
| 1782 | mdelay(1); | 1775 | usleep_range(1000, 2000); |
| 1783 | } | 1776 | } |
| 1784 | /* steady state not achieved */ | 1777 | /* steady state not achieved */ |
| 1785 | if (tries == 0) { | 1778 | if (tries == 0) { |
| @@ -1946,7 +1939,7 @@ static void hdmi_v14_timing_apply(struct hdmi_context *hdata) | |||
| 1946 | u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS_0); | 1939 | u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS_0); |
| 1947 | if (val & HDMI_PHY_STATUS_READY) | 1940 | if (val & HDMI_PHY_STATUS_READY) |
| 1948 | break; | 1941 | break; |
| 1949 | mdelay(1); | 1942 | usleep_range(1000, 2000); |
| 1950 | } | 1943 | } |
| 1951 | /* steady state not achieved */ | 1944 | /* steady state not achieved */ |
| 1952 | if (tries == 0) { | 1945 | if (tries == 0) { |
| @@ -1998,9 +1991,9 @@ static void hdmiphy_conf_reset(struct hdmi_context *hdata) | |||
| 1998 | 1991 | ||
| 1999 | /* reset hdmiphy */ | 1992 | /* reset hdmiphy */ |
| 2000 | hdmi_reg_writemask(hdata, reg, ~0, HDMI_PHY_SW_RSTOUT); | 1993 | hdmi_reg_writemask(hdata, reg, ~0, HDMI_PHY_SW_RSTOUT); |
| 2001 | mdelay(10); | 1994 | usleep_range(10000, 12000); |
| 2002 | hdmi_reg_writemask(hdata, reg, 0, HDMI_PHY_SW_RSTOUT); | 1995 | hdmi_reg_writemask(hdata, reg, 0, HDMI_PHY_SW_RSTOUT); |
| 2003 | mdelay(10); | 1996 | usleep_range(10000, 12000); |
| 2004 | } | 1997 | } |
| 2005 | 1998 | ||
| 2006 | static void hdmiphy_poweron(struct hdmi_context *hdata) | 1999 | static void hdmiphy_poweron(struct hdmi_context *hdata) |
| @@ -2048,7 +2041,7 @@ static void hdmiphy_conf_apply(struct hdmi_context *hdata) | |||
| 2048 | return; | 2041 | return; |
| 2049 | } | 2042 | } |
| 2050 | 2043 | ||
| 2051 | mdelay(10); | 2044 | usleep_range(10000, 12000); |
| 2052 | 2045 | ||
| 2053 | /* operation mode */ | 2046 | /* operation mode */ |
| 2054 | operation[0] = 0x1f; | 2047 | operation[0] = 0x1f; |
| @@ -2170,6 +2163,13 @@ static void hdmi_commit(void *ctx) | |||
| 2170 | 2163 | ||
| 2171 | DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); | 2164 | DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); |
| 2172 | 2165 | ||
| 2166 | mutex_lock(&hdata->hdmi_mutex); | ||
| 2167 | if (!hdata->powered) { | ||
| 2168 | mutex_unlock(&hdata->hdmi_mutex); | ||
| 2169 | return; | ||
| 2170 | } | ||
| 2171 | mutex_unlock(&hdata->hdmi_mutex); | ||
| 2172 | |||
| 2173 | hdmi_conf_apply(hdata); | 2173 | hdmi_conf_apply(hdata); |
| 2174 | } | 2174 | } |
| 2175 | 2175 | ||
| @@ -2265,7 +2265,7 @@ static struct exynos_hdmi_ops hdmi_ops = { | |||
| 2265 | .dpms = hdmi_dpms, | 2265 | .dpms = hdmi_dpms, |
| 2266 | }; | 2266 | }; |
| 2267 | 2267 | ||
| 2268 | static irqreturn_t hdmi_external_irq_thread(int irq, void *arg) | 2268 | static irqreturn_t hdmi_irq_thread(int irq, void *arg) |
| 2269 | { | 2269 | { |
| 2270 | struct exynos_drm_hdmi_context *ctx = arg; | 2270 | struct exynos_drm_hdmi_context *ctx = arg; |
| 2271 | struct hdmi_context *hdata = ctx->ctx; | 2271 | struct hdmi_context *hdata = ctx->ctx; |
| @@ -2280,31 +2280,6 @@ static irqreturn_t hdmi_external_irq_thread(int irq, void *arg) | |||
| 2280 | return IRQ_HANDLED; | 2280 | return IRQ_HANDLED; |
| 2281 | } | 2281 | } |
| 2282 | 2282 | ||
| 2283 | static irqreturn_t hdmi_internal_irq_thread(int irq, void *arg) | ||
| 2284 | { | ||
| 2285 | struct exynos_drm_hdmi_context *ctx = arg; | ||
| 2286 | struct hdmi_context *hdata = ctx->ctx; | ||
| 2287 | u32 intc_flag; | ||
| 2288 | |||
| 2289 | intc_flag = hdmi_reg_read(hdata, HDMI_INTC_FLAG); | ||
| 2290 | /* clearing flags for HPD plug/unplug */ | ||
| 2291 | if (intc_flag & HDMI_INTC_FLAG_HPD_UNPLUG) { | ||
| 2292 | DRM_DEBUG_KMS("unplugged\n"); | ||
| 2293 | hdmi_reg_writemask(hdata, HDMI_INTC_FLAG, ~0, | ||
| 2294 | HDMI_INTC_FLAG_HPD_UNPLUG); | ||
| 2295 | } | ||
| 2296 | if (intc_flag & HDMI_INTC_FLAG_HPD_PLUG) { | ||
| 2297 | DRM_DEBUG_KMS("plugged\n"); | ||
| 2298 | hdmi_reg_writemask(hdata, HDMI_INTC_FLAG, ~0, | ||
| 2299 | HDMI_INTC_FLAG_HPD_PLUG); | ||
| 2300 | } | ||
| 2301 | |||
| 2302 | if (ctx->drm_dev) | ||
| 2303 | drm_helper_hpd_irq_event(ctx->drm_dev); | ||
| 2304 | |||
| 2305 | return IRQ_HANDLED; | ||
| 2306 | } | ||
| 2307 | |||
| 2308 | static int hdmi_resources_init(struct hdmi_context *hdata) | 2283 | static int hdmi_resources_init(struct hdmi_context *hdata) |
| 2309 | { | 2284 | { |
| 2310 | struct device *dev = hdata->dev; | 2285 | struct device *dev = hdata->dev; |
| @@ -2555,39 +2530,24 @@ static int hdmi_probe(struct platform_device *pdev) | |||
| 2555 | 2530 | ||
| 2556 | hdata->hdmiphy_port = hdmi_hdmiphy; | 2531 | hdata->hdmiphy_port = hdmi_hdmiphy; |
| 2557 | 2532 | ||
| 2558 | hdata->external_irq = gpio_to_irq(hdata->hpd_gpio); | 2533 | hdata->irq = gpio_to_irq(hdata->hpd_gpio); |
| 2559 | if (hdata->external_irq < 0) { | 2534 | if (hdata->irq < 0) { |
| 2560 | DRM_ERROR("failed to get GPIO external irq\n"); | 2535 | DRM_ERROR("failed to get GPIO irq\n"); |
| 2561 | ret = hdata->external_irq; | 2536 | ret = hdata->irq; |
| 2562 | goto err_hdmiphy; | ||
| 2563 | } | ||
| 2564 | |||
| 2565 | hdata->internal_irq = platform_get_irq(pdev, 0); | ||
| 2566 | if (hdata->internal_irq < 0) { | ||
| 2567 | DRM_ERROR("failed to get platform internal irq\n"); | ||
| 2568 | ret = hdata->internal_irq; | ||
| 2569 | goto err_hdmiphy; | 2537 | goto err_hdmiphy; |
| 2570 | } | 2538 | } |
| 2571 | 2539 | ||
| 2572 | hdata->hpd = gpio_get_value(hdata->hpd_gpio); | 2540 | hdata->hpd = gpio_get_value(hdata->hpd_gpio); |
| 2573 | 2541 | ||
| 2574 | ret = request_threaded_irq(hdata->external_irq, NULL, | 2542 | ret = request_threaded_irq(hdata->irq, NULL, |
| 2575 | hdmi_external_irq_thread, IRQF_TRIGGER_RISING | | 2543 | hdmi_irq_thread, IRQF_TRIGGER_RISING | |
| 2576 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | 2544 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, |
| 2577 | "hdmi_external", drm_hdmi_ctx); | 2545 | "hdmi", drm_hdmi_ctx); |
| 2578 | if (ret) { | 2546 | if (ret) { |
| 2579 | DRM_ERROR("failed to register hdmi external interrupt\n"); | 2547 | DRM_ERROR("failed to register hdmi interrupt\n"); |
| 2580 | goto err_hdmiphy; | 2548 | goto err_hdmiphy; |
| 2581 | } | 2549 | } |
| 2582 | 2550 | ||
| 2583 | ret = request_threaded_irq(hdata->internal_irq, NULL, | ||
| 2584 | hdmi_internal_irq_thread, IRQF_ONESHOT, | ||
| 2585 | "hdmi_internal", drm_hdmi_ctx); | ||
| 2586 | if (ret) { | ||
| 2587 | DRM_ERROR("failed to register hdmi internal interrupt\n"); | ||
| 2588 | goto err_free_irq; | ||
| 2589 | } | ||
| 2590 | |||
| 2591 | /* Attach HDMI Driver to common hdmi. */ | 2551 | /* Attach HDMI Driver to common hdmi. */ |
| 2592 | exynos_hdmi_drv_attach(drm_hdmi_ctx); | 2552 | exynos_hdmi_drv_attach(drm_hdmi_ctx); |
| 2593 | 2553 | ||
| @@ -2598,8 +2558,6 @@ static int hdmi_probe(struct platform_device *pdev) | |||
| 2598 | 2558 | ||
| 2599 | return 0; | 2559 | return 0; |
| 2600 | 2560 | ||
| 2601 | err_free_irq: | ||
| 2602 | free_irq(hdata->external_irq, drm_hdmi_ctx); | ||
| 2603 | err_hdmiphy: | 2561 | err_hdmiphy: |
| 2604 | i2c_del_driver(&hdmiphy_driver); | 2562 | i2c_del_driver(&hdmiphy_driver); |
| 2605 | err_ddc: | 2563 | err_ddc: |
| @@ -2617,8 +2575,7 @@ static int hdmi_remove(struct platform_device *pdev) | |||
| 2617 | 2575 | ||
| 2618 | pm_runtime_disable(dev); | 2576 | pm_runtime_disable(dev); |
| 2619 | 2577 | ||
| 2620 | free_irq(hdata->internal_irq, hdata); | 2578 | free_irq(hdata->irq, hdata); |
| 2621 | free_irq(hdata->external_irq, hdata); | ||
| 2622 | 2579 | ||
| 2623 | 2580 | ||
| 2624 | /* hdmiphy i2c driver */ | 2581 | /* hdmiphy i2c driver */ |
| @@ -2637,8 +2594,7 @@ static int hdmi_suspend(struct device *dev) | |||
| 2637 | 2594 | ||
| 2638 | DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); | 2595 | DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); |
| 2639 | 2596 | ||
| 2640 | disable_irq(hdata->internal_irq); | 2597 | disable_irq(hdata->irq); |
| 2641 | disable_irq(hdata->external_irq); | ||
| 2642 | 2598 | ||
| 2643 | hdata->hpd = false; | 2599 | hdata->hpd = false; |
| 2644 | if (ctx->drm_dev) | 2600 | if (ctx->drm_dev) |
| @@ -2663,8 +2619,7 @@ static int hdmi_resume(struct device *dev) | |||
| 2663 | 2619 | ||
| 2664 | hdata->hpd = gpio_get_value(hdata->hpd_gpio); | 2620 | hdata->hpd = gpio_get_value(hdata->hpd_gpio); |
| 2665 | 2621 | ||
| 2666 | enable_irq(hdata->external_irq); | 2622 | enable_irq(hdata->irq); |
| 2667 | enable_irq(hdata->internal_irq); | ||
| 2668 | 2623 | ||
| 2669 | if (!pm_runtime_suspended(dev)) { | 2624 | if (!pm_runtime_suspended(dev)) { |
| 2670 | DRM_DEBUG_KMS("%s : Already resumed\n", __func__); | 2625 | DRM_DEBUG_KMS("%s : Already resumed\n", __func__); |
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index c187ea33b748..c414584bfbae 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c | |||
| @@ -600,7 +600,7 @@ static void vp_win_reset(struct mixer_context *ctx) | |||
| 600 | /* waiting until VP_SRESET_PROCESSING is 0 */ | 600 | /* waiting until VP_SRESET_PROCESSING is 0 */ |
| 601 | if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING) | 601 | if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING) |
| 602 | break; | 602 | break; |
| 603 | mdelay(10); | 603 | usleep_range(10000, 12000); |
| 604 | } | 604 | } |
| 605 | WARN(tries == 0, "failed to reset Video Processor\n"); | 605 | WARN(tries == 0, "failed to reset Video Processor\n"); |
| 606 | } | 606 | } |
| @@ -776,6 +776,13 @@ static void mixer_win_commit(void *ctx, int win) | |||
| 776 | 776 | ||
| 777 | DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win); | 777 | DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win); |
| 778 | 778 | ||
| 779 | mutex_lock(&mixer_ctx->mixer_mutex); | ||
| 780 | if (!mixer_ctx->powered) { | ||
| 781 | mutex_unlock(&mixer_ctx->mixer_mutex); | ||
| 782 | return; | ||
| 783 | } | ||
| 784 | mutex_unlock(&mixer_ctx->mixer_mutex); | ||
| 785 | |||
| 779 | if (win > 1 && mixer_ctx->vp_enabled) | 786 | if (win > 1 && mixer_ctx->vp_enabled) |
| 780 | vp_video_buffer(mixer_ctx, win); | 787 | vp_video_buffer(mixer_ctx, win); |
| 781 | else | 788 | else |
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index e6a11ca85eaf..9d4a2c2adf0e 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c | |||
| @@ -30,6 +30,7 @@ | |||
| 30 | #include <linux/debugfs.h> | 30 | #include <linux/debugfs.h> |
| 31 | #include <linux/slab.h> | 31 | #include <linux/slab.h> |
| 32 | #include <linux/export.h> | 32 | #include <linux/export.h> |
| 33 | #include <generated/utsrelease.h> | ||
| 33 | #include <drm/drmP.h> | 34 | #include <drm/drmP.h> |
| 34 | #include "intel_drv.h" | 35 | #include "intel_drv.h" |
| 35 | #include "intel_ringbuffer.h" | 36 | #include "intel_ringbuffer.h" |
| @@ -641,6 +642,7 @@ static void i915_ring_error_state(struct seq_file *m, | |||
| 641 | seq_printf(m, "%s command stream:\n", ring_str(ring)); | 642 | seq_printf(m, "%s command stream:\n", ring_str(ring)); |
| 642 | seq_printf(m, " HEAD: 0x%08x\n", error->head[ring]); | 643 | seq_printf(m, " HEAD: 0x%08x\n", error->head[ring]); |
| 643 | seq_printf(m, " TAIL: 0x%08x\n", error->tail[ring]); | 644 | seq_printf(m, " TAIL: 0x%08x\n", error->tail[ring]); |
| 645 | seq_printf(m, " CTL: 0x%08x\n", error->ctl[ring]); | ||
| 644 | seq_printf(m, " ACTHD: 0x%08x\n", error->acthd[ring]); | 646 | seq_printf(m, " ACTHD: 0x%08x\n", error->acthd[ring]); |
| 645 | seq_printf(m, " IPEIR: 0x%08x\n", error->ipeir[ring]); | 647 | seq_printf(m, " IPEIR: 0x%08x\n", error->ipeir[ring]); |
| 646 | seq_printf(m, " IPEHR: 0x%08x\n", error->ipehr[ring]); | 648 | seq_printf(m, " IPEHR: 0x%08x\n", error->ipehr[ring]); |
| @@ -689,10 +691,13 @@ static int i915_error_state(struct seq_file *m, void *unused) | |||
| 689 | 691 | ||
| 690 | seq_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec, | 692 | seq_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec, |
| 691 | error->time.tv_usec); | 693 | error->time.tv_usec); |
| 694 | seq_printf(m, "Kernel: " UTS_RELEASE); | ||
| 692 | seq_printf(m, "PCI ID: 0x%04x\n", dev->pci_device); | 695 | seq_printf(m, "PCI ID: 0x%04x\n", dev->pci_device); |
| 693 | seq_printf(m, "EIR: 0x%08x\n", error->eir); | 696 | seq_printf(m, "EIR: 0x%08x\n", error->eir); |
| 694 | seq_printf(m, "IER: 0x%08x\n", error->ier); | 697 | seq_printf(m, "IER: 0x%08x\n", error->ier); |
| 695 | seq_printf(m, "PGTBL_ER: 0x%08x\n", error->pgtbl_er); | 698 | seq_printf(m, "PGTBL_ER: 0x%08x\n", error->pgtbl_er); |
| 699 | seq_printf(m, "FORCEWAKE: 0x%08x\n", error->forcewake); | ||
| 700 | seq_printf(m, "DERRMR: 0x%08x\n", error->derrmr); | ||
| 696 | seq_printf(m, "CCID: 0x%08x\n", error->ccid); | 701 | seq_printf(m, "CCID: 0x%08x\n", error->ccid); |
| 697 | 702 | ||
| 698 | for (i = 0; i < dev_priv->num_fence_regs; i++) | 703 | 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..59afb7eb6db6 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. |
| @@ -531,6 +533,7 @@ | |||
| 531 | #define MI_MODE 0x0209c | 533 | #define MI_MODE 0x0209c |
| 532 | # define VS_TIMER_DISPATCH (1 << 6) | 534 | # define VS_TIMER_DISPATCH (1 << 6) |
| 533 | # define MI_FLUSH_ENABLE (1 << 12) | 535 | # define MI_FLUSH_ENABLE (1 << 12) |
| 536 | # define ASYNC_FLIP_PERF_DISABLE (1 << 14) | ||
| 534 | 537 | ||
| 535 | #define GEN6_GT_MODE 0x20d0 | 538 | #define GEN6_GT_MODE 0x20d0 |
| 536 | #define GEN6_GT_MODE_HI (1 << 9) | 539 | #define GEN6_GT_MODE_HI (1 << 9) |
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_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index ae253e04c391..42ff97d667d2 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c | |||
| @@ -505,13 +505,25 @@ static int init_render_ring(struct intel_ring_buffer *ring) | |||
| 505 | struct drm_i915_private *dev_priv = dev->dev_private; | 505 | struct drm_i915_private *dev_priv = dev->dev_private; |
| 506 | int ret = init_ring_common(ring); | 506 | int ret = init_ring_common(ring); |
| 507 | 507 | ||
| 508 | if (INTEL_INFO(dev)->gen > 3) { | 508 | if (INTEL_INFO(dev)->gen > 3) |
| 509 | I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(VS_TIMER_DISPATCH)); | 509 | I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(VS_TIMER_DISPATCH)); |
| 510 | if (IS_GEN7(dev)) | 510 | |
| 511 | I915_WRITE(GFX_MODE_GEN7, | 511 | /* We need to disable the AsyncFlip performance optimisations in order |
| 512 | _MASKED_BIT_DISABLE(GFX_TLB_INVALIDATE_ALWAYS) | | 512 | * to use MI_WAIT_FOR_EVENT within the CS. It should already be |
| 513 | _MASKED_BIT_ENABLE(GFX_REPLAY_MODE)); | 513 | * programmed to '1' on all products. |
| 514 | } | 514 | */ |
| 515 | if (INTEL_INFO(dev)->gen >= 6) | ||
| 516 | I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(ASYNC_FLIP_PERF_DISABLE)); | ||
| 517 | |||
| 518 | /* Required for the hardware to program scanline values for waiting */ | ||
| 519 | if (INTEL_INFO(dev)->gen == 6) | ||
| 520 | I915_WRITE(GFX_MODE, | ||
| 521 | _MASKED_BIT_ENABLE(GFX_TLB_INVALIDATE_ALWAYS)); | ||
| 522 | |||
| 523 | if (IS_GEN7(dev)) | ||
| 524 | I915_WRITE(GFX_MODE_GEN7, | ||
| 525 | _MASKED_BIT_DISABLE(GFX_TLB_INVALIDATE_ALWAYS) | | ||
| 526 | _MASKED_BIT_ENABLE(GFX_REPLAY_MODE)); | ||
| 515 | 527 | ||
| 516 | if (INTEL_INFO(dev)->gen >= 5) { | 528 | if (INTEL_INFO(dev)->gen >= 5) { |
| 517 | ret = init_pipe_control(ring); | 529 | ret = init_pipe_control(ring); |
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..835992d8d067 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c | |||
| @@ -1216,7 +1216,7 @@ void cayman_dma_stop(struct radeon_device *rdev) | |||
| 1216 | int cayman_dma_resume(struct radeon_device *rdev) | 1216 | int cayman_dma_resume(struct radeon_device *rdev) |
| 1217 | { | 1217 | { |
| 1218 | struct radeon_ring *ring; | 1218 | struct radeon_ring *ring; |
| 1219 | u32 rb_cntl, dma_cntl; | 1219 | u32 rb_cntl, dma_cntl, ib_cntl; |
| 1220 | u32 rb_bufsz; | 1220 | u32 rb_bufsz; |
| 1221 | u32 reg_offset, wb_offset; | 1221 | u32 reg_offset, wb_offset; |
| 1222 | int i, r; | 1222 | int i, r; |
| @@ -1265,7 +1265,11 @@ int cayman_dma_resume(struct radeon_device *rdev) | |||
| 1265 | WREG32(DMA_RB_BASE + reg_offset, ring->gpu_addr >> 8); | 1265 | WREG32(DMA_RB_BASE + reg_offset, ring->gpu_addr >> 8); |
| 1266 | 1266 | ||
| 1267 | /* enable DMA IBs */ | 1267 | /* enable DMA IBs */ |
| 1268 | WREG32(DMA_IB_CNTL + reg_offset, DMA_IB_ENABLE | CMD_VMID_FORCE); | 1268 | ib_cntl = DMA_IB_ENABLE | CMD_VMID_FORCE; |
| 1269 | #ifdef __BIG_ENDIAN | ||
| 1270 | ib_cntl |= DMA_IB_SWAP_ENABLE; | ||
| 1271 | #endif | ||
| 1272 | WREG32(DMA_IB_CNTL + reg_offset, ib_cntl); | ||
| 1269 | 1273 | ||
| 1270 | dma_cntl = RREG32(DMA_CNTL + reg_offset); | 1274 | dma_cntl = RREG32(DMA_CNTL + reg_offset); |
| 1271 | dma_cntl &= ~CTXEMPTY_INT_ENABLE; | 1275 | dma_cntl &= ~CTXEMPTY_INT_ENABLE; |
| @@ -1409,6 +1413,12 @@ static int cayman_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask) | |||
| 1409 | { | 1413 | { |
| 1410 | struct evergreen_mc_save save; | 1414 | struct evergreen_mc_save save; |
| 1411 | 1415 | ||
| 1416 | if (!(RREG32(GRBM_STATUS) & GUI_ACTIVE)) | ||
| 1417 | reset_mask &= ~(RADEON_RESET_GFX | RADEON_RESET_COMPUTE); | ||
| 1418 | |||
| 1419 | if (RREG32(DMA_STATUS_REG) & DMA_IDLE) | ||
| 1420 | reset_mask &= ~RADEON_RESET_DMA; | ||
| 1421 | |||
| 1412 | if (reset_mask == 0) | 1422 | if (reset_mask == 0) |
| 1413 | return 0; | 1423 | return 0; |
| 1414 | 1424 | ||
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 537e259b3837..bc2540b17c5e 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 | ||
| @@ -2307,7 +2313,7 @@ void r600_dma_stop(struct radeon_device *rdev) | |||
| 2307 | int r600_dma_resume(struct radeon_device *rdev) | 2313 | int r600_dma_resume(struct radeon_device *rdev) |
| 2308 | { | 2314 | { |
| 2309 | struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX]; | 2315 | struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX]; |
| 2310 | u32 rb_cntl, dma_cntl; | 2316 | u32 rb_cntl, dma_cntl, ib_cntl; |
| 2311 | u32 rb_bufsz; | 2317 | u32 rb_bufsz; |
| 2312 | int r; | 2318 | int r; |
| 2313 | 2319 | ||
| @@ -2347,7 +2353,11 @@ int r600_dma_resume(struct radeon_device *rdev) | |||
| 2347 | WREG32(DMA_RB_BASE, ring->gpu_addr >> 8); | 2353 | WREG32(DMA_RB_BASE, ring->gpu_addr >> 8); |
| 2348 | 2354 | ||
| 2349 | /* enable DMA IBs */ | 2355 | /* enable DMA IBs */ |
| 2350 | WREG32(DMA_IB_CNTL, DMA_IB_ENABLE); | 2356 | ib_cntl = DMA_IB_ENABLE; |
| 2357 | #ifdef __BIG_ENDIAN | ||
| 2358 | ib_cntl |= DMA_IB_SWAP_ENABLE; | ||
| 2359 | #endif | ||
| 2360 | WREG32(DMA_IB_CNTL, ib_cntl); | ||
| 2351 | 2361 | ||
| 2352 | dma_cntl = RREG32(DMA_CNTL); | 2362 | dma_cntl = RREG32(DMA_CNTL); |
| 2353 | dma_cntl &= ~CTXEMPTY_INT_ENABLE; | 2363 | dma_cntl &= ~CTXEMPTY_INT_ENABLE; |
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..5407459e56d2 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c | |||
| @@ -279,13 +279,15 @@ 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 | p->chunks[p->chunk_ib_idx].kpage[0] = NULL; | ||
| 290 | p->chunks[p->chunk_ib_idx].kpage[1] = NULL; | ||
| 289 | return -ENOMEM; | 291 | return -ENOMEM; |
| 290 | } | 292 | } |
| 291 | } | 293 | } |
| @@ -583,7 +585,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]; | 585 | struct radeon_cs_chunk *ibc = &p->chunks[p->chunk_ib_idx]; |
| 584 | int i; | 586 | int i; |
| 585 | int size = PAGE_SIZE; | 587 | int size = PAGE_SIZE; |
| 586 | bool copy1 = (p->rdev->flags & RADEON_IS_AGP) ? false : true; | 588 | bool copy1 = (p->rdev && (p->rdev->flags & RADEON_IS_AGP)) ? |
| 589 | false : true; | ||
| 587 | 590 | ||
| 588 | for (i = ibc->last_copied_page + 1; i < pg_idx; i++) { | 591 | for (i = ibc->last_copied_page + 1; i < pg_idx; i++) { |
| 589 | if (DRM_COPY_FROM_USER(p->ib.ptr + (i * (PAGE_SIZE/4)), | 592 | if (DRM_COPY_FROM_USER(p->ib.ptr + (i * (PAGE_SIZE/4)), |
diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c index ad6df625e8b8..0d67674b64b1 100644 --- a/drivers/gpu/drm/radeon/radeon_cursor.c +++ b/drivers/gpu/drm/radeon/radeon_cursor.c | |||
| @@ -241,7 +241,8 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc, | |||
| 241 | y = 0; | 241 | y = 0; |
| 242 | } | 242 | } |
| 243 | 243 | ||
| 244 | if (ASIC_IS_AVIVO(rdev)) { | 244 | /* fixed on DCE6 and newer */ |
| 245 | if (ASIC_IS_AVIVO(rdev) && !ASIC_IS_DCE6(rdev)) { | ||
| 245 | int i = 0; | 246 | int i = 0; |
| 246 | struct drm_crtc *crtc_p; | 247 | struct drm_crtc *crtc_p; |
| 247 | 248 | ||
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index edfc54e41842..0d6562bb0c93 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c | |||
| @@ -429,7 +429,8 @@ bool radeon_card_posted(struct radeon_device *rdev) | |||
| 429 | { | 429 | { |
| 430 | uint32_t reg; | 430 | uint32_t reg; |
| 431 | 431 | ||
| 432 | if (efi_enabled && rdev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE) | 432 | if (efi_enabled(EFI_BOOT) && |
| 433 | rdev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE) | ||
| 433 | return false; | 434 | return false; |
| 434 | 435 | ||
| 435 | /* first check CRTCs */ | 436 | /* first check CRTCs */ |
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 1da2386d7cf7..ff3def784619 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c | |||
| @@ -1122,7 +1122,7 @@ radeon_user_framebuffer_create(struct drm_device *dev, | |||
| 1122 | if (ret) { | 1122 | if (ret) { |
| 1123 | kfree(radeon_fb); | 1123 | kfree(radeon_fb); |
| 1124 | drm_gem_object_unreference_unlocked(obj); | 1124 | drm_gem_object_unreference_unlocked(obj); |
| 1125 | return NULL; | 1125 | return ERR_PTR(ret); |
| 1126 | } | 1126 | } |
| 1127 | 1127 | ||
| 1128 | return &radeon_fb->base; | 1128 | return &radeon_fb->base; |
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/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 656b2e3334a6..56813f967c8f 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c | |||
| @@ -12,8 +12,7 @@ | |||
| 12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
| 13 | #include <linux/of.h> | 13 | #include <linux/of.h> |
| 14 | #include <linux/platform_device.h> | 14 | #include <linux/platform_device.h> |
| 15 | 15 | #include <linux/clk/tegra.h> | |
| 16 | #include <mach/clk.h> | ||
| 17 | 16 | ||
| 18 | #include "drm.h" | 17 | #include "drm.h" |
| 19 | #include "dc.h" | 18 | #include "dc.h" |
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 3a503c9e4686..d980dc75788c 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c | |||
| @@ -11,7 +11,6 @@ | |||
| 11 | #include <linux/of_address.h> | 11 | #include <linux/of_address.h> |
| 12 | #include <linux/of_platform.h> | 12 | #include <linux/of_platform.h> |
| 13 | 13 | ||
| 14 | #include <mach/clk.h> | ||
| 15 | #include <linux/dma-mapping.h> | 14 | #include <linux/dma-mapping.h> |
| 16 | #include <asm/dma-iommu.h> | 15 | #include <asm/dma-iommu.h> |
| 17 | 16 | ||
diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index e060c7e6434d..92ad276cc5e0 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c | |||
| @@ -14,8 +14,7 @@ | |||
| 14 | #include <linux/of.h> | 14 | #include <linux/of.h> |
| 15 | #include <linux/platform_device.h> | 15 | #include <linux/platform_device.h> |
| 16 | #include <linux/regulator/consumer.h> | 16 | #include <linux/regulator/consumer.h> |
| 17 | 17 | #include <linux/clk/tegra.h> | |
| 18 | #include <mach/clk.h> | ||
| 19 | 18 | ||
| 20 | #include "hdmi.h" | 19 | #include "hdmi.h" |
| 21 | #include "drm.h" | 20 | #include "drm.h" |
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/hid/hid-ids.h b/drivers/hid/hid-ids.h index 4dfa605e2d14..34e25471aeaa 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h | |||
| @@ -306,6 +306,9 @@ | |||
| 306 | #define USB_VENDOR_ID_EZKEY 0x0518 | 306 | #define USB_VENDOR_ID_EZKEY 0x0518 |
| 307 | #define USB_DEVICE_ID_BTC_8193 0x0002 | 307 | #define USB_DEVICE_ID_BTC_8193 0x0002 |
| 308 | 308 | ||
| 309 | #define USB_VENDOR_ID_FORMOSA 0x147a | ||
| 310 | #define USB_DEVICE_ID_FORMOSA_IR_RECEIVER 0xe03e | ||
| 311 | |||
| 309 | #define USB_VENDOR_ID_FREESCALE 0x15A2 | 312 | #define USB_VENDOR_ID_FREESCALE 0x15A2 |
| 310 | #define USB_DEVICE_ID_FREESCALE_MX28 0x004F | 313 | #define USB_DEVICE_ID_FREESCALE_MX28 0x004F |
| 311 | 314 | ||
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index 12e4fdc810bf..e766b5614ef5 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c | |||
| @@ -540,13 +540,24 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf, | |||
| 540 | { | 540 | { |
| 541 | struct i2c_client *client = hid->driver_data; | 541 | struct i2c_client *client = hid->driver_data; |
| 542 | int report_id = buf[0]; | 542 | int report_id = buf[0]; |
| 543 | int ret; | ||
| 543 | 544 | ||
| 544 | if (report_type == HID_INPUT_REPORT) | 545 | if (report_type == HID_INPUT_REPORT) |
| 545 | return -EINVAL; | 546 | return -EINVAL; |
| 546 | 547 | ||
| 547 | return i2c_hid_set_report(client, | 548 | if (report_id) { |
| 549 | buf++; | ||
| 550 | count--; | ||
| 551 | } | ||
| 552 | |||
| 553 | ret = i2c_hid_set_report(client, | ||
| 548 | report_type == HID_FEATURE_REPORT ? 0x03 : 0x02, | 554 | report_type == HID_FEATURE_REPORT ? 0x03 : 0x02, |
| 549 | report_id, buf, count); | 555 | report_id, buf, count); |
| 556 | |||
| 557 | if (report_id && ret >= 0) | ||
| 558 | ret++; /* add report_id to the number of transfered bytes */ | ||
| 559 | |||
| 560 | return ret; | ||
| 550 | } | 561 | } |
| 551 | 562 | ||
| 552 | static int i2c_hid_parse(struct hid_device *hid) | 563 | static int i2c_hid_parse(struct hid_device *hid) |
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index ac9e35228254..e0e6abf1cd3b 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c | |||
| @@ -70,6 +70,7 @@ static const struct hid_blacklist { | |||
| 70 | { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_AXIS_295, HID_QUIRK_NOGET }, | 70 | { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_AXIS_295, HID_QUIRK_NOGET }, |
| 71 | { USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET }, | 71 | { USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET }, |
| 72 | { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET }, | 72 | { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET }, |
| 73 | { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS }, | ||
| 73 | { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET }, | 74 | { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET }, |
| 74 | { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, | 75 | { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, |
| 75 | { USB_VENDOR_ID_NOVATEK, USB_DEVICE_ID_NOVATEK_MOUSE, HID_QUIRK_NO_INIT_REPORTS }, | 76 | { USB_VENDOR_ID_NOVATEK, USB_DEVICE_ID_NOVATEK_MOUSE, HID_QUIRK_NO_INIT_REPORTS }, |
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/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 7b38877ffec1..c7aca35e38fd 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c | |||
| @@ -29,11 +29,10 @@ | |||
| 29 | #include <linux/of_i2c.h> | 29 | #include <linux/of_i2c.h> |
| 30 | #include <linux/of_device.h> | 30 | #include <linux/of_device.h> |
| 31 | #include <linux/module.h> | 31 | #include <linux/module.h> |
| 32 | #include <linux/clk/tegra.h> | ||
| 32 | 33 | ||
| 33 | #include <asm/unaligned.h> | 34 | #include <asm/unaligned.h> |
| 34 | 35 | ||
| 35 | #include <mach/clk.h> | ||
| 36 | |||
| 37 | #define TEGRA_I2C_TIMEOUT (msecs_to_jiffies(1000)) | 36 | #define TEGRA_I2C_TIMEOUT (msecs_to_jiffies(1000)) |
| 38 | #define BYTES_PER_FIFO_WORD 4 | 37 | #define BYTES_PER_FIFO_WORD 4 |
| 39 | 38 | ||
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/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c index c76f96872d31..54ac1dc7d477 100644 --- a/drivers/input/keyboard/tegra-kbc.c +++ b/drivers/input/keyboard/tegra-kbc.c | |||
| @@ -30,7 +30,7 @@ | |||
| 30 | #include <linux/clk.h> | 30 | #include <linux/clk.h> |
| 31 | #include <linux/slab.h> | 31 | #include <linux/slab.h> |
| 32 | #include <linux/input/tegra_kbc.h> | 32 | #include <linux/input/tegra_kbc.h> |
| 33 | #include <mach/clk.h> | 33 | #include <linux/clk/tegra.h> |
| 34 | 34 | ||
| 35 | #define KBC_MAX_DEBOUNCE_CNT 0x3ffu | 35 | #define KBC_MAX_DEBOUNCE_CNT 0x3ffu |
| 36 | 36 | ||
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index 81837b0710a9..faf10ba1ed9a 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c | |||
| @@ -975,6 +975,38 @@ static void __init free_iommu_all(void) | |||
| 975 | } | 975 | } |
| 976 | 976 | ||
| 977 | /* | 977 | /* |
| 978 | * Family15h Model 10h-1fh erratum 746 (IOMMU Logging May Stall Translations) | ||
| 979 | * Workaround: | ||
| 980 | * BIOS should disable L2B micellaneous clock gating by setting | ||
| 981 | * L2_L2B_CK_GATE_CONTROL[CKGateL2BMiscDisable](D0F2xF4_x90[2]) = 1b | ||
| 982 | */ | ||
| 983 | static void __init amd_iommu_erratum_746_workaround(struct amd_iommu *iommu) | ||
| 984 | { | ||
| 985 | u32 value; | ||
| 986 | |||
| 987 | if ((boot_cpu_data.x86 != 0x15) || | ||
| 988 | (boot_cpu_data.x86_model < 0x10) || | ||
| 989 | (boot_cpu_data.x86_model > 0x1f)) | ||
| 990 | return; | ||
| 991 | |||
| 992 | pci_write_config_dword(iommu->dev, 0xf0, 0x90); | ||
| 993 | pci_read_config_dword(iommu->dev, 0xf4, &value); | ||
| 994 | |||
| 995 | if (value & BIT(2)) | ||
| 996 | return; | ||
| 997 | |||
| 998 | /* Select NB indirect register 0x90 and enable writing */ | ||
| 999 | pci_write_config_dword(iommu->dev, 0xf0, 0x90 | (1 << 8)); | ||
| 1000 | |||
| 1001 | pci_write_config_dword(iommu->dev, 0xf4, value | 0x4); | ||
| 1002 | pr_info("AMD-Vi: Applying erratum 746 workaround for IOMMU at %s\n", | ||
| 1003 | dev_name(&iommu->dev->dev)); | ||
| 1004 | |||
| 1005 | /* Clear the enable writing bit */ | ||
| 1006 | pci_write_config_dword(iommu->dev, 0xf0, 0x90); | ||
| 1007 | } | ||
| 1008 | |||
| 1009 | /* | ||
| 978 | * This function clues the initialization function for one IOMMU | 1010 | * This function clues the initialization function for one IOMMU |
| 979 | * together and also allocates the command buffer and programs the | 1011 | * together and also allocates the command buffer and programs the |
| 980 | * hardware. It does NOT enable the IOMMU. This is done afterwards. | 1012 | * hardware. It does NOT enable the IOMMU. This is done afterwards. |
| @@ -1172,6 +1204,8 @@ static int iommu_init_pci(struct amd_iommu *iommu) | |||
| 1172 | iommu->stored_l2[i] = iommu_read_l2(iommu, i); | 1204 | iommu->stored_l2[i] = iommu_read_l2(iommu, i); |
| 1173 | } | 1205 | } |
| 1174 | 1206 | ||
| 1207 | amd_iommu_erratum_746_workaround(iommu); | ||
| 1208 | |||
| 1175 | return pci_enable_device(iommu->dev); | 1209 | return pci_enable_device(iommu->dev); |
| 1176 | } | 1210 | } |
| 1177 | 1211 | ||
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index b9d091157884..eca28014ef3e 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c | |||
| @@ -4234,6 +4234,21 @@ static struct iommu_ops intel_iommu_ops = { | |||
| 4234 | .pgsize_bitmap = INTEL_IOMMU_PGSIZES, | 4234 | .pgsize_bitmap = INTEL_IOMMU_PGSIZES, |
| 4235 | }; | 4235 | }; |
| 4236 | 4236 | ||
| 4237 | static void quirk_iommu_g4x_gfx(struct pci_dev *dev) | ||
| 4238 | { | ||
| 4239 | /* G4x/GM45 integrated gfx dmar support is totally busted. */ | ||
| 4240 | printk(KERN_INFO "DMAR: Disabling IOMMU for graphics on this chipset\n"); | ||
| 4241 | dmar_map_gfx = 0; | ||
| 4242 | } | ||
| 4243 | |||
| 4244 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_g4x_gfx); | ||
| 4245 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_g4x_gfx); | ||
| 4246 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e10, quirk_iommu_g4x_gfx); | ||
| 4247 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e20, quirk_iommu_g4x_gfx); | ||
| 4248 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e30, quirk_iommu_g4x_gfx); | ||
| 4249 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e40, quirk_iommu_g4x_gfx); | ||
| 4250 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e90, quirk_iommu_g4x_gfx); | ||
| 4251 | |||
| 4237 | static void quirk_iommu_rwbf(struct pci_dev *dev) | 4252 | static void quirk_iommu_rwbf(struct pci_dev *dev) |
| 4238 | { | 4253 | { |
| 4239 | /* | 4254 | /* |
| @@ -4242,12 +4257,6 @@ static void quirk_iommu_rwbf(struct pci_dev *dev) | |||
| 4242 | */ | 4257 | */ |
| 4243 | printk(KERN_INFO "DMAR: Forcing write-buffer flush capability\n"); | 4258 | printk(KERN_INFO "DMAR: Forcing write-buffer flush capability\n"); |
| 4244 | rwbf_quirk = 1; | 4259 | rwbf_quirk = 1; |
| 4245 | |||
| 4246 | /* https://bugzilla.redhat.com/show_bug.cgi?id=538163 */ | ||
| 4247 | if (dev->revision == 0x07) { | ||
| 4248 | printk(KERN_INFO "DMAR: Disabling IOMMU for graphics on this chipset\n"); | ||
| 4249 | dmar_map_gfx = 0; | ||
| 4250 | } | ||
| 4251 | } | 4260 | } |
| 4252 | 4261 | ||
| 4253 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_rwbf); | 4262 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_rwbf); |
diff --git a/drivers/isdn/gigaset/capi.c b/drivers/isdn/gigaset/capi.c index 68452b768da2..03a0a01a4054 100644 --- a/drivers/isdn/gigaset/capi.c +++ b/drivers/isdn/gigaset/capi.c | |||
| @@ -248,6 +248,8 @@ static inline void dump_rawmsg(enum debuglevel level, const char *tag, | |||
| 248 | CAPIMSG_APPID(data), CAPIMSG_MSGID(data), l, | 248 | CAPIMSG_APPID(data), CAPIMSG_MSGID(data), l, |
| 249 | CAPIMSG_CONTROL(data)); | 249 | CAPIMSG_CONTROL(data)); |
| 250 | l -= 12; | 250 | l -= 12; |
| 251 | if (l <= 0) | ||
| 252 | return; | ||
| 251 | dbgline = kmalloc(3 * l, GFP_ATOMIC); | 253 | dbgline = kmalloc(3 * l, GFP_ATOMIC); |
| 252 | if (!dbgline) | 254 | if (!dbgline) |
| 253 | return; | 255 | return; |
diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c index 3d8984edeff7..9e58dbd8d8cb 100644 --- a/drivers/md/dm-raid.c +++ b/drivers/md/dm-raid.c | |||
| @@ -340,24 +340,22 @@ static int validate_region_size(struct raid_set *rs, unsigned long region_size) | |||
| 340 | } | 340 | } |
| 341 | 341 | ||
| 342 | /* | 342 | /* |
| 343 | * validate_rebuild_devices | 343 | * validate_raid_redundancy |
| 344 | * @rs | 344 | * @rs |
| 345 | * | 345 | * |
| 346 | * Determine if the devices specified for rebuild can result in a valid | 346 | * Determine if there are enough devices in the array that haven't |
| 347 | * usable array that is capable of rebuilding the given devices. | 347 | * failed (or are being rebuilt) to form a usable array. |
| 348 | * | 348 | * |
| 349 | * Returns: 0 on success, -EINVAL on failure. | 349 | * Returns: 0 on success, -EINVAL on failure. |
| 350 | */ | 350 | */ |
| 351 | static int validate_rebuild_devices(struct raid_set *rs) | 351 | static int validate_raid_redundancy(struct raid_set *rs) |
| 352 | { | 352 | { |
| 353 | unsigned i, rebuild_cnt = 0; | 353 | unsigned i, rebuild_cnt = 0; |
| 354 | unsigned rebuilds_per_group, copies, d; | 354 | unsigned rebuilds_per_group, copies, d; |
| 355 | 355 | ||
| 356 | if (!(rs->print_flags & DMPF_REBUILD)) | ||
| 357 | return 0; | ||
| 358 | |||
| 359 | for (i = 0; i < rs->md.raid_disks; i++) | 356 | for (i = 0; i < rs->md.raid_disks; i++) |
| 360 | if (!test_bit(In_sync, &rs->dev[i].rdev.flags)) | 357 | if (!test_bit(In_sync, &rs->dev[i].rdev.flags) || |
| 358 | !rs->dev[i].rdev.sb_page) | ||
| 361 | rebuild_cnt++; | 359 | rebuild_cnt++; |
| 362 | 360 | ||
| 363 | switch (rs->raid_type->level) { | 361 | switch (rs->raid_type->level) { |
| @@ -393,27 +391,24 @@ static int validate_rebuild_devices(struct raid_set *rs) | |||
| 393 | * A A B B C | 391 | * A A B B C |
| 394 | * C D D E E | 392 | * C D D E E |
| 395 | */ | 393 | */ |
| 396 | rebuilds_per_group = 0; | ||
| 397 | for (i = 0; i < rs->md.raid_disks * copies; i++) { | 394 | for (i = 0; i < rs->md.raid_disks * copies; i++) { |
| 395 | if (!(i % copies)) | ||
| 396 | rebuilds_per_group = 0; | ||
| 398 | d = i % rs->md.raid_disks; | 397 | d = i % rs->md.raid_disks; |
| 399 | if (!test_bit(In_sync, &rs->dev[d].rdev.flags) && | 398 | if ((!rs->dev[d].rdev.sb_page || |
| 399 | !test_bit(In_sync, &rs->dev[d].rdev.flags)) && | ||
| 400 | (++rebuilds_per_group >= copies)) | 400 | (++rebuilds_per_group >= copies)) |
| 401 | goto too_many; | 401 | goto too_many; |
| 402 | if (!((i + 1) % copies)) | ||
| 403 | rebuilds_per_group = 0; | ||
| 404 | } | 402 | } |
| 405 | break; | 403 | break; |
| 406 | default: | 404 | default: |
| 407 | DMERR("The rebuild parameter is not supported for %s", | 405 | if (rebuild_cnt) |
| 408 | rs->raid_type->name); | 406 | return -EINVAL; |
| 409 | rs->ti->error = "Rebuild not supported for this RAID type"; | ||
| 410 | return -EINVAL; | ||
| 411 | } | 407 | } |
| 412 | 408 | ||
| 413 | return 0; | 409 | return 0; |
| 414 | 410 | ||
| 415 | too_many: | 411 | too_many: |
| 416 | rs->ti->error = "Too many rebuild devices specified"; | ||
| 417 | return -EINVAL; | 412 | return -EINVAL; |
| 418 | } | 413 | } |
| 419 | 414 | ||
| @@ -664,9 +659,6 @@ static int parse_raid_params(struct raid_set *rs, char **argv, | |||
| 664 | } | 659 | } |
| 665 | rs->md.dev_sectors = sectors_per_dev; | 660 | rs->md.dev_sectors = sectors_per_dev; |
| 666 | 661 | ||
| 667 | if (validate_rebuild_devices(rs)) | ||
| 668 | return -EINVAL; | ||
| 669 | |||
| 670 | /* Assume there are no metadata devices until the drives are parsed */ | 662 | /* Assume there are no metadata devices until the drives are parsed */ |
| 671 | rs->md.persistent = 0; | 663 | rs->md.persistent = 0; |
| 672 | rs->md.external = 1; | 664 | rs->md.external = 1; |
| @@ -995,28 +987,10 @@ static int super_validate(struct mddev *mddev, struct md_rdev *rdev) | |||
| 995 | static int analyse_superblocks(struct dm_target *ti, struct raid_set *rs) | 987 | static int analyse_superblocks(struct dm_target *ti, struct raid_set *rs) |
| 996 | { | 988 | { |
| 997 | int ret; | 989 | int ret; |
| 998 | unsigned redundancy = 0; | ||
| 999 | struct raid_dev *dev; | 990 | struct raid_dev *dev; |
| 1000 | struct md_rdev *rdev, *tmp, *freshest; | 991 | struct md_rdev *rdev, *tmp, *freshest; |
| 1001 | struct mddev *mddev = &rs->md; | 992 | struct mddev *mddev = &rs->md; |
| 1002 | 993 | ||
| 1003 | switch (rs->raid_type->level) { | ||
| 1004 | case 1: | ||
| 1005 | redundancy = rs->md.raid_disks - 1; | ||
| 1006 | break; | ||
| 1007 | case 4: | ||
| 1008 | case 5: | ||
| 1009 | case 6: | ||
| 1010 | redundancy = rs->raid_type->parity_devs; | ||
| 1011 | break; | ||
| 1012 | case 10: | ||
| 1013 | redundancy = raid10_md_layout_to_copies(mddev->layout) - 1; | ||
| 1014 | break; | ||
| 1015 | default: | ||
| 1016 | ti->error = "Unknown RAID type"; | ||
| 1017 | return -EINVAL; | ||
| 1018 | } | ||
| 1019 | |||
| 1020 | freshest = NULL; | 994 | freshest = NULL; |
| 1021 | rdev_for_each_safe(rdev, tmp, mddev) { | 995 | rdev_for_each_safe(rdev, tmp, mddev) { |
| 1022 | /* | 996 | /* |
| @@ -1045,44 +1019,43 @@ static int analyse_superblocks(struct dm_target *ti, struct raid_set *rs) | |||
| 1045 | break; | 1019 | break; |
| 1046 | default: | 1020 | default: |
| 1047 | dev = container_of(rdev, struct raid_dev, rdev); | 1021 | dev = container_of(rdev, struct raid_dev, rdev); |
| 1048 | if (redundancy--) { | 1022 | if (dev->meta_dev) |
| 1049 | if (dev->meta_dev) | 1023 | dm_put_device(ti, dev->meta_dev); |
| 1050 | dm_put_device(ti, dev->meta_dev); | ||
| 1051 | |||
| 1052 | dev->meta_dev = NULL; | ||
| 1053 | rdev->meta_bdev = NULL; | ||
| 1054 | 1024 | ||
| 1055 | if (rdev->sb_page) | 1025 | dev->meta_dev = NULL; |
| 1056 | put_page(rdev->sb_page); | 1026 | rdev->meta_bdev = NULL; |
| 1057 | 1027 | ||
| 1058 | rdev->sb_page = NULL; | 1028 | if (rdev->sb_page) |
| 1029 | put_page(rdev->sb_page); | ||
| 1059 | 1030 | ||
| 1060 | rdev->sb_loaded = 0; | 1031 | rdev->sb_page = NULL; |
| 1061 | 1032 | ||
| 1062 | /* | 1033 | rdev->sb_loaded = 0; |
| 1063 | * We might be able to salvage the data device | ||
| 1064 | * even though the meta device has failed. For | ||
| 1065 | * now, we behave as though '- -' had been | ||
| 1066 | * set for this device in the table. | ||
| 1067 | */ | ||
| 1068 | if (dev->data_dev) | ||
| 1069 | dm_put_device(ti, dev->data_dev); | ||
| 1070 | 1034 | ||
| 1071 | dev->data_dev = NULL; | 1035 | /* |
| 1072 | rdev->bdev = NULL; | 1036 | * We might be able to salvage the data device |
| 1037 | * even though the meta device has failed. For | ||
| 1038 | * now, we behave as though '- -' had been | ||
| 1039 | * set for this device in the table. | ||
| 1040 | */ | ||
| 1041 | if (dev->data_dev) | ||
| 1042 | dm_put_device(ti, dev->data_dev); | ||
| 1073 | 1043 | ||
| 1074 | list_del(&rdev->same_set); | 1044 | dev->data_dev = NULL; |
| 1045 | rdev->bdev = NULL; | ||
| 1075 | 1046 | ||
| 1076 | continue; | 1047 | list_del(&rdev->same_set); |
| 1077 | } | ||
| 1078 | ti->error = "Failed to load superblock"; | ||
| 1079 | return ret; | ||
| 1080 | } | 1048 | } |
| 1081 | } | 1049 | } |
| 1082 | 1050 | ||
| 1083 | if (!freshest) | 1051 | if (!freshest) |
| 1084 | return 0; | 1052 | return 0; |
| 1085 | 1053 | ||
| 1054 | if (validate_raid_redundancy(rs)) { | ||
| 1055 | rs->ti->error = "Insufficient redundancy to activate array"; | ||
| 1056 | return -EINVAL; | ||
| 1057 | } | ||
| 1058 | |||
| 1086 | /* | 1059 | /* |
| 1087 | * Validation of the freshest device provides the source of | 1060 | * Validation of the freshest device provides the source of |
| 1088 | * validation for the remaining devices. | 1061 | * validation for the remaining devices. |
| @@ -1432,7 +1405,7 @@ static void raid_resume(struct dm_target *ti) | |||
| 1432 | 1405 | ||
| 1433 | static struct target_type raid_target = { | 1406 | static struct target_type raid_target = { |
| 1434 | .name = "raid", | 1407 | .name = "raid", |
| 1435 | .version = {1, 4, 0}, | 1408 | .version = {1, 4, 1}, |
| 1436 | .module = THIS_MODULE, | 1409 | .module = THIS_MODULE, |
| 1437 | .ctr = raid_ctr, | 1410 | .ctr = raid_ctr, |
| 1438 | .dtr = raid_dtr, | 1411 | .dtr = raid_dtr, |
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index 675ae5274016..5409607d4875 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c | |||
| @@ -2746,19 +2746,9 @@ static int thin_iterate_devices(struct dm_target *ti, | |||
| 2746 | return 0; | 2746 | return 0; |
| 2747 | } | 2747 | } |
| 2748 | 2748 | ||
| 2749 | /* | ||
| 2750 | * A thin device always inherits its queue limits from its pool. | ||
| 2751 | */ | ||
| 2752 | static void thin_io_hints(struct dm_target *ti, struct queue_limits *limits) | ||
| 2753 | { | ||
| 2754 | struct thin_c *tc = ti->private; | ||
| 2755 | |||
| 2756 | *limits = bdev_get_queue(tc->pool_dev->bdev)->limits; | ||
| 2757 | } | ||
| 2758 | |||
| 2759 | static struct target_type thin_target = { | 2749 | static struct target_type thin_target = { |
| 2760 | .name = "thin", | 2750 | .name = "thin", |
| 2761 | .version = {1, 6, 0}, | 2751 | .version = {1, 7, 0}, |
| 2762 | .module = THIS_MODULE, | 2752 | .module = THIS_MODULE, |
| 2763 | .ctr = thin_ctr, | 2753 | .ctr = thin_ctr, |
| 2764 | .dtr = thin_dtr, | 2754 | .dtr = thin_dtr, |
| @@ -2767,7 +2757,6 @@ static struct target_type thin_target = { | |||
| 2767 | .postsuspend = thin_postsuspend, | 2757 | .postsuspend = thin_postsuspend, |
| 2768 | .status = thin_status, | 2758 | .status = thin_status, |
| 2769 | .iterate_devices = thin_iterate_devices, | 2759 | .iterate_devices = thin_iterate_devices, |
| 2770 | .io_hints = thin_io_hints, | ||
| 2771 | }; | 2760 | }; |
| 2772 | 2761 | ||
| 2773 | /*----------------------------------------------------------------*/ | 2762 | /*----------------------------------------------------------------*/ |
diff --git a/drivers/md/dm.c b/drivers/md/dm.c index c72e4d5a9617..314a0e2faf79 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c | |||
| @@ -1188,6 +1188,7 @@ static int __clone_and_map_changing_extent_only(struct clone_info *ci, | |||
| 1188 | { | 1188 | { |
| 1189 | struct dm_target *ti; | 1189 | struct dm_target *ti; |
| 1190 | sector_t len; | 1190 | sector_t len; |
| 1191 | unsigned num_requests; | ||
| 1191 | 1192 | ||
| 1192 | do { | 1193 | do { |
| 1193 | ti = dm_table_find_target(ci->map, ci->sector); | 1194 | ti = dm_table_find_target(ci->map, ci->sector); |
| @@ -1200,7 +1201,8 @@ static int __clone_and_map_changing_extent_only(struct clone_info *ci, | |||
| 1200 | * reconfiguration might also have changed that since the | 1201 | * reconfiguration might also have changed that since the |
| 1201 | * check was performed. | 1202 | * check was performed. |
| 1202 | */ | 1203 | */ |
| 1203 | if (!get_num_requests || !get_num_requests(ti)) | 1204 | num_requests = get_num_requests ? get_num_requests(ti) : 0; |
| 1205 | if (!num_requests) | ||
| 1204 | return -EOPNOTSUPP; | 1206 | return -EOPNOTSUPP; |
| 1205 | 1207 | ||
| 1206 | if (is_split_required && !is_split_required(ti)) | 1208 | if (is_split_required && !is_split_required(ti)) |
| @@ -1208,7 +1210,7 @@ static int __clone_and_map_changing_extent_only(struct clone_info *ci, | |||
| 1208 | else | 1210 | else |
| 1209 | len = min(ci->sector_count, max_io_len(ci->sector, ti)); | 1211 | len = min(ci->sector_count, max_io_len(ci->sector, ti)); |
| 1210 | 1212 | ||
| 1211 | __issue_target_requests(ci, ti, ti->num_discard_requests, len); | 1213 | __issue_target_requests(ci, ti, num_requests, len); |
| 1212 | 1214 | ||
| 1213 | ci->sector += len; | 1215 | ci->sector += len; |
| 1214 | } while (ci->sector_count -= len); | 1216 | } while (ci->sector_count -= len); |
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..ff553babf455 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig | |||
| @@ -237,6 +237,7 @@ config MFD_TPS65910 | |||
| 237 | depends on I2C=y && GPIOLIB | 237 | depends on I2C=y && GPIOLIB |
| 238 | select MFD_CORE | 238 | select MFD_CORE |
| 239 | select REGMAP_I2C | 239 | select REGMAP_I2C |
| 240 | select REGMAP_IRQ | ||
| 240 | select IRQ_DOMAIN | 241 | select IRQ_DOMAIN |
| 241 | help | 242 | help |
| 242 | if you say yes here you get support for the TPS65910 series of | 243 | if you say yes here you get support for the TPS65910 series of |
| @@ -292,6 +293,7 @@ config TWL4030_CORE | |||
| 292 | bool "Texas Instruments TWL4030/TWL5030/TWL6030/TPS659x0 Support" | 293 | bool "Texas Instruments TWL4030/TWL5030/TWL6030/TPS659x0 Support" |
| 293 | depends on I2C=y && GENERIC_HARDIRQS | 294 | depends on I2C=y && GENERIC_HARDIRQS |
| 294 | select IRQ_DOMAIN | 295 | select IRQ_DOMAIN |
| 296 | select REGMAP_I2C | ||
| 295 | help | 297 | help |
| 296 | Say yes here if you have TWL4030 / TWL6030 family chip on your board. | 298 | Say yes here if you have TWL4030 / TWL6030 family chip on your board. |
| 297 | This core driver provides register access and IRQ handling | 299 | This core driver provides register access and IRQ handling |
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index e1650badd106..4778bb124efe 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #include <linux/mfd/core.h> | 19 | #include <linux/mfd/core.h> |
| 20 | #include <linux/mfd/abx500.h> | 20 | #include <linux/mfd/abx500.h> |
| 21 | #include <linux/mfd/abx500/ab8500.h> | 21 | #include <linux/mfd/abx500/ab8500.h> |
| 22 | #include <linux/mfd/abx500/ab8500-bm.h> | ||
| 22 | #include <linux/mfd/dbx500-prcmu.h> | 23 | #include <linux/mfd/dbx500-prcmu.h> |
| 23 | #include <linux/regulator/ab8500.h> | 24 | #include <linux/regulator/ab8500.h> |
| 24 | #include <linux/of.h> | 25 | #include <linux/of.h> |
diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index bc8a3edb6bbf..222c03a5ddc0 100644 --- a/drivers/mfd/arizona-core.c +++ b/drivers/mfd/arizona-core.c | |||
| @@ -239,7 +239,12 @@ static int arizona_runtime_resume(struct device *dev) | |||
| 239 | return ret; | 239 | return ret; |
| 240 | } | 240 | } |
| 241 | 241 | ||
| 242 | regcache_sync(arizona->regmap); | 242 | ret = regcache_sync(arizona->regmap); |
| 243 | if (ret != 0) { | ||
| 244 | dev_err(arizona->dev, "Failed to restore register cache\n"); | ||
| 245 | regulator_disable(arizona->dcvdd); | ||
| 246 | return ret; | ||
| 247 | } | ||
| 243 | 248 | ||
| 244 | return 0; | 249 | return 0; |
| 245 | } | 250 | } |
diff --git a/drivers/mfd/arizona-irq.c b/drivers/mfd/arizona-irq.c index 74713bf5371f..2bec5f0db3ee 100644 --- a/drivers/mfd/arizona-irq.c +++ b/drivers/mfd/arizona-irq.c | |||
| @@ -176,14 +176,7 @@ int arizona_irq_init(struct arizona *arizona) | |||
| 176 | aod = &wm5102_aod; | 176 | aod = &wm5102_aod; |
| 177 | irq = &wm5102_irq; | 177 | irq = &wm5102_irq; |
| 178 | 178 | ||
| 179 | switch (arizona->rev) { | 179 | ctrlif_error = false; |
| 180 | case 0: | ||
| 181 | case 1: | ||
| 182 | ctrlif_error = false; | ||
| 183 | break; | ||
| 184 | default: | ||
| 185 | break; | ||
| 186 | } | ||
| 187 | break; | 180 | break; |
| 188 | #endif | 181 | #endif |
| 189 | #ifdef CONFIG_MFD_WM5110 | 182 | #ifdef CONFIG_MFD_WM5110 |
| @@ -191,14 +184,7 @@ int arizona_irq_init(struct arizona *arizona) | |||
| 191 | aod = &wm5110_aod; | 184 | aod = &wm5110_aod; |
| 192 | irq = &wm5110_irq; | 185 | irq = &wm5110_irq; |
| 193 | 186 | ||
| 194 | switch (arizona->rev) { | 187 | ctrlif_error = false; |
| 195 | case 0: | ||
| 196 | case 1: | ||
| 197 | ctrlif_error = false; | ||
| 198 | break; | ||
| 199 | default: | ||
| 200 | break; | ||
| 201 | } | ||
| 202 | break; | 188 | break; |
| 203 | #endif | 189 | #endif |
| 204 | default: | 190 | default: |
diff --git a/drivers/mfd/da9052-i2c.c b/drivers/mfd/da9052-i2c.c index ac74a4d1daea..885e56780358 100644 --- a/drivers/mfd/da9052-i2c.c +++ b/drivers/mfd/da9052-i2c.c | |||
| @@ -27,6 +27,66 @@ | |||
| 27 | #include <linux/of_device.h> | 27 | #include <linux/of_device.h> |
| 28 | #endif | 28 | #endif |
| 29 | 29 | ||
| 30 | /* I2C safe register check */ | ||
| 31 | static inline bool i2c_safe_reg(unsigned char reg) | ||
| 32 | { | ||
| 33 | switch (reg) { | ||
| 34 | case DA9052_STATUS_A_REG: | ||
| 35 | case DA9052_STATUS_B_REG: | ||
| 36 | case DA9052_STATUS_C_REG: | ||
| 37 | case DA9052_STATUS_D_REG: | ||
| 38 | case DA9052_ADC_RES_L_REG: | ||
| 39 | case DA9052_ADC_RES_H_REG: | ||
| 40 | case DA9052_VDD_RES_REG: | ||
| 41 | case DA9052_ICHG_AV_REG: | ||
| 42 | case DA9052_TBAT_RES_REG: | ||
| 43 | case DA9052_ADCIN4_RES_REG: | ||
| 44 | case DA9052_ADCIN5_RES_REG: | ||
| 45 | case DA9052_ADCIN6_RES_REG: | ||
| 46 | case DA9052_TJUNC_RES_REG: | ||
| 47 | case DA9052_TSI_X_MSB_REG: | ||
| 48 | case DA9052_TSI_Y_MSB_REG: | ||
| 49 | case DA9052_TSI_LSB_REG: | ||
| 50 | case DA9052_TSI_Z_MSB_REG: | ||
| 51 | return true; | ||
| 52 | default: | ||
| 53 | return false; | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | /* | ||
| 58 | * There is an issue with DA9052 and DA9053_AA/BA/BB PMIC where the PMIC | ||
| 59 | * gets lockup up or fails to respond following a system reset. | ||
| 60 | * This fix is to follow any read or write with a dummy read to a safe | ||
| 61 | * register. | ||
| 62 | */ | ||
| 63 | int da9052_i2c_fix(struct da9052 *da9052, unsigned char reg) | ||
| 64 | { | ||
| 65 | int val; | ||
| 66 | |||
| 67 | switch (da9052->chip_id) { | ||
| 68 | case DA9052: | ||
| 69 | case DA9053_AA: | ||
| 70 | case DA9053_BA: | ||
| 71 | case DA9053_BB: | ||
| 72 | /* A dummy read to a safe register address. */ | ||
| 73 | if (!i2c_safe_reg(reg)) | ||
| 74 | return regmap_read(da9052->regmap, | ||
| 75 | DA9052_PARK_REGISTER, | ||
| 76 | &val); | ||
| 77 | break; | ||
| 78 | default: | ||
| 79 | /* | ||
| 80 | * For other chips parking of I2C register | ||
| 81 | * to a safe place is not required. | ||
| 82 | */ | ||
| 83 | break; | ||
| 84 | } | ||
| 85 | |||
| 86 | return 0; | ||
| 87 | } | ||
| 88 | EXPORT_SYMBOL(da9052_i2c_fix); | ||
| 89 | |||
| 30 | static int da9052_i2c_enable_multiwrite(struct da9052 *da9052) | 90 | static int da9052_i2c_enable_multiwrite(struct da9052 *da9052) |
| 31 | { | 91 | { |
| 32 | int reg_val, ret; | 92 | int reg_val, ret; |
| @@ -83,6 +143,7 @@ static int da9052_i2c_probe(struct i2c_client *client, | |||
| 83 | 143 | ||
| 84 | da9052->dev = &client->dev; | 144 | da9052->dev = &client->dev; |
| 85 | da9052->chip_irq = client->irq; | 145 | da9052->chip_irq = client->irq; |
| 146 | da9052->fix_io = da9052_i2c_fix; | ||
| 86 | 147 | ||
| 87 | i2c_set_clientdata(client, da9052); | 148 | i2c_set_clientdata(client, da9052); |
| 88 | 149 | ||
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c index 13f4ccf2612d..6fbe1c96a404 100644 --- a/drivers/mfd/db8500-prcmu.c +++ b/drivers/mfd/db8500-prcmu.c | |||
| @@ -2524,7 +2524,7 @@ static bool read_mailbox_0(void) | |||
| 2524 | 2524 | ||
| 2525 | for (n = 0; n < NUM_PRCMU_WAKEUPS; n++) { | 2525 | for (n = 0; n < NUM_PRCMU_WAKEUPS; n++) { |
| 2526 | if (ev & prcmu_irq_bit[n]) | 2526 | if (ev & prcmu_irq_bit[n]) |
| 2527 | generic_handle_irq(IRQ_PRCMU_BASE + n); | 2527 | generic_handle_irq(irq_find_mapping(db8500_irq_domain, n)); |
| 2528 | } | 2528 | } |
| 2529 | r = true; | 2529 | r = true; |
| 2530 | break; | 2530 | break; |
| @@ -2737,13 +2737,14 @@ static int db8500_irq_map(struct irq_domain *d, unsigned int virq, | |||
| 2737 | } | 2737 | } |
| 2738 | 2738 | ||
| 2739 | static struct irq_domain_ops db8500_irq_ops = { | 2739 | static struct irq_domain_ops db8500_irq_ops = { |
| 2740 | .map = db8500_irq_map, | 2740 | .map = db8500_irq_map, |
| 2741 | .xlate = irq_domain_xlate_twocell, | 2741 | .xlate = irq_domain_xlate_twocell, |
| 2742 | }; | 2742 | }; |
| 2743 | 2743 | ||
| 2744 | static int db8500_irq_init(struct device_node *np) | 2744 | static int db8500_irq_init(struct device_node *np) |
| 2745 | { | 2745 | { |
| 2746 | int irq_base = -1; | 2746 | int irq_base = 0; |
| 2747 | int i; | ||
| 2747 | 2748 | ||
| 2748 | /* In the device tree case, just take some IRQs */ | 2749 | /* In the device tree case, just take some IRQs */ |
| 2749 | if (!np) | 2750 | if (!np) |
| @@ -2758,6 +2759,10 @@ static int db8500_irq_init(struct device_node *np) | |||
| 2758 | return -ENOSYS; | 2759 | return -ENOSYS; |
| 2759 | } | 2760 | } |
| 2760 | 2761 | ||
| 2762 | /* All wakeups will be used, so create mappings for all */ | ||
| 2763 | for (i = 0; i < NUM_PRCMU_WAKEUPS; i++) | ||
| 2764 | irq_create_mapping(db8500_irq_domain, i); | ||
| 2765 | |||
| 2761 | return 0; | 2766 | return 0; |
| 2762 | } | 2767 | } |
| 2763 | 2768 | ||
diff --git a/drivers/mfd/max77686.c b/drivers/mfd/max77686.c index f6878f8db57d..4d73963cd8f0 100644 --- a/drivers/mfd/max77686.c +++ b/drivers/mfd/max77686.c | |||
| @@ -93,15 +93,6 @@ static int max77686_i2c_probe(struct i2c_client *i2c, | |||
| 93 | if (max77686 == NULL) | 93 | if (max77686 == NULL) |
| 94 | return -ENOMEM; | 94 | return -ENOMEM; |
| 95 | 95 | ||
| 96 | max77686->regmap = regmap_init_i2c(i2c, &max77686_regmap_config); | ||
| 97 | if (IS_ERR(max77686->regmap)) { | ||
| 98 | ret = PTR_ERR(max77686->regmap); | ||
| 99 | dev_err(max77686->dev, "Failed to allocate register map: %d\n", | ||
| 100 | ret); | ||
| 101 | kfree(max77686); | ||
| 102 | return ret; | ||
| 103 | } | ||
| 104 | |||
| 105 | i2c_set_clientdata(i2c, max77686); | 96 | i2c_set_clientdata(i2c, max77686); |
| 106 | max77686->dev = &i2c->dev; | 97 | max77686->dev = &i2c->dev; |
| 107 | max77686->i2c = i2c; | 98 | max77686->i2c = i2c; |
| @@ -111,6 +102,15 @@ static int max77686_i2c_probe(struct i2c_client *i2c, | |||
| 111 | max77686->irq_gpio = pdata->irq_gpio; | 102 | max77686->irq_gpio = pdata->irq_gpio; |
| 112 | max77686->irq = i2c->irq; | 103 | max77686->irq = i2c->irq; |
| 113 | 104 | ||
| 105 | max77686->regmap = regmap_init_i2c(i2c, &max77686_regmap_config); | ||
| 106 | if (IS_ERR(max77686->regmap)) { | ||
| 107 | ret = PTR_ERR(max77686->regmap); | ||
| 108 | dev_err(max77686->dev, "Failed to allocate register map: %d\n", | ||
| 109 | ret); | ||
| 110 | kfree(max77686); | ||
| 111 | return ret; | ||
| 112 | } | ||
| 113 | |||
| 114 | if (regmap_read(max77686->regmap, | 114 | if (regmap_read(max77686->regmap, |
| 115 | MAX77686_REG_DEVICE_ID, &data) < 0) { | 115 | MAX77686_REG_DEVICE_ID, &data) < 0) { |
| 116 | dev_err(max77686->dev, | 116 | dev_err(max77686->dev, |
diff --git a/drivers/mfd/max77693.c b/drivers/mfd/max77693.c index cc5155e20494..9e60fed5ff82 100644 --- a/drivers/mfd/max77693.c +++ b/drivers/mfd/max77693.c | |||
| @@ -114,35 +114,37 @@ static int max77693_i2c_probe(struct i2c_client *i2c, | |||
| 114 | u8 reg_data; | 114 | u8 reg_data; |
| 115 | int ret = 0; | 115 | int ret = 0; |
| 116 | 116 | ||
| 117 | if (!pdata) { | ||
| 118 | dev_err(&i2c->dev, "No platform data found.\n"); | ||
| 119 | return -EINVAL; | ||
| 120 | } | ||
| 121 | |||
| 117 | max77693 = devm_kzalloc(&i2c->dev, | 122 | max77693 = devm_kzalloc(&i2c->dev, |
| 118 | sizeof(struct max77693_dev), GFP_KERNEL); | 123 | sizeof(struct max77693_dev), GFP_KERNEL); |
| 119 | if (max77693 == NULL) | 124 | if (max77693 == NULL) |
| 120 | return -ENOMEM; | 125 | return -ENOMEM; |
| 121 | 126 | ||
| 122 | max77693->regmap = devm_regmap_init_i2c(i2c, &max77693_regmap_config); | ||
| 123 | if (IS_ERR(max77693->regmap)) { | ||
| 124 | ret = PTR_ERR(max77693->regmap); | ||
| 125 | dev_err(max77693->dev,"failed to allocate register map: %d\n", | ||
| 126 | ret); | ||
| 127 | goto err_regmap; | ||
| 128 | } | ||
| 129 | |||
| 130 | i2c_set_clientdata(i2c, max77693); | 127 | i2c_set_clientdata(i2c, max77693); |
| 131 | max77693->dev = &i2c->dev; | 128 | max77693->dev = &i2c->dev; |
| 132 | max77693->i2c = i2c; | 129 | max77693->i2c = i2c; |
| 133 | max77693->irq = i2c->irq; | 130 | max77693->irq = i2c->irq; |
| 134 | max77693->type = id->driver_data; | 131 | max77693->type = id->driver_data; |
| 135 | 132 | ||
| 136 | if (!pdata) | 133 | max77693->regmap = devm_regmap_init_i2c(i2c, &max77693_regmap_config); |
| 137 | goto err_regmap; | 134 | if (IS_ERR(max77693->regmap)) { |
| 135 | ret = PTR_ERR(max77693->regmap); | ||
| 136 | dev_err(max77693->dev, "failed to allocate register map: %d\n", | ||
| 137 | ret); | ||
| 138 | return ret; | ||
| 139 | } | ||
| 138 | 140 | ||
| 139 | max77693->wakeup = pdata->wakeup; | 141 | max77693->wakeup = pdata->wakeup; |
| 140 | 142 | ||
| 141 | if (max77693_read_reg(max77693->regmap, | 143 | ret = max77693_read_reg(max77693->regmap, MAX77693_PMIC_REG_PMIC_ID2, |
| 142 | MAX77693_PMIC_REG_PMIC_ID2, ®_data) < 0) { | 144 | ®_data); |
| 145 | if (ret < 0) { | ||
| 143 | dev_err(max77693->dev, "device not found on this channel\n"); | 146 | dev_err(max77693->dev, "device not found on this channel\n"); |
| 144 | ret = -ENODEV; | 147 | return ret; |
| 145 | goto err_regmap; | ||
| 146 | } else | 148 | } else |
| 147 | dev_info(max77693->dev, "device ID: 0x%x\n", reg_data); | 149 | dev_info(max77693->dev, "device ID: 0x%x\n", reg_data); |
| 148 | 150 | ||
| @@ -163,7 +165,7 @@ static int max77693_i2c_probe(struct i2c_client *i2c, | |||
| 163 | ret = PTR_ERR(max77693->regmap_muic); | 165 | ret = PTR_ERR(max77693->regmap_muic); |
| 164 | dev_err(max77693->dev, | 166 | dev_err(max77693->dev, |
| 165 | "failed to allocate register map: %d\n", ret); | 167 | "failed to allocate register map: %d\n", ret); |
| 166 | goto err_regmap; | 168 | goto err_regmap_muic; |
| 167 | } | 169 | } |
| 168 | 170 | ||
| 169 | ret = max77693_irq_init(max77693); | 171 | ret = max77693_irq_init(max77693); |
| @@ -184,9 +186,9 @@ static int max77693_i2c_probe(struct i2c_client *i2c, | |||
| 184 | err_mfd: | 186 | err_mfd: |
| 185 | max77693_irq_exit(max77693); | 187 | max77693_irq_exit(max77693); |
| 186 | err_irq: | 188 | err_irq: |
| 189 | err_regmap_muic: | ||
| 187 | i2c_unregister_device(max77693->muic); | 190 | i2c_unregister_device(max77693->muic); |
| 188 | i2c_unregister_device(max77693->haptic); | 191 | i2c_unregister_device(max77693->haptic); |
| 189 | err_regmap: | ||
| 190 | return ret; | 192 | return ret; |
| 191 | } | 193 | } |
| 192 | 194 | ||
diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c index 64803f13bcec..d11567307fbe 100644 --- a/drivers/mfd/pcf50633-core.c +++ b/drivers/mfd/pcf50633-core.c | |||
| @@ -208,6 +208,8 @@ static int pcf50633_probe(struct i2c_client *client, | |||
| 208 | if (!pcf) | 208 | if (!pcf) |
| 209 | return -ENOMEM; | 209 | return -ENOMEM; |
| 210 | 210 | ||
| 211 | i2c_set_clientdata(client, pcf); | ||
| 212 | pcf->dev = &client->dev; | ||
| 211 | pcf->pdata = pdata; | 213 | pcf->pdata = pdata; |
| 212 | 214 | ||
| 213 | mutex_init(&pcf->lock); | 215 | mutex_init(&pcf->lock); |
| @@ -219,9 +221,6 @@ static int pcf50633_probe(struct i2c_client *client, | |||
| 219 | return ret; | 221 | return ret; |
| 220 | } | 222 | } |
| 221 | 223 | ||
| 222 | i2c_set_clientdata(client, pcf); | ||
| 223 | pcf->dev = &client->dev; | ||
| 224 | |||
| 225 | version = pcf50633_reg_read(pcf, 0); | 224 | version = pcf50633_reg_read(pcf, 0); |
| 226 | variant = pcf50633_reg_read(pcf, 1); | 225 | variant = pcf50633_reg_read(pcf, 1); |
| 227 | if (version < 0 || variant < 0) { | 226 | if (version < 0 || variant < 0) { |
diff --git a/drivers/mfd/rtl8411.c b/drivers/mfd/rtl8411.c index 89f046ca9e41..3d3b4addf81a 100644 --- a/drivers/mfd/rtl8411.c +++ b/drivers/mfd/rtl8411.c | |||
| @@ -112,6 +112,21 @@ static int rtl8411_card_power_off(struct rtsx_pcr *pcr, int card) | |||
| 112 | BPP_LDO_POWB, BPP_LDO_SUSPEND); | 112 | BPP_LDO_POWB, BPP_LDO_SUSPEND); |
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | static int rtl8411_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) | ||
| 116 | { | ||
| 117 | u8 mask, val; | ||
| 118 | |||
| 119 | mask = (BPP_REG_TUNED18 << BPP_TUNED18_SHIFT_8411) | BPP_PAD_MASK; | ||
| 120 | if (voltage == OUTPUT_3V3) | ||
| 121 | val = (BPP_ASIC_3V3 << BPP_TUNED18_SHIFT_8411) | BPP_PAD_3V3; | ||
| 122 | else if (voltage == OUTPUT_1V8) | ||
| 123 | val = (BPP_ASIC_1V8 << BPP_TUNED18_SHIFT_8411) | BPP_PAD_1V8; | ||
| 124 | else | ||
| 125 | return -EINVAL; | ||
| 126 | |||
| 127 | return rtsx_pci_write_register(pcr, LDO_CTL, mask, val); | ||
| 128 | } | ||
| 129 | |||
| 115 | static unsigned int rtl8411_cd_deglitch(struct rtsx_pcr *pcr) | 130 | static unsigned int rtl8411_cd_deglitch(struct rtsx_pcr *pcr) |
| 116 | { | 131 | { |
| 117 | unsigned int card_exist; | 132 | unsigned int card_exist; |
| @@ -163,6 +178,18 @@ static unsigned int rtl8411_cd_deglitch(struct rtsx_pcr *pcr) | |||
| 163 | return card_exist; | 178 | return card_exist; |
| 164 | } | 179 | } |
| 165 | 180 | ||
| 181 | static int rtl8411_conv_clk_and_div_n(int input, int dir) | ||
| 182 | { | ||
| 183 | int output; | ||
| 184 | |||
| 185 | if (dir == CLK_TO_DIV_N) | ||
| 186 | output = input * 4 / 5 - 2; | ||
| 187 | else | ||
| 188 | output = (input + 2) * 5 / 4; | ||
| 189 | |||
| 190 | return output; | ||
| 191 | } | ||
| 192 | |||
| 166 | static const struct pcr_ops rtl8411_pcr_ops = { | 193 | static const struct pcr_ops rtl8411_pcr_ops = { |
| 167 | .extra_init_hw = rtl8411_extra_init_hw, | 194 | .extra_init_hw = rtl8411_extra_init_hw, |
| 168 | .optimize_phy = NULL, | 195 | .optimize_phy = NULL, |
| @@ -172,7 +199,9 @@ static const struct pcr_ops rtl8411_pcr_ops = { | |||
| 172 | .disable_auto_blink = rtl8411_disable_auto_blink, | 199 | .disable_auto_blink = rtl8411_disable_auto_blink, |
| 173 | .card_power_on = rtl8411_card_power_on, | 200 | .card_power_on = rtl8411_card_power_on, |
| 174 | .card_power_off = rtl8411_card_power_off, | 201 | .card_power_off = rtl8411_card_power_off, |
| 202 | .switch_output_voltage = rtl8411_switch_output_voltage, | ||
| 175 | .cd_deglitch = rtl8411_cd_deglitch, | 203 | .cd_deglitch = rtl8411_cd_deglitch, |
| 204 | .conv_clk_and_div_n = rtl8411_conv_clk_and_div_n, | ||
| 176 | }; | 205 | }; |
| 177 | 206 | ||
| 178 | /* SD Pull Control Enable: | 207 | /* SD Pull Control Enable: |
diff --git a/drivers/mfd/rts5209.c b/drivers/mfd/rts5209.c index 283a4f148084..98fe0f39463e 100644 --- a/drivers/mfd/rts5209.c +++ b/drivers/mfd/rts5209.c | |||
| @@ -144,6 +144,25 @@ static int rts5209_card_power_off(struct rtsx_pcr *pcr, int card) | |||
| 144 | return rtsx_pci_send_cmd(pcr, 100); | 144 | return rtsx_pci_send_cmd(pcr, 100); |
| 145 | } | 145 | } |
| 146 | 146 | ||
| 147 | static int rts5209_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) | ||
| 148 | { | ||
| 149 | int err; | ||
| 150 | |||
| 151 | if (voltage == OUTPUT_3V3) { | ||
| 152 | err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24); | ||
| 153 | if (err < 0) | ||
| 154 | return err; | ||
| 155 | } else if (voltage == OUTPUT_1V8) { | ||
| 156 | err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C40 | 0x24); | ||
| 157 | if (err < 0) | ||
| 158 | return err; | ||
| 159 | } else { | ||
| 160 | return -EINVAL; | ||
| 161 | } | ||
| 162 | |||
| 163 | return 0; | ||
| 164 | } | ||
| 165 | |||
| 147 | static const struct pcr_ops rts5209_pcr_ops = { | 166 | static const struct pcr_ops rts5209_pcr_ops = { |
| 148 | .extra_init_hw = rts5209_extra_init_hw, | 167 | .extra_init_hw = rts5209_extra_init_hw, |
| 149 | .optimize_phy = rts5209_optimize_phy, | 168 | .optimize_phy = rts5209_optimize_phy, |
| @@ -153,7 +172,9 @@ static const struct pcr_ops rts5209_pcr_ops = { | |||
| 153 | .disable_auto_blink = rts5209_disable_auto_blink, | 172 | .disable_auto_blink = rts5209_disable_auto_blink, |
| 154 | .card_power_on = rts5209_card_power_on, | 173 | .card_power_on = rts5209_card_power_on, |
| 155 | .card_power_off = rts5209_card_power_off, | 174 | .card_power_off = rts5209_card_power_off, |
| 175 | .switch_output_voltage = rts5209_switch_output_voltage, | ||
| 156 | .cd_deglitch = NULL, | 176 | .cd_deglitch = NULL, |
| 177 | .conv_clk_and_div_n = NULL, | ||
| 157 | }; | 178 | }; |
| 158 | 179 | ||
| 159 | /* SD Pull Control Enable: | 180 | /* SD Pull Control Enable: |
diff --git a/drivers/mfd/rts5229.c b/drivers/mfd/rts5229.c index b9dbab266fda..29d889cbb9c5 100644 --- a/drivers/mfd/rts5229.c +++ b/drivers/mfd/rts5229.c | |||
| @@ -114,6 +114,25 @@ static int rts5229_card_power_off(struct rtsx_pcr *pcr, int card) | |||
| 114 | return rtsx_pci_send_cmd(pcr, 100); | 114 | return rtsx_pci_send_cmd(pcr, 100); |
| 115 | } | 115 | } |
| 116 | 116 | ||
| 117 | static int rts5229_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) | ||
| 118 | { | ||
| 119 | int err; | ||
| 120 | |||
| 121 | if (voltage == OUTPUT_3V3) { | ||
| 122 | err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24); | ||
| 123 | if (err < 0) | ||
| 124 | return err; | ||
| 125 | } else if (voltage == OUTPUT_1V8) { | ||
| 126 | err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C40 | 0x24); | ||
| 127 | if (err < 0) | ||
| 128 | return err; | ||
| 129 | } else { | ||
| 130 | return -EINVAL; | ||
| 131 | } | ||
| 132 | |||
| 133 | return 0; | ||
| 134 | } | ||
| 135 | |||
| 117 | static const struct pcr_ops rts5229_pcr_ops = { | 136 | static const struct pcr_ops rts5229_pcr_ops = { |
| 118 | .extra_init_hw = rts5229_extra_init_hw, | 137 | .extra_init_hw = rts5229_extra_init_hw, |
| 119 | .optimize_phy = rts5229_optimize_phy, | 138 | .optimize_phy = rts5229_optimize_phy, |
| @@ -123,7 +142,9 @@ static const struct pcr_ops rts5229_pcr_ops = { | |||
| 123 | .disable_auto_blink = rts5229_disable_auto_blink, | 142 | .disable_auto_blink = rts5229_disable_auto_blink, |
| 124 | .card_power_on = rts5229_card_power_on, | 143 | .card_power_on = rts5229_card_power_on, |
| 125 | .card_power_off = rts5229_card_power_off, | 144 | .card_power_off = rts5229_card_power_off, |
| 145 | .switch_output_voltage = rts5229_switch_output_voltage, | ||
| 126 | .cd_deglitch = NULL, | 146 | .cd_deglitch = NULL, |
| 147 | .conv_clk_and_div_n = NULL, | ||
| 127 | }; | 148 | }; |
| 128 | 149 | ||
| 129 | /* SD Pull Control Enable: | 150 | /* SD Pull Control Enable: |
diff --git a/drivers/mfd/rtsx_pcr.c b/drivers/mfd/rtsx_pcr.c index 7a7b0bda4618..9fc57009e228 100644 --- a/drivers/mfd/rtsx_pcr.c +++ b/drivers/mfd/rtsx_pcr.c | |||
| @@ -630,7 +630,10 @@ int rtsx_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock, | |||
| 630 | if (clk == pcr->cur_clock) | 630 | if (clk == pcr->cur_clock) |
| 631 | return 0; | 631 | return 0; |
| 632 | 632 | ||
| 633 | N = (u8)(clk - 2); | 633 | if (pcr->ops->conv_clk_and_div_n) |
| 634 | N = (u8)pcr->ops->conv_clk_and_div_n(clk, CLK_TO_DIV_N); | ||
| 635 | else | ||
| 636 | N = (u8)(clk - 2); | ||
| 634 | if ((clk <= 2) || (N > max_N)) | 637 | if ((clk <= 2) || (N > max_N)) |
| 635 | return -EINVAL; | 638 | return -EINVAL; |
| 636 | 639 | ||
| @@ -641,7 +644,14 @@ int rtsx_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock, | |||
| 641 | /* Make sure that the SSC clock div_n is equal or greater than min_N */ | 644 | /* Make sure that the SSC clock div_n is equal or greater than min_N */ |
| 642 | div = CLK_DIV_1; | 645 | div = CLK_DIV_1; |
| 643 | while ((N < min_N) && (div < max_div)) { | 646 | while ((N < min_N) && (div < max_div)) { |
| 644 | N = (N + 2) * 2 - 2; | 647 | if (pcr->ops->conv_clk_and_div_n) { |
| 648 | int dbl_clk = pcr->ops->conv_clk_and_div_n(N, | ||
| 649 | DIV_N_TO_CLK) * 2; | ||
| 650 | N = (u8)pcr->ops->conv_clk_and_div_n(dbl_clk, | ||
| 651 | CLK_TO_DIV_N); | ||
| 652 | } else { | ||
| 653 | N = (N + 2) * 2 - 2; | ||
| 654 | } | ||
| 645 | div++; | 655 | div++; |
| 646 | } | 656 | } |
| 647 | dev_dbg(&(pcr->pci->dev), "N = %d, div = %d\n", N, div); | 657 | dev_dbg(&(pcr->pci->dev), "N = %d, div = %d\n", N, div); |
| @@ -703,6 +713,15 @@ int rtsx_pci_card_power_off(struct rtsx_pcr *pcr, int card) | |||
| 703 | } | 713 | } |
| 704 | EXPORT_SYMBOL_GPL(rtsx_pci_card_power_off); | 714 | EXPORT_SYMBOL_GPL(rtsx_pci_card_power_off); |
| 705 | 715 | ||
| 716 | int rtsx_pci_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) | ||
| 717 | { | ||
| 718 | if (pcr->ops->switch_output_voltage) | ||
| 719 | return pcr->ops->switch_output_voltage(pcr, voltage); | ||
| 720 | |||
| 721 | return 0; | ||
| 722 | } | ||
| 723 | EXPORT_SYMBOL_GPL(rtsx_pci_switch_output_voltage); | ||
| 724 | |||
| 706 | unsigned int rtsx_pci_card_exist(struct rtsx_pcr *pcr) | 725 | unsigned int rtsx_pci_card_exist(struct rtsx_pcr *pcr) |
| 707 | { | 726 | { |
| 708 | unsigned int val; | 727 | unsigned int val; |
| @@ -767,10 +786,10 @@ static void rtsx_pci_card_detect(struct work_struct *work) | |||
| 767 | 786 | ||
| 768 | spin_unlock_irqrestore(&pcr->lock, flags); | 787 | spin_unlock_irqrestore(&pcr->lock, flags); |
| 769 | 788 | ||
| 770 | if (card_detect & SD_EXIST) | 789 | if ((card_detect & SD_EXIST) && pcr->slots[RTSX_SD_CARD].card_event) |
| 771 | pcr->slots[RTSX_SD_CARD].card_event( | 790 | pcr->slots[RTSX_SD_CARD].card_event( |
| 772 | pcr->slots[RTSX_SD_CARD].p_dev); | 791 | pcr->slots[RTSX_SD_CARD].p_dev); |
| 773 | if (card_detect & MS_EXIST) | 792 | if ((card_detect & MS_EXIST) && pcr->slots[RTSX_MS_CARD].card_event) |
| 774 | pcr->slots[RTSX_MS_CARD].card_event( | 793 | pcr->slots[RTSX_MS_CARD].card_event( |
| 775 | pcr->slots[RTSX_MS_CARD].p_dev); | 794 | pcr->slots[RTSX_MS_CARD].p_dev); |
| 776 | } | 795 | } |
diff --git a/drivers/mfd/tc3589x.c b/drivers/mfd/tc3589x.c index a06d66b929b1..ecc092c7f745 100644 --- a/drivers/mfd/tc3589x.c +++ b/drivers/mfd/tc3589x.c | |||
| @@ -219,25 +219,18 @@ static void tc3589x_irq_unmap(struct irq_domain *d, unsigned int virq) | |||
| 219 | } | 219 | } |
| 220 | 220 | ||
| 221 | static struct irq_domain_ops tc3589x_irq_ops = { | 221 | static struct irq_domain_ops tc3589x_irq_ops = { |
| 222 | .map = tc3589x_irq_map, | 222 | .map = tc3589x_irq_map, |
| 223 | .unmap = tc3589x_irq_unmap, | 223 | .unmap = tc3589x_irq_unmap, |
| 224 | .xlate = irq_domain_xlate_twocell, | 224 | .xlate = irq_domain_xlate_twocell, |
| 225 | }; | 225 | }; |
| 226 | 226 | ||
| 227 | static int tc3589x_irq_init(struct tc3589x *tc3589x, struct device_node *np) | 227 | static int tc3589x_irq_init(struct tc3589x *tc3589x, struct device_node *np) |
| 228 | { | 228 | { |
| 229 | int base = tc3589x->irq_base; | 229 | int base = tc3589x->irq_base; |
| 230 | 230 | ||
| 231 | if (base) { | 231 | tc3589x->domain = irq_domain_add_simple( |
| 232 | tc3589x->domain = irq_domain_add_legacy( | 232 | np, TC3589x_NR_INTERNAL_IRQS, base, |
| 233 | NULL, TC3589x_NR_INTERNAL_IRQS, base, | 233 | &tc3589x_irq_ops, tc3589x); |
| 234 | 0, &tc3589x_irq_ops, tc3589x); | ||
| 235 | } | ||
| 236 | else { | ||
| 237 | tc3589x->domain = irq_domain_add_linear( | ||
| 238 | np, TC3589x_NR_INTERNAL_IRQS, | ||
| 239 | &tc3589x_irq_ops, tc3589x); | ||
| 240 | } | ||
| 241 | 234 | ||
| 242 | if (!tc3589x->domain) { | 235 | if (!tc3589x->domain) { |
| 243 | dev_err(tc3589x->dev, "Failed to create irqdomain\n"); | 236 | dev_err(tc3589x->dev, "Failed to create irqdomain\n"); |
diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c index 4dae241e5017..dd362c1078e1 100644 --- a/drivers/mfd/twl4030-power.c +++ b/drivers/mfd/twl4030-power.c | |||
| @@ -159,7 +159,7 @@ out: | |||
| 159 | static int twl4030_write_script(u8 address, struct twl4030_ins *script, | 159 | static int twl4030_write_script(u8 address, struct twl4030_ins *script, |
| 160 | int len) | 160 | int len) |
| 161 | { | 161 | { |
| 162 | int err; | 162 | int err = -EINVAL; |
| 163 | 163 | ||
| 164 | for (; len; len--, address++, script++) { | 164 | for (; len; len--, address++, script++) { |
| 165 | if (len == 1) { | 165 | if (len == 1) { |
diff --git a/drivers/mfd/vexpress-config.c b/drivers/mfd/vexpress-config.c index fae15d880758..3c1723aa6225 100644 --- a/drivers/mfd/vexpress-config.c +++ b/drivers/mfd/vexpress-config.c | |||
| @@ -67,6 +67,7 @@ struct vexpress_config_bridge *vexpress_config_bridge_register( | |||
| 67 | 67 | ||
| 68 | return bridge; | 68 | return bridge; |
| 69 | } | 69 | } |
| 70 | EXPORT_SYMBOL(vexpress_config_bridge_register); | ||
| 70 | 71 | ||
| 71 | void vexpress_config_bridge_unregister(struct vexpress_config_bridge *bridge) | 72 | void vexpress_config_bridge_unregister(struct vexpress_config_bridge *bridge) |
| 72 | { | 73 | { |
| @@ -83,6 +84,7 @@ void vexpress_config_bridge_unregister(struct vexpress_config_bridge *bridge) | |||
| 83 | while (!list_empty(&__bridge.transactions)) | 84 | while (!list_empty(&__bridge.transactions)) |
| 84 | cpu_relax(); | 85 | cpu_relax(); |
| 85 | } | 86 | } |
| 87 | EXPORT_SYMBOL(vexpress_config_bridge_unregister); | ||
| 86 | 88 | ||
| 87 | 89 | ||
| 88 | struct vexpress_config_func { | 90 | struct vexpress_config_func { |
| @@ -142,6 +144,7 @@ struct vexpress_config_func *__vexpress_config_func_get(struct device *dev, | |||
| 142 | 144 | ||
| 143 | return func; | 145 | return func; |
| 144 | } | 146 | } |
| 147 | EXPORT_SYMBOL(__vexpress_config_func_get); | ||
| 145 | 148 | ||
| 146 | void vexpress_config_func_put(struct vexpress_config_func *func) | 149 | void vexpress_config_func_put(struct vexpress_config_func *func) |
| 147 | { | 150 | { |
| @@ -149,7 +152,7 @@ void vexpress_config_func_put(struct vexpress_config_func *func) | |||
| 149 | of_node_put(func->bridge->node); | 152 | of_node_put(func->bridge->node); |
| 150 | kfree(func); | 153 | kfree(func); |
| 151 | } | 154 | } |
| 152 | 155 | EXPORT_SYMBOL(vexpress_config_func_put); | |
| 153 | 156 | ||
| 154 | struct vexpress_config_trans { | 157 | struct vexpress_config_trans { |
| 155 | struct vexpress_config_func *func; | 158 | struct vexpress_config_func *func; |
| @@ -229,6 +232,7 @@ void vexpress_config_complete(struct vexpress_config_bridge *bridge, | |||
| 229 | 232 | ||
| 230 | complete(&trans->completion); | 233 | complete(&trans->completion); |
| 231 | } | 234 | } |
| 235 | EXPORT_SYMBOL(vexpress_config_complete); | ||
| 232 | 236 | ||
| 233 | int vexpress_config_wait(struct vexpress_config_trans *trans) | 237 | int vexpress_config_wait(struct vexpress_config_trans *trans) |
| 234 | { | 238 | { |
| @@ -236,7 +240,7 @@ int vexpress_config_wait(struct vexpress_config_trans *trans) | |||
| 236 | 240 | ||
| 237 | return trans->status; | 241 | return trans->status; |
| 238 | } | 242 | } |
| 239 | 243 | EXPORT_SYMBOL(vexpress_config_wait); | |
| 240 | 244 | ||
| 241 | int vexpress_config_read(struct vexpress_config_func *func, int offset, | 245 | int vexpress_config_read(struct vexpress_config_func *func, int offset, |
| 242 | u32 *data) | 246 | u32 *data) |
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/mfd/wm5102-tables.c b/drivers/mfd/wm5102-tables.c index 088872ab6338..1133a64c2dc9 100644 --- a/drivers/mfd/wm5102-tables.c +++ b/drivers/mfd/wm5102-tables.c | |||
| @@ -1882,7 +1882,7 @@ static bool wm5102_volatile_register(struct device *dev, unsigned int reg) | |||
| 1882 | } | 1882 | } |
| 1883 | } | 1883 | } |
| 1884 | 1884 | ||
| 1885 | #define WM5102_MAX_REGISTER 0x1a8fff | 1885 | #define WM5102_MAX_REGISTER 0x1a9800 |
| 1886 | 1886 | ||
| 1887 | const struct regmap_config wm5102_spi_regmap = { | 1887 | const struct regmap_config wm5102_spi_regmap = { |
| 1888 | .reg_bits = 32, | 1888 | .reg_bits = 32, |
diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c index 158da5a81a66..3c09cbb70b1d 100644 --- a/drivers/misc/atmel-ssc.c +++ b/drivers/misc/atmel-ssc.c | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
| 20 | 20 | ||
| 21 | #include <linux/of.h> | 21 | #include <linux/of.h> |
| 22 | #include <linux/pinctrl/consumer.h> | ||
| 22 | 23 | ||
| 23 | /* Serialize access to ssc_list and user count */ | 24 | /* Serialize access to ssc_list and user count */ |
| 24 | static DEFINE_SPINLOCK(user_lock); | 25 | static DEFINE_SPINLOCK(user_lock); |
| @@ -131,6 +132,13 @@ static int ssc_probe(struct platform_device *pdev) | |||
| 131 | struct resource *regs; | 132 | struct resource *regs; |
| 132 | struct ssc_device *ssc; | 133 | struct ssc_device *ssc; |
| 133 | const struct atmel_ssc_platform_data *plat_dat; | 134 | const struct atmel_ssc_platform_data *plat_dat; |
| 135 | struct pinctrl *pinctrl; | ||
| 136 | |||
| 137 | pinctrl = devm_pinctrl_get_select_default(&pdev->dev); | ||
| 138 | if (IS_ERR(pinctrl)) { | ||
| 139 | dev_err(&pdev->dev, "Failed to request pinctrl\n"); | ||
| 140 | return PTR_ERR(pinctrl); | ||
| 141 | } | ||
| 134 | 142 | ||
| 135 | ssc = devm_kzalloc(&pdev->dev, sizeof(struct ssc_device), GFP_KERNEL); | 143 | ssc = devm_kzalloc(&pdev->dev, sizeof(struct ssc_device), GFP_KERNEL); |
| 136 | if (!ssc) { | 144 | if (!ssc) { |
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/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c index 571915dfb218..f74b5adca642 100644 --- a/drivers/mmc/host/rtsx_pci_sdmmc.c +++ b/drivers/mmc/host/rtsx_pci_sdmmc.c | |||
| @@ -1060,26 +1060,6 @@ static int sd_wait_voltage_stable_2(struct realtek_pci_sdmmc *host) | |||
| 1060 | return 0; | 1060 | return 0; |
| 1061 | } | 1061 | } |
| 1062 | 1062 | ||
| 1063 | static int sd_change_bank_voltage(struct realtek_pci_sdmmc *host, u8 voltage) | ||
| 1064 | { | ||
| 1065 | struct rtsx_pcr *pcr = host->pcr; | ||
| 1066 | int err; | ||
| 1067 | |||
| 1068 | if (voltage == SD_IO_3V3) { | ||
| 1069 | err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24); | ||
| 1070 | if (err < 0) | ||
| 1071 | return err; | ||
| 1072 | } else if (voltage == SD_IO_1V8) { | ||
| 1073 | err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C40 | 0x24); | ||
| 1074 | if (err < 0) | ||
| 1075 | return err; | ||
| 1076 | } else { | ||
| 1077 | return -EINVAL; | ||
| 1078 | } | ||
| 1079 | |||
| 1080 | return 0; | ||
| 1081 | } | ||
| 1082 | |||
| 1083 | static int sdmmc_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios) | 1063 | static int sdmmc_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios) |
| 1084 | { | 1064 | { |
| 1085 | struct realtek_pci_sdmmc *host = mmc_priv(mmc); | 1065 | struct realtek_pci_sdmmc *host = mmc_priv(mmc); |
| @@ -1098,11 +1078,11 @@ static int sdmmc_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios) | |||
| 1098 | rtsx_pci_start_run(pcr); | 1078 | rtsx_pci_start_run(pcr); |
| 1099 | 1079 | ||
| 1100 | if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) | 1080 | if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) |
| 1101 | voltage = SD_IO_3V3; | 1081 | voltage = OUTPUT_3V3; |
| 1102 | else | 1082 | else |
| 1103 | voltage = SD_IO_1V8; | 1083 | voltage = OUTPUT_1V8; |
| 1104 | 1084 | ||
| 1105 | if (voltage == SD_IO_1V8) { | 1085 | if (voltage == OUTPUT_1V8) { |
| 1106 | err = rtsx_pci_write_register(pcr, | 1086 | err = rtsx_pci_write_register(pcr, |
| 1107 | SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_B); | 1087 | SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_B); |
| 1108 | if (err < 0) | 1088 | if (err < 0) |
| @@ -1113,11 +1093,11 @@ static int sdmmc_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios) | |||
| 1113 | goto out; | 1093 | goto out; |
| 1114 | } | 1094 | } |
| 1115 | 1095 | ||
| 1116 | err = sd_change_bank_voltage(host, voltage); | 1096 | err = rtsx_pci_switch_output_voltage(pcr, voltage); |
| 1117 | if (err < 0) | 1097 | if (err < 0) |
| 1118 | goto out; | 1098 | goto out; |
| 1119 | 1099 | ||
| 1120 | if (voltage == SD_IO_1V8) { | 1100 | if (voltage == OUTPUT_1V8) { |
| 1121 | err = sd_wait_voltage_stable_2(host); | 1101 | err = sd_wait_voltage_stable_2(host); |
| 1122 | if (err < 0) | 1102 | if (err < 0) |
| 1123 | goto out; | 1103 | goto out; |
diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c index 5233b8f58d77..58607f196c9e 100644 --- a/drivers/net/can/c_can/c_can.c +++ b/drivers/net/can/c_can/c_can.c | |||
| @@ -960,7 +960,7 @@ static int c_can_handle_bus_err(struct net_device *dev, | |||
| 960 | break; | 960 | break; |
| 961 | case LEC_ACK_ERROR: | 961 | case LEC_ACK_ERROR: |
| 962 | netdev_dbg(dev, "ack error\n"); | 962 | netdev_dbg(dev, "ack error\n"); |
| 963 | cf->data[2] |= (CAN_ERR_PROT_LOC_ACK | | 963 | cf->data[3] |= (CAN_ERR_PROT_LOC_ACK | |
| 964 | CAN_ERR_PROT_LOC_ACK_DEL); | 964 | CAN_ERR_PROT_LOC_ACK_DEL); |
| 965 | break; | 965 | break; |
| 966 | case LEC_BIT1_ERROR: | 966 | case LEC_BIT1_ERROR: |
| @@ -973,7 +973,7 @@ static int c_can_handle_bus_err(struct net_device *dev, | |||
| 973 | break; | 973 | break; |
| 974 | case LEC_CRC_ERROR: | 974 | case LEC_CRC_ERROR: |
| 975 | netdev_dbg(dev, "CRC error\n"); | 975 | netdev_dbg(dev, "CRC error\n"); |
| 976 | cf->data[2] |= (CAN_ERR_PROT_LOC_CRC_SEQ | | 976 | cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ | |
| 977 | CAN_ERR_PROT_LOC_CRC_DEL); | 977 | CAN_ERR_PROT_LOC_CRC_DEL); |
| 978 | break; | 978 | break; |
| 979 | default: | 979 | default: |
diff --git a/drivers/net/can/pch_can.c b/drivers/net/can/pch_can.c index 7d1748575b1f..5c314a961970 100644 --- a/drivers/net/can/pch_can.c +++ b/drivers/net/can/pch_can.c | |||
| @@ -560,7 +560,7 @@ static void pch_can_error(struct net_device *ndev, u32 status) | |||
| 560 | stats->rx_errors++; | 560 | stats->rx_errors++; |
| 561 | break; | 561 | break; |
| 562 | case PCH_CRC_ERR: | 562 | case PCH_CRC_ERR: |
| 563 | cf->data[2] |= CAN_ERR_PROT_LOC_CRC_SEQ | | 563 | cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ | |
| 564 | CAN_ERR_PROT_LOC_CRC_DEL; | 564 | CAN_ERR_PROT_LOC_CRC_DEL; |
| 565 | priv->can.can_stats.bus_error++; | 565 | priv->can.can_stats.bus_error++; |
| 566 | stats->rx_errors++; | 566 | stats->rx_errors++; |
diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c index f898c6363729..300581b24ff3 100644 --- a/drivers/net/can/ti_hecc.c +++ b/drivers/net/can/ti_hecc.c | |||
| @@ -746,12 +746,12 @@ static int ti_hecc_error(struct net_device *ndev, int int_status, | |||
| 746 | } | 746 | } |
| 747 | if (err_status & HECC_CANES_CRCE) { | 747 | if (err_status & HECC_CANES_CRCE) { |
| 748 | hecc_set_bit(priv, HECC_CANES, HECC_CANES_CRCE); | 748 | hecc_set_bit(priv, HECC_CANES, HECC_CANES_CRCE); |
| 749 | cf->data[2] |= CAN_ERR_PROT_LOC_CRC_SEQ | | 749 | cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ | |
| 750 | CAN_ERR_PROT_LOC_CRC_DEL; | 750 | CAN_ERR_PROT_LOC_CRC_DEL; |
| 751 | } | 751 | } |
| 752 | if (err_status & HECC_CANES_ACKE) { | 752 | if (err_status & HECC_CANES_ACKE) { |
| 753 | hecc_set_bit(priv, HECC_CANES, HECC_CANES_ACKE); | 753 | hecc_set_bit(priv, HECC_CANES, HECC_CANES_ACKE); |
| 754 | cf->data[2] |= CAN_ERR_PROT_LOC_ACK | | 754 | cf->data[3] |= CAN_ERR_PROT_LOC_ACK | |
| 755 | CAN_ERR_PROT_LOC_ACK_DEL; | 755 | CAN_ERR_PROT_LOC_ACK_DEL; |
| 756 | } | 756 | } |
| 757 | } | 757 | } |
diff --git a/drivers/net/ethernet/3com/3c574_cs.c b/drivers/net/ethernet/3com/3c574_cs.c index 66df93638085..ffd8de28a76a 100644 --- a/drivers/net/ethernet/3com/3c574_cs.c +++ b/drivers/net/ethernet/3com/3c574_cs.c | |||
| @@ -432,7 +432,7 @@ static int tc574_config(struct pcmcia_device *link) | |||
| 432 | netdev_info(dev, "%s at io %#3lx, irq %d, hw_addr %pM\n", | 432 | netdev_info(dev, "%s at io %#3lx, irq %d, hw_addr %pM\n", |
| 433 | cardname, dev->base_addr, dev->irq, dev->dev_addr); | 433 | cardname, dev->base_addr, dev->irq, dev->dev_addr); |
| 434 | netdev_info(dev, " %dK FIFO split %s Rx:Tx, %sMII interface.\n", | 434 | netdev_info(dev, " %dK FIFO split %s Rx:Tx, %sMII interface.\n", |
| 435 | 8 << config & Ram_size, | 435 | 8 << (config & Ram_size), |
| 436 | ram_split[(config & Ram_split) >> Ram_split_shift], | 436 | ram_split[(config & Ram_split) >> Ram_split_shift], |
| 437 | config & Autoselect ? "autoselect " : ""); | 437 | config & Autoselect ? "autoselect " : ""); |
| 438 | 438 | ||
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/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 78ea90c40e19..bdb086934cd9 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c | |||
| @@ -1283,14 +1283,26 @@ static int tg3_phy_auxctl_write(struct tg3 *tp, int reg, u32 set) | |||
| 1283 | return tg3_writephy(tp, MII_TG3_AUX_CTRL, set | reg); | 1283 | return tg3_writephy(tp, MII_TG3_AUX_CTRL, set | reg); |
| 1284 | } | 1284 | } |
| 1285 | 1285 | ||
| 1286 | #define TG3_PHY_AUXCTL_SMDSP_ENABLE(tp) \ | 1286 | static int tg3_phy_toggle_auxctl_smdsp(struct tg3 *tp, bool enable) |
| 1287 | tg3_phy_auxctl_write((tp), MII_TG3_AUXCTL_SHDWSEL_AUXCTL, \ | 1287 | { |
| 1288 | MII_TG3_AUXCTL_ACTL_SMDSP_ENA | \ | 1288 | u32 val; |
| 1289 | MII_TG3_AUXCTL_ACTL_TX_6DB) | 1289 | int err; |
| 1290 | 1290 | ||
| 1291 | #define TG3_PHY_AUXCTL_SMDSP_DISABLE(tp) \ | 1291 | err = tg3_phy_auxctl_read(tp, MII_TG3_AUXCTL_SHDWSEL_AUXCTL, &val); |
| 1292 | tg3_phy_auxctl_write((tp), MII_TG3_AUXCTL_SHDWSEL_AUXCTL, \ | 1292 | |
| 1293 | MII_TG3_AUXCTL_ACTL_TX_6DB); | 1293 | if (err) |
| 1294 | return err; | ||
| 1295 | if (enable) | ||
| 1296 | |||
| 1297 | val |= MII_TG3_AUXCTL_ACTL_SMDSP_ENA; | ||
| 1298 | else | ||
| 1299 | val &= ~MII_TG3_AUXCTL_ACTL_SMDSP_ENA; | ||
| 1300 | |||
| 1301 | err = tg3_phy_auxctl_write((tp), MII_TG3_AUXCTL_SHDWSEL_AUXCTL, | ||
| 1302 | val | MII_TG3_AUXCTL_ACTL_TX_6DB); | ||
| 1303 | |||
| 1304 | return err; | ||
| 1305 | } | ||
| 1294 | 1306 | ||
| 1295 | static int tg3_bmcr_reset(struct tg3 *tp) | 1307 | static int tg3_bmcr_reset(struct tg3 *tp) |
| 1296 | { | 1308 | { |
| @@ -2223,7 +2235,7 @@ static void tg3_phy_apply_otp(struct tg3 *tp) | |||
| 2223 | 2235 | ||
| 2224 | otp = tp->phy_otp; | 2236 | otp = tp->phy_otp; |
| 2225 | 2237 | ||
| 2226 | if (TG3_PHY_AUXCTL_SMDSP_ENABLE(tp)) | 2238 | if (tg3_phy_toggle_auxctl_smdsp(tp, true)) |
| 2227 | return; | 2239 | return; |
| 2228 | 2240 | ||
| 2229 | phy = ((otp & TG3_OTP_AGCTGT_MASK) >> TG3_OTP_AGCTGT_SHIFT); | 2241 | phy = ((otp & TG3_OTP_AGCTGT_MASK) >> TG3_OTP_AGCTGT_SHIFT); |
| @@ -2248,7 +2260,7 @@ static void tg3_phy_apply_otp(struct tg3 *tp) | |||
| 2248 | ((otp & TG3_OTP_RCOFF_MASK) >> TG3_OTP_RCOFF_SHIFT); | 2260 | ((otp & TG3_OTP_RCOFF_MASK) >> TG3_OTP_RCOFF_SHIFT); |
| 2249 | tg3_phydsp_write(tp, MII_TG3_DSP_EXP97, phy); | 2261 | tg3_phydsp_write(tp, MII_TG3_DSP_EXP97, phy); |
| 2250 | 2262 | ||
| 2251 | TG3_PHY_AUXCTL_SMDSP_DISABLE(tp); | 2263 | tg3_phy_toggle_auxctl_smdsp(tp, false); |
| 2252 | } | 2264 | } |
| 2253 | 2265 | ||
| 2254 | static void tg3_phy_eee_adjust(struct tg3 *tp, u32 current_link_up) | 2266 | static void tg3_phy_eee_adjust(struct tg3 *tp, u32 current_link_up) |
| @@ -2284,9 +2296,9 @@ static void tg3_phy_eee_adjust(struct tg3 *tp, u32 current_link_up) | |||
| 2284 | 2296 | ||
| 2285 | if (!tp->setlpicnt) { | 2297 | if (!tp->setlpicnt) { |
| 2286 | if (current_link_up == 1 && | 2298 | if (current_link_up == 1 && |
| 2287 | !TG3_PHY_AUXCTL_SMDSP_ENABLE(tp)) { | 2299 | !tg3_phy_toggle_auxctl_smdsp(tp, true)) { |
| 2288 | tg3_phydsp_write(tp, MII_TG3_DSP_TAP26, 0x0000); | 2300 | tg3_phydsp_write(tp, MII_TG3_DSP_TAP26, 0x0000); |
| 2289 | TG3_PHY_AUXCTL_SMDSP_DISABLE(tp); | 2301 | tg3_phy_toggle_auxctl_smdsp(tp, false); |
| 2290 | } | 2302 | } |
| 2291 | 2303 | ||
| 2292 | val = tr32(TG3_CPMU_EEE_MODE); | 2304 | val = tr32(TG3_CPMU_EEE_MODE); |
| @@ -2302,11 +2314,11 @@ static void tg3_phy_eee_enable(struct tg3 *tp) | |||
| 2302 | (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || | 2314 | (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || |
| 2303 | GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || | 2315 | GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || |
| 2304 | tg3_flag(tp, 57765_CLASS)) && | 2316 | tg3_flag(tp, 57765_CLASS)) && |
| 2305 | !TG3_PHY_AUXCTL_SMDSP_ENABLE(tp)) { | 2317 | !tg3_phy_toggle_auxctl_smdsp(tp, true)) { |
| 2306 | val = MII_TG3_DSP_TAP26_ALNOKO | | 2318 | val = MII_TG3_DSP_TAP26_ALNOKO | |
| 2307 | MII_TG3_DSP_TAP26_RMRXSTO; | 2319 | MII_TG3_DSP_TAP26_RMRXSTO; |
| 2308 | tg3_phydsp_write(tp, MII_TG3_DSP_TAP26, val); | 2320 | tg3_phydsp_write(tp, MII_TG3_DSP_TAP26, val); |
| 2309 | TG3_PHY_AUXCTL_SMDSP_DISABLE(tp); | 2321 | tg3_phy_toggle_auxctl_smdsp(tp, false); |
| 2310 | } | 2322 | } |
| 2311 | 2323 | ||
| 2312 | val = tr32(TG3_CPMU_EEE_MODE); | 2324 | val = tr32(TG3_CPMU_EEE_MODE); |
| @@ -2450,7 +2462,7 @@ static int tg3_phy_reset_5703_4_5(struct tg3 *tp) | |||
| 2450 | tg3_writephy(tp, MII_CTRL1000, | 2462 | tg3_writephy(tp, MII_CTRL1000, |
| 2451 | CTL1000_AS_MASTER | CTL1000_ENABLE_MASTER); | 2463 | CTL1000_AS_MASTER | CTL1000_ENABLE_MASTER); |
| 2452 | 2464 | ||
| 2453 | err = TG3_PHY_AUXCTL_SMDSP_ENABLE(tp); | 2465 | err = tg3_phy_toggle_auxctl_smdsp(tp, true); |
| 2454 | if (err) | 2466 | if (err) |
| 2455 | return err; | 2467 | return err; |
| 2456 | 2468 | ||
| @@ -2471,7 +2483,7 @@ static int tg3_phy_reset_5703_4_5(struct tg3 *tp) | |||
| 2471 | tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8200); | 2483 | tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8200); |
| 2472 | tg3_writephy(tp, MII_TG3_DSP_CONTROL, 0x0000); | 2484 | tg3_writephy(tp, MII_TG3_DSP_CONTROL, 0x0000); |
| 2473 | 2485 | ||
| 2474 | TG3_PHY_AUXCTL_SMDSP_DISABLE(tp); | 2486 | tg3_phy_toggle_auxctl_smdsp(tp, false); |
| 2475 | 2487 | ||
| 2476 | tg3_writephy(tp, MII_CTRL1000, phy9_orig); | 2488 | tg3_writephy(tp, MII_CTRL1000, phy9_orig); |
| 2477 | 2489 | ||
| @@ -2572,10 +2584,10 @@ static int tg3_phy_reset(struct tg3 *tp) | |||
| 2572 | 2584 | ||
| 2573 | out: | 2585 | out: |
| 2574 | if ((tp->phy_flags & TG3_PHYFLG_ADC_BUG) && | 2586 | if ((tp->phy_flags & TG3_PHYFLG_ADC_BUG) && |
| 2575 | !TG3_PHY_AUXCTL_SMDSP_ENABLE(tp)) { | 2587 | !tg3_phy_toggle_auxctl_smdsp(tp, true)) { |
| 2576 | tg3_phydsp_write(tp, 0x201f, 0x2aaa); | 2588 | tg3_phydsp_write(tp, 0x201f, 0x2aaa); |
| 2577 | tg3_phydsp_write(tp, 0x000a, 0x0323); | 2589 | tg3_phydsp_write(tp, 0x000a, 0x0323); |
| 2578 | TG3_PHY_AUXCTL_SMDSP_DISABLE(tp); | 2590 | tg3_phy_toggle_auxctl_smdsp(tp, false); |
| 2579 | } | 2591 | } |
| 2580 | 2592 | ||
| 2581 | if (tp->phy_flags & TG3_PHYFLG_5704_A0_BUG) { | 2593 | if (tp->phy_flags & TG3_PHYFLG_5704_A0_BUG) { |
| @@ -2584,14 +2596,14 @@ out: | |||
| 2584 | } | 2596 | } |
| 2585 | 2597 | ||
| 2586 | if (tp->phy_flags & TG3_PHYFLG_BER_BUG) { | 2598 | if (tp->phy_flags & TG3_PHYFLG_BER_BUG) { |
| 2587 | if (!TG3_PHY_AUXCTL_SMDSP_ENABLE(tp)) { | 2599 | if (!tg3_phy_toggle_auxctl_smdsp(tp, true)) { |
| 2588 | tg3_phydsp_write(tp, 0x000a, 0x310b); | 2600 | tg3_phydsp_write(tp, 0x000a, 0x310b); |
| 2589 | tg3_phydsp_write(tp, 0x201f, 0x9506); | 2601 | tg3_phydsp_write(tp, 0x201f, 0x9506); |
| 2590 | tg3_phydsp_write(tp, 0x401f, 0x14e2); | 2602 | tg3_phydsp_write(tp, 0x401f, 0x14e2); |
| 2591 | TG3_PHY_AUXCTL_SMDSP_DISABLE(tp); | 2603 | tg3_phy_toggle_auxctl_smdsp(tp, false); |
| 2592 | } | 2604 | } |
| 2593 | } else if (tp->phy_flags & TG3_PHYFLG_JITTER_BUG) { | 2605 | } else if (tp->phy_flags & TG3_PHYFLG_JITTER_BUG) { |
| 2594 | if (!TG3_PHY_AUXCTL_SMDSP_ENABLE(tp)) { | 2606 | if (!tg3_phy_toggle_auxctl_smdsp(tp, true)) { |
| 2595 | tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x000a); | 2607 | tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x000a); |
| 2596 | if (tp->phy_flags & TG3_PHYFLG_ADJUST_TRIM) { | 2608 | if (tp->phy_flags & TG3_PHYFLG_ADJUST_TRIM) { |
| 2597 | tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x110b); | 2609 | tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x110b); |
| @@ -2600,7 +2612,7 @@ out: | |||
| 2600 | } else | 2612 | } else |
| 2601 | tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x010b); | 2613 | tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x010b); |
| 2602 | 2614 | ||
| 2603 | TG3_PHY_AUXCTL_SMDSP_DISABLE(tp); | 2615 | tg3_phy_toggle_auxctl_smdsp(tp, false); |
| 2604 | } | 2616 | } |
| 2605 | } | 2617 | } |
| 2606 | 2618 | ||
| @@ -4009,7 +4021,7 @@ static int tg3_phy_autoneg_cfg(struct tg3 *tp, u32 advertise, u32 flowctrl) | |||
| 4009 | tw32(TG3_CPMU_EEE_MODE, | 4021 | tw32(TG3_CPMU_EEE_MODE, |
| 4010 | tr32(TG3_CPMU_EEE_MODE) & ~TG3_CPMU_EEEMD_LPI_ENABLE); | 4022 | tr32(TG3_CPMU_EEE_MODE) & ~TG3_CPMU_EEEMD_LPI_ENABLE); |
| 4011 | 4023 | ||
| 4012 | err = TG3_PHY_AUXCTL_SMDSP_ENABLE(tp); | 4024 | err = tg3_phy_toggle_auxctl_smdsp(tp, true); |
| 4013 | if (!err) { | 4025 | if (!err) { |
| 4014 | u32 err2; | 4026 | u32 err2; |
| 4015 | 4027 | ||
| @@ -4042,7 +4054,7 @@ static int tg3_phy_autoneg_cfg(struct tg3 *tp, u32 advertise, u32 flowctrl) | |||
| 4042 | MII_TG3_DSP_CH34TP2_HIBW01); | 4054 | MII_TG3_DSP_CH34TP2_HIBW01); |
| 4043 | } | 4055 | } |
| 4044 | 4056 | ||
| 4045 | err2 = TG3_PHY_AUXCTL_SMDSP_DISABLE(tp); | 4057 | err2 = tg3_phy_toggle_auxctl_smdsp(tp, false); |
| 4046 | if (!err) | 4058 | if (!err) |
| 4047 | err = err2; | 4059 | err = err2; |
| 4048 | } | 4060 | } |
| @@ -6950,6 +6962,9 @@ static void tg3_poll_controller(struct net_device *dev) | |||
| 6950 | int i; | 6962 | int i; |
| 6951 | struct tg3 *tp = netdev_priv(dev); | 6963 | struct tg3 *tp = netdev_priv(dev); |
| 6952 | 6964 | ||
| 6965 | if (tg3_irq_sync(tp)) | ||
| 6966 | return; | ||
| 6967 | |||
| 6953 | for (i = 0; i < tp->irq_cnt; i++) | 6968 | for (i = 0; i < tp->irq_cnt; i++) |
| 6954 | tg3_interrupt(tp->napi[i].irq_vec, &tp->napi[i]); | 6969 | tg3_interrupt(tp->napi[i].irq_vec, &tp->napi[i]); |
| 6955 | } | 6970 | } |
| @@ -16367,6 +16382,7 @@ static int tg3_init_one(struct pci_dev *pdev, | |||
| 16367 | tp->pm_cap = pm_cap; | 16382 | tp->pm_cap = pm_cap; |
| 16368 | tp->rx_mode = TG3_DEF_RX_MODE; | 16383 | tp->rx_mode = TG3_DEF_RX_MODE; |
| 16369 | tp->tx_mode = TG3_DEF_TX_MODE; | 16384 | tp->tx_mode = TG3_DEF_TX_MODE; |
| 16385 | tp->irq_sync = 1; | ||
| 16370 | 16386 | ||
| 16371 | if (tg3_debug > 0) | 16387 | if (tg3_debug > 0) |
| 16372 | tp->msg_enable = tg3_debug; | 16388 | tp->msg_enable = tg3_debug; |
diff --git a/drivers/net/ethernet/calxeda/xgmac.c b/drivers/net/ethernet/calxeda/xgmac.c index b407043ce9b0..f7f02900f650 100644 --- a/drivers/net/ethernet/calxeda/xgmac.c +++ b/drivers/net/ethernet/calxeda/xgmac.c | |||
| @@ -548,6 +548,10 @@ static int desc_get_rx_status(struct xgmac_priv *priv, struct xgmac_dma_desc *p) | |||
| 548 | return -1; | 548 | return -1; |
| 549 | } | 549 | } |
| 550 | 550 | ||
| 551 | /* All frames should fit into a single buffer */ | ||
| 552 | if (!(status & RXDESC_FIRST_SEG) || !(status & RXDESC_LAST_SEG)) | ||
| 553 | return -1; | ||
| 554 | |||
| 551 | /* Check if packet has checksum already */ | 555 | /* Check if packet has checksum already */ |
| 552 | if ((status & RXDESC_FRAME_TYPE) && (status & RXDESC_EXT_STATUS) && | 556 | if ((status & RXDESC_FRAME_TYPE) && (status & RXDESC_EXT_STATUS) && |
| 553 | !(ext_status & RXDESC_IP_PAYLOAD_MASK)) | 557 | !(ext_status & RXDESC_IP_PAYLOAD_MASK)) |
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index f0718e1a8369..c306df7d4568 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | |||
| @@ -1994,9 +1994,20 @@ static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c) | |||
| 1994 | { | 1994 | { |
| 1995 | const struct port_info *pi = netdev_priv(dev); | 1995 | const struct port_info *pi = netdev_priv(dev); |
| 1996 | struct adapter *adap = pi->adapter; | 1996 | struct adapter *adap = pi->adapter; |
| 1997 | 1997 | struct sge_rspq *q; | |
| 1998 | return set_rxq_intr_params(adap, &adap->sge.ethrxq[pi->first_qset].rspq, | 1998 | int i; |
| 1999 | c->rx_coalesce_usecs, c->rx_max_coalesced_frames); | 1999 | int r = 0; |
| 2000 | |||
| 2001 | for (i = pi->first_qset; i < pi->first_qset + pi->nqsets; i++) { | ||
| 2002 | q = &adap->sge.ethrxq[i].rspq; | ||
| 2003 | r = set_rxq_intr_params(adap, q, c->rx_coalesce_usecs, | ||
| 2004 | c->rx_max_coalesced_frames); | ||
| 2005 | if (r) { | ||
| 2006 | dev_err(&dev->dev, "failed to set coalesce %d\n", r); | ||
| 2007 | break; | ||
| 2008 | } | ||
| 2009 | } | ||
| 2010 | return r; | ||
| 2000 | } | 2011 | } |
| 2001 | 2012 | ||
| 2002 | static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c) | 2013 | static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c) |
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/intel/ixgbe/Makefile b/drivers/net/ethernet/intel/ixgbe/Makefile index f3a632bf8d96..687c83d1bdab 100644 --- a/drivers/net/ethernet/intel/ixgbe/Makefile +++ b/drivers/net/ethernet/intel/ixgbe/Makefile | |||
| @@ -32,7 +32,7 @@ | |||
| 32 | 32 | ||
| 33 | obj-$(CONFIG_IXGBE) += ixgbe.o | 33 | obj-$(CONFIG_IXGBE) += ixgbe.o |
| 34 | 34 | ||
| 35 | ixgbe-objs := ixgbe_main.o ixgbe_common.o ixgbe_ethtool.o ixgbe_debugfs.o\ | 35 | ixgbe-objs := ixgbe_main.o ixgbe_common.o ixgbe_ethtool.o \ |
| 36 | ixgbe_82599.o ixgbe_82598.o ixgbe_phy.o ixgbe_sriov.o \ | 36 | ixgbe_82599.o ixgbe_82598.o ixgbe_phy.o ixgbe_sriov.o \ |
| 37 | ixgbe_mbx.o ixgbe_x540.o ixgbe_lib.o ixgbe_ptp.o | 37 | ixgbe_mbx.o ixgbe_x540.o ixgbe_lib.o ixgbe_ptp.o |
| 38 | 38 | ||
| @@ -40,4 +40,5 @@ ixgbe-$(CONFIG_IXGBE_DCB) += ixgbe_dcb.o ixgbe_dcb_82598.o \ | |||
| 40 | ixgbe_dcb_82599.o ixgbe_dcb_nl.o | 40 | ixgbe_dcb_82599.o ixgbe_dcb_nl.o |
| 41 | 41 | ||
| 42 | ixgbe-$(CONFIG_IXGBE_HWMON) += ixgbe_sysfs.o | 42 | ixgbe-$(CONFIG_IXGBE_HWMON) += ixgbe_sysfs.o |
| 43 | ixgbe-$(CONFIG_DEBUG_FS) += ixgbe_debugfs.o | ||
| 43 | ixgbe-$(CONFIG_FCOE:m=y) += ixgbe_fcoe.o | 44 | ixgbe-$(CONFIG_FCOE:m=y) += ixgbe_fcoe.o |
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c index 50aa546b8c7a..3504686d3af5 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c | |||
| @@ -24,9 +24,6 @@ | |||
| 24 | Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | 24 | Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 |
| 25 | 25 | ||
| 26 | *******************************************************************************/ | 26 | *******************************************************************************/ |
| 27 | |||
| 28 | #ifdef CONFIG_DEBUG_FS | ||
| 29 | |||
| 30 | #include <linux/debugfs.h> | 27 | #include <linux/debugfs.h> |
| 31 | #include <linux/module.h> | 28 | #include <linux/module.h> |
| 32 | 29 | ||
| @@ -277,5 +274,3 @@ void ixgbe_dbg_exit(void) | |||
| 277 | { | 274 | { |
| 278 | debugfs_remove_recursive(ixgbe_dbg_root); | 275 | debugfs_remove_recursive(ixgbe_dbg_root); |
| 279 | } | 276 | } |
| 280 | |||
| 281 | #endif /* CONFIG_DEBUG_FS */ | ||
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c index 1a751c9d09c4..bb9256a1b0a9 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c | |||
| @@ -660,11 +660,11 @@ int ixgbe_ptp_hwtstamp_ioctl(struct ixgbe_adapter *adapter, | |||
| 660 | break; | 660 | break; |
| 661 | case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: | 661 | case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: |
| 662 | tsync_rx_ctl |= IXGBE_TSYNCRXCTL_TYPE_L4_V1; | 662 | tsync_rx_ctl |= IXGBE_TSYNCRXCTL_TYPE_L4_V1; |
| 663 | tsync_rx_mtrl = IXGBE_RXMTRL_V1_SYNC_MSG; | 663 | tsync_rx_mtrl |= IXGBE_RXMTRL_V1_SYNC_MSG; |
| 664 | break; | 664 | break; |
| 665 | case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: | 665 | case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: |
| 666 | tsync_rx_ctl |= IXGBE_TSYNCRXCTL_TYPE_L4_V1; | 666 | tsync_rx_ctl |= IXGBE_TSYNCRXCTL_TYPE_L4_V1; |
| 667 | tsync_rx_mtrl = IXGBE_RXMTRL_V1_DELAY_REQ_MSG; | 667 | tsync_rx_mtrl |= IXGBE_RXMTRL_V1_DELAY_REQ_MSG; |
| 668 | break; | 668 | break; |
| 669 | case HWTSTAMP_FILTER_PTP_V2_EVENT: | 669 | case HWTSTAMP_FILTER_PTP_V2_EVENT: |
| 670 | case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: | 670 | case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: |
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c index 2b799f4f1c37..6771b69f40d5 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c | |||
| @@ -630,10 +630,15 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 630 | ring->tx_csum++; | 630 | ring->tx_csum++; |
| 631 | } | 631 | } |
| 632 | 632 | ||
| 633 | /* Copy dst mac address to wqe */ | 633 | if (mlx4_is_mfunc(mdev->dev) || priv->validate_loopback) { |
| 634 | ethh = (struct ethhdr *)skb->data; | 634 | /* Copy dst mac address to wqe. This allows loopback in eSwitch, |
| 635 | tx_desc->ctrl.srcrb_flags16[0] = get_unaligned((__be16 *)ethh->h_dest); | 635 | * so that VFs and PF can communicate with each other |
| 636 | tx_desc->ctrl.imm = get_unaligned((__be32 *)(ethh->h_dest + 2)); | 636 | */ |
| 637 | ethh = (struct ethhdr *)skb->data; | ||
| 638 | tx_desc->ctrl.srcrb_flags16[0] = get_unaligned((__be16 *)ethh->h_dest); | ||
| 639 | tx_desc->ctrl.imm = get_unaligned((__be32 *)(ethh->h_dest + 2)); | ||
| 640 | } | ||
| 641 | |||
| 637 | /* Handle LSO (TSO) packets */ | 642 | /* Handle LSO (TSO) packets */ |
| 638 | if (lso_header_size) { | 643 | if (lso_header_size) { |
| 639 | /* Mark opcode as LSO */ | 644 | /* Mark opcode as LSO */ |
diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index e1bafffbc3b1..a6542d75374c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c | |||
| @@ -1790,15 +1790,8 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev) | |||
| 1790 | int i; | 1790 | int i; |
| 1791 | 1791 | ||
| 1792 | if (msi_x) { | 1792 | if (msi_x) { |
| 1793 | /* In multifunction mode each function gets 2 msi-X vectors | 1793 | nreq = min_t(int, dev->caps.num_eqs - dev->caps.reserved_eqs, |
| 1794 | * one for data path completions anf the other for asynch events | 1794 | nreq); |
| 1795 | * or command completions */ | ||
| 1796 | if (mlx4_is_mfunc(dev)) { | ||
| 1797 | nreq = 2; | ||
| 1798 | } else { | ||
| 1799 | nreq = min_t(int, dev->caps.num_eqs - | ||
| 1800 | dev->caps.reserved_eqs, nreq); | ||
| 1801 | } | ||
| 1802 | 1795 | ||
| 1803 | entries = kcalloc(nreq, sizeof *entries, GFP_KERNEL); | 1796 | entries = kcalloc(nreq, sizeof *entries, GFP_KERNEL); |
| 1804 | if (!entries) | 1797 | if (!entries) |
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c index bc165f4d0f65..695667d471a1 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c | |||
| @@ -144,7 +144,7 @@ void netxen_release_tx_buffers(struct netxen_adapter *adapter) | |||
| 144 | buffrag->length, PCI_DMA_TODEVICE); | 144 | buffrag->length, PCI_DMA_TODEVICE); |
| 145 | buffrag->dma = 0ULL; | 145 | buffrag->dma = 0ULL; |
| 146 | } | 146 | } |
| 147 | for (j = 0; j < cmd_buf->frag_count; j++) { | 147 | for (j = 1; j < cmd_buf->frag_count; j++) { |
| 148 | buffrag++; | 148 | buffrag++; |
| 149 | if (buffrag->dma) { | 149 | if (buffrag->dma) { |
| 150 | pci_unmap_page(adapter->pdev, buffrag->dma, | 150 | pci_unmap_page(adapter->pdev, buffrag->dma, |
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c index 6098fd4adfeb..69e321a65077 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c | |||
| @@ -1963,10 +1963,12 @@ unwind: | |||
| 1963 | while (--i >= 0) { | 1963 | while (--i >= 0) { |
| 1964 | nf = &pbuf->frag_array[i+1]; | 1964 | nf = &pbuf->frag_array[i+1]; |
| 1965 | pci_unmap_page(pdev, nf->dma, nf->length, PCI_DMA_TODEVICE); | 1965 | pci_unmap_page(pdev, nf->dma, nf->length, PCI_DMA_TODEVICE); |
| 1966 | nf->dma = 0ULL; | ||
| 1966 | } | 1967 | } |
| 1967 | 1968 | ||
| 1968 | nf = &pbuf->frag_array[0]; | 1969 | nf = &pbuf->frag_array[0]; |
| 1969 | pci_unmap_single(pdev, nf->dma, skb_headlen(skb), PCI_DMA_TODEVICE); | 1970 | pci_unmap_single(pdev, nf->dma, skb_headlen(skb), PCI_DMA_TODEVICE); |
| 1971 | nf->dma = 0ULL; | ||
| 1970 | 1972 | ||
| 1971 | out_err: | 1973 | out_err: |
| 1972 | return -ENOMEM; | 1974 | return -ENOMEM; |
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/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index ed96f309bca8..11702324a071 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c | |||
| @@ -1826,8 +1826,6 @@ static void rtl8169_rx_vlan_tag(struct RxDesc *desc, struct sk_buff *skb) | |||
| 1826 | 1826 | ||
| 1827 | if (opts2 & RxVlanTag) | 1827 | if (opts2 & RxVlanTag) |
| 1828 | __vlan_hwaccel_put_tag(skb, swab16(opts2 & 0xffff)); | 1828 | __vlan_hwaccel_put_tag(skb, swab16(opts2 & 0xffff)); |
| 1829 | |||
| 1830 | desc->opts2 = 0; | ||
| 1831 | } | 1829 | } |
| 1832 | 1830 | ||
| 1833 | static int rtl8169_gset_tbi(struct net_device *dev, struct ethtool_cmd *cmd) | 1831 | static int rtl8169_gset_tbi(struct net_device *dev, struct ethtool_cmd *cmd) |
| @@ -6064,8 +6062,6 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, u32 budget | |||
| 6064 | !(status & (RxRWT | RxFOVF)) && | 6062 | !(status & (RxRWT | RxFOVF)) && |
| 6065 | (dev->features & NETIF_F_RXALL)) | 6063 | (dev->features & NETIF_F_RXALL)) |
| 6066 | goto process_pkt; | 6064 | goto process_pkt; |
| 6067 | |||
| 6068 | rtl8169_mark_to_asic(desc, rx_buf_sz); | ||
| 6069 | } else { | 6065 | } else { |
| 6070 | struct sk_buff *skb; | 6066 | struct sk_buff *skb; |
| 6071 | dma_addr_t addr; | 6067 | dma_addr_t addr; |
| @@ -6086,16 +6082,14 @@ process_pkt: | |||
| 6086 | if (unlikely(rtl8169_fragmented_frame(status))) { | 6082 | if (unlikely(rtl8169_fragmented_frame(status))) { |
| 6087 | dev->stats.rx_dropped++; | 6083 | dev->stats.rx_dropped++; |
| 6088 | dev->stats.rx_length_errors++; | 6084 | dev->stats.rx_length_errors++; |
| 6089 | rtl8169_mark_to_asic(desc, rx_buf_sz); | 6085 | goto release_descriptor; |
| 6090 | continue; | ||
| 6091 | } | 6086 | } |
| 6092 | 6087 | ||
| 6093 | skb = rtl8169_try_rx_copy(tp->Rx_databuff[entry], | 6088 | skb = rtl8169_try_rx_copy(tp->Rx_databuff[entry], |
| 6094 | tp, pkt_size, addr); | 6089 | tp, pkt_size, addr); |
| 6095 | rtl8169_mark_to_asic(desc, rx_buf_sz); | ||
| 6096 | if (!skb) { | 6090 | if (!skb) { |
| 6097 | dev->stats.rx_dropped++; | 6091 | dev->stats.rx_dropped++; |
| 6098 | continue; | 6092 | goto release_descriptor; |
| 6099 | } | 6093 | } |
| 6100 | 6094 | ||
| 6101 | rtl8169_rx_csum(skb, status); | 6095 | rtl8169_rx_csum(skb, status); |
| @@ -6111,13 +6105,10 @@ process_pkt: | |||
| 6111 | tp->rx_stats.bytes += pkt_size; | 6105 | tp->rx_stats.bytes += pkt_size; |
| 6112 | u64_stats_update_end(&tp->rx_stats.syncp); | 6106 | u64_stats_update_end(&tp->rx_stats.syncp); |
| 6113 | } | 6107 | } |
| 6114 | 6108 | release_descriptor: | |
| 6115 | /* Work around for AMD plateform. */ | 6109 | desc->opts2 = 0; |
| 6116 | if ((desc->opts2 & cpu_to_le32(0xfffe000)) && | 6110 | wmb(); |
| 6117 | (tp->mac_version == RTL_GIGA_MAC_VER_05)) { | 6111 | rtl8169_mark_to_asic(desc, rx_buf_sz); |
| 6118 | desc->opts2 = 0; | ||
| 6119 | cur_rx++; | ||
| 6120 | } | ||
| 6121 | } | 6112 | } |
| 6122 | 6113 | ||
| 6123 | count = cur_rx - tp->cur_rx; | 6114 | count = cur_rx - tp->cur_rx; |
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/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 5fd6f4674326..e6fe0d80d612 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h | |||
| @@ -84,7 +84,7 @@ struct hv_netvsc_packet { | |||
| 84 | }; | 84 | }; |
| 85 | 85 | ||
| 86 | struct netvsc_device_info { | 86 | struct netvsc_device_info { |
| 87 | unsigned char mac_adr[6]; | 87 | unsigned char mac_adr[ETH_ALEN]; |
| 88 | bool link_state; /* 0 - link up, 1 - link down */ | 88 | bool link_state; /* 0 - link up, 1 - link down */ |
| 89 | int ring_size; | 89 | int ring_size; |
| 90 | }; | 90 | }; |
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index f825a629a699..8264f0ef7692 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c | |||
| @@ -349,7 +349,7 @@ static int netvsc_set_mac_addr(struct net_device *ndev, void *p) | |||
| 349 | struct net_device_context *ndevctx = netdev_priv(ndev); | 349 | struct net_device_context *ndevctx = netdev_priv(ndev); |
| 350 | struct hv_device *hdev = ndevctx->device_ctx; | 350 | struct hv_device *hdev = ndevctx->device_ctx; |
| 351 | struct sockaddr *addr = p; | 351 | struct sockaddr *addr = p; |
| 352 | char save_adr[14]; | 352 | char save_adr[ETH_ALEN]; |
| 353 | unsigned char save_aatype; | 353 | unsigned char save_aatype; |
| 354 | int err; | 354 | int err; |
| 355 | 355 | ||
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 81f8f9e31db5..fcbf680c3e62 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c | |||
| @@ -77,6 +77,11 @@ static netdev_tx_t loopback_xmit(struct sk_buff *skb, | |||
| 77 | 77 | ||
| 78 | skb_orphan(skb); | 78 | skb_orphan(skb); |
| 79 | 79 | ||
| 80 | /* Before queueing this packet to netif_rx(), | ||
| 81 | * make sure dst is refcounted. | ||
| 82 | */ | ||
| 83 | skb_dst_force(skb); | ||
| 84 | |||
| 80 | skb->protocol = eth_type_trans(skb, dev); | 85 | skb->protocol = eth_type_trans(skb, dev); |
| 81 | 86 | ||
| 82 | /* it's OK to use per_cpu_ptr() because BHs are off */ | 87 | /* it's OK to use per_cpu_ptr() because BHs are off */ |
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 68a43fe602e7..d3fb97d97cbc 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c | |||
| @@ -822,7 +822,10 @@ static int macvlan_changelink(struct net_device *dev, | |||
| 822 | 822 | ||
| 823 | static size_t macvlan_get_size(const struct net_device *dev) | 823 | static size_t macvlan_get_size(const struct net_device *dev) |
| 824 | { | 824 | { |
| 825 | return nla_total_size(4); | 825 | return (0 |
| 826 | + nla_total_size(4) /* IFLA_MACVLAN_MODE */ | ||
| 827 | + nla_total_size(2) /* IFLA_MACVLAN_FLAGS */ | ||
| 828 | ); | ||
| 826 | } | 829 | } |
| 827 | 830 | ||
| 828 | static int macvlan_fill_info(struct sk_buff *skb, | 831 | static int macvlan_fill_info(struct sk_buff *skb, |
diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c index d5199cb4caec..b5ddd5077a80 100644 --- a/drivers/net/phy/icplus.c +++ b/drivers/net/phy/icplus.c | |||
| @@ -36,8 +36,9 @@ MODULE_LICENSE("GPL"); | |||
| 36 | 36 | ||
| 37 | /* IP101A/G - IP1001 */ | 37 | /* IP101A/G - IP1001 */ |
| 38 | #define IP10XX_SPEC_CTRL_STATUS 16 /* Spec. Control Register */ | 38 | #define IP10XX_SPEC_CTRL_STATUS 16 /* Spec. Control Register */ |
| 39 | #define IP1001_RXPHASE_SEL (1<<0) /* Add delay on RX_CLK */ | ||
| 40 | #define IP1001_TXPHASE_SEL (1<<1) /* Add delay on TX_CLK */ | ||
| 39 | #define IP1001_SPEC_CTRL_STATUS_2 20 /* IP1001 Spec. Control Reg 2 */ | 41 | #define IP1001_SPEC_CTRL_STATUS_2 20 /* IP1001 Spec. Control Reg 2 */ |
| 40 | #define IP1001_PHASE_SEL_MASK 3 /* IP1001 RX/TXPHASE_SEL */ | ||
| 41 | #define IP1001_APS_ON 11 /* IP1001 APS Mode bit */ | 42 | #define IP1001_APS_ON 11 /* IP1001 APS Mode bit */ |
| 42 | #define IP101A_G_APS_ON 2 /* IP101A/G APS Mode bit */ | 43 | #define IP101A_G_APS_ON 2 /* IP101A/G APS Mode bit */ |
| 43 | #define IP101A_G_IRQ_CONF_STATUS 0x11 /* Conf Info IRQ & Status Reg */ | 44 | #define IP101A_G_IRQ_CONF_STATUS 0x11 /* Conf Info IRQ & Status Reg */ |
| @@ -138,19 +139,24 @@ static int ip1001_config_init(struct phy_device *phydev) | |||
| 138 | if (c < 0) | 139 | if (c < 0) |
| 139 | return c; | 140 | return c; |
| 140 | 141 | ||
| 141 | /* INTR pin used: speed/link/duplex will cause an interrupt */ | 142 | if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) || |
| 142 | c = phy_write(phydev, IP101A_G_IRQ_CONF_STATUS, IP101A_G_IRQ_DEFAULT); | 143 | (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) || |
| 143 | if (c < 0) | 144 | (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) || |
| 144 | return c; | 145 | (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) { |
| 145 | 146 | ||
| 146 | if (phydev->interface == PHY_INTERFACE_MODE_RGMII) { | ||
| 147 | /* Additional delay (2ns) used to adjust RX clock phase | ||
| 148 | * at RGMII interface */ | ||
| 149 | c = phy_read(phydev, IP10XX_SPEC_CTRL_STATUS); | 147 | c = phy_read(phydev, IP10XX_SPEC_CTRL_STATUS); |
| 150 | if (c < 0) | 148 | if (c < 0) |
| 151 | return c; | 149 | return c; |
| 152 | 150 | ||
| 153 | c |= IP1001_PHASE_SEL_MASK; | 151 | c &= ~(IP1001_RXPHASE_SEL | IP1001_TXPHASE_SEL); |
| 152 | |||
| 153 | if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) | ||
| 154 | c |= (IP1001_RXPHASE_SEL | IP1001_TXPHASE_SEL); | ||
| 155 | else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) | ||
| 156 | c |= IP1001_RXPHASE_SEL; | ||
| 157 | else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) | ||
| 158 | c |= IP1001_TXPHASE_SEL; | ||
| 159 | |||
| 154 | c = phy_write(phydev, IP10XX_SPEC_CTRL_STATUS, c); | 160 | c = phy_write(phydev, IP10XX_SPEC_CTRL_STATUS, c); |
| 155 | if (c < 0) | 161 | if (c < 0) |
| 156 | return c; | 162 | return c; |
| @@ -167,6 +173,11 @@ static int ip101a_g_config_init(struct phy_device *phydev) | |||
| 167 | if (c < 0) | 173 | if (c < 0) |
| 168 | return c; | 174 | return c; |
| 169 | 175 | ||
| 176 | /* INTR pin used: speed/link/duplex will cause an interrupt */ | ||
| 177 | c = phy_write(phydev, IP101A_G_IRQ_CONF_STATUS, IP101A_G_IRQ_DEFAULT); | ||
| 178 | if (c < 0) | ||
| 179 | return c; | ||
| 180 | |||
| 170 | /* Enable Auto Power Saving mode */ | 181 | /* Enable Auto Power Saving mode */ |
| 171 | c = phy_read(phydev, IP10XX_SPEC_CTRL_STATUS); | 182 | c = phy_read(phydev, IP10XX_SPEC_CTRL_STATUS); |
| 172 | c |= IP101A_G_APS_ON; | 183 | c |= IP101A_G_APS_ON; |
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 5d2a3f215887..22dec9c7ef05 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c | |||
| @@ -353,15 +353,6 @@ static int m88e1111_config_init(struct phy_device *phydev) | |||
| 353 | int err; | 353 | int err; |
| 354 | int temp; | 354 | int temp; |
| 355 | 355 | ||
| 356 | /* Enable Fiber/Copper auto selection */ | ||
| 357 | temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); | ||
| 358 | temp &= ~MII_M1111_HWCFG_FIBER_COPPER_AUTO; | ||
| 359 | phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); | ||
| 360 | |||
| 361 | temp = phy_read(phydev, MII_BMCR); | ||
| 362 | temp |= BMCR_RESET; | ||
| 363 | phy_write(phydev, MII_BMCR, temp); | ||
| 364 | |||
| 365 | if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) || | 356 | if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) || |
| 366 | (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) || | 357 | (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) || |
| 367 | (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) || | 358 | (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) || |
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index fbd106edbe59..cc09b67c23bc 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c | |||
| @@ -109,11 +109,11 @@ struct tap_filter { | |||
| 109 | unsigned char addr[FLT_EXACT_COUNT][ETH_ALEN]; | 109 | unsigned char addr[FLT_EXACT_COUNT][ETH_ALEN]; |
| 110 | }; | 110 | }; |
| 111 | 111 | ||
| 112 | /* 1024 is probably a high enough limit: modern hypervisors seem to support on | 112 | /* DEFAULT_MAX_NUM_RSS_QUEUES were choosed to let the rx/tx queues allocated for |
| 113 | * the order of 100-200 CPUs so this leaves us some breathing space if we want | 113 | * the netdevice to be fit in one page. So we can make sure the success of |
| 114 | * to match a queue per guest CPU. | 114 | * memory allocation. TODO: increase the limit. */ |
| 115 | */ | 115 | #define MAX_TAP_QUEUES DEFAULT_MAX_NUM_RSS_QUEUES |
| 116 | #define MAX_TAP_QUEUES 1024 | 116 | #define MAX_TAP_FLOWS 4096 |
| 117 | 117 | ||
| 118 | #define TUN_FLOW_EXPIRE (3 * HZ) | 118 | #define TUN_FLOW_EXPIRE (3 * HZ) |
| 119 | 119 | ||
| @@ -185,6 +185,8 @@ struct tun_struct { | |||
| 185 | unsigned long ageing_time; | 185 | unsigned long ageing_time; |
| 186 | unsigned int numdisabled; | 186 | unsigned int numdisabled; |
| 187 | struct list_head disabled; | 187 | struct list_head disabled; |
| 188 | void *security; | ||
| 189 | u32 flow_count; | ||
| 188 | }; | 190 | }; |
| 189 | 191 | ||
| 190 | static inline u32 tun_hashfn(u32 rxhash) | 192 | static inline u32 tun_hashfn(u32 rxhash) |
| @@ -218,6 +220,7 @@ static struct tun_flow_entry *tun_flow_create(struct tun_struct *tun, | |||
| 218 | e->queue_index = queue_index; | 220 | e->queue_index = queue_index; |
| 219 | e->tun = tun; | 221 | e->tun = tun; |
| 220 | hlist_add_head_rcu(&e->hash_link, head); | 222 | hlist_add_head_rcu(&e->hash_link, head); |
| 223 | ++tun->flow_count; | ||
| 221 | } | 224 | } |
| 222 | return e; | 225 | return e; |
| 223 | } | 226 | } |
| @@ -228,6 +231,7 @@ static void tun_flow_delete(struct tun_struct *tun, struct tun_flow_entry *e) | |||
| 228 | e->rxhash, e->queue_index); | 231 | e->rxhash, e->queue_index); |
| 229 | hlist_del_rcu(&e->hash_link); | 232 | hlist_del_rcu(&e->hash_link); |
| 230 | kfree_rcu(e, rcu); | 233 | kfree_rcu(e, rcu); |
| 234 | --tun->flow_count; | ||
| 231 | } | 235 | } |
| 232 | 236 | ||
| 233 | static void tun_flow_flush(struct tun_struct *tun) | 237 | static void tun_flow_flush(struct tun_struct *tun) |
| @@ -317,7 +321,8 @@ static void tun_flow_update(struct tun_struct *tun, u32 rxhash, | |||
| 317 | e->updated = jiffies; | 321 | e->updated = jiffies; |
| 318 | } else { | 322 | } else { |
| 319 | spin_lock_bh(&tun->lock); | 323 | spin_lock_bh(&tun->lock); |
| 320 | if (!tun_flow_find(head, rxhash)) | 324 | if (!tun_flow_find(head, rxhash) && |
| 325 | tun->flow_count < MAX_TAP_FLOWS) | ||
| 321 | tun_flow_create(tun, head, rxhash, queue_index); | 326 | tun_flow_create(tun, head, rxhash, queue_index); |
| 322 | 327 | ||
| 323 | if (!timer_pending(&tun->flow_gc_timer)) | 328 | if (!timer_pending(&tun->flow_gc_timer)) |
| @@ -404,8 +409,8 @@ static void __tun_detach(struct tun_file *tfile, bool clean) | |||
| 404 | struct tun_struct *tun; | 409 | struct tun_struct *tun; |
| 405 | struct net_device *dev; | 410 | struct net_device *dev; |
| 406 | 411 | ||
| 407 | tun = rcu_dereference_protected(tfile->tun, | 412 | tun = rtnl_dereference(tfile->tun); |
| 408 | lockdep_rtnl_is_held()); | 413 | |
| 409 | if (tun) { | 414 | if (tun) { |
| 410 | u16 index = tfile->queue_index; | 415 | u16 index = tfile->queue_index; |
| 411 | BUG_ON(index >= tun->numqueues); | 416 | BUG_ON(index >= tun->numqueues); |
| @@ -414,8 +419,7 @@ static void __tun_detach(struct tun_file *tfile, bool clean) | |||
| 414 | rcu_assign_pointer(tun->tfiles[index], | 419 | rcu_assign_pointer(tun->tfiles[index], |
| 415 | tun->tfiles[tun->numqueues - 1]); | 420 | tun->tfiles[tun->numqueues - 1]); |
| 416 | rcu_assign_pointer(tfile->tun, NULL); | 421 | rcu_assign_pointer(tfile->tun, NULL); |
| 417 | ntfile = rcu_dereference_protected(tun->tfiles[index], | 422 | ntfile = rtnl_dereference(tun->tfiles[index]); |
| 418 | lockdep_rtnl_is_held()); | ||
| 419 | ntfile->queue_index = index; | 423 | ntfile->queue_index = index; |
| 420 | 424 | ||
| 421 | --tun->numqueues; | 425 | --tun->numqueues; |
| @@ -429,8 +433,10 @@ static void __tun_detach(struct tun_file *tfile, bool clean) | |||
| 429 | /* Drop read queue */ | 433 | /* Drop read queue */ |
| 430 | skb_queue_purge(&tfile->sk.sk_receive_queue); | 434 | skb_queue_purge(&tfile->sk.sk_receive_queue); |
| 431 | tun_set_real_num_queues(tun); | 435 | tun_set_real_num_queues(tun); |
| 432 | } else if (tfile->detached && clean) | 436 | } else if (tfile->detached && clean) { |
| 433 | tun = tun_enable_queue(tfile); | 437 | tun = tun_enable_queue(tfile); |
| 438 | sock_put(&tfile->sk); | ||
| 439 | } | ||
| 434 | 440 | ||
| 435 | if (clean) { | 441 | if (clean) { |
| 436 | if (tun && tun->numqueues == 0 && tun->numdisabled == 0 && | 442 | if (tun && tun->numqueues == 0 && tun->numdisabled == 0 && |
| @@ -458,8 +464,7 @@ static void tun_detach_all(struct net_device *dev) | |||
| 458 | int i, n = tun->numqueues; | 464 | int i, n = tun->numqueues; |
| 459 | 465 | ||
| 460 | for (i = 0; i < n; i++) { | 466 | for (i = 0; i < n; i++) { |
| 461 | tfile = rcu_dereference_protected(tun->tfiles[i], | 467 | tfile = rtnl_dereference(tun->tfiles[i]); |
| 462 | lockdep_rtnl_is_held()); | ||
| 463 | BUG_ON(!tfile); | 468 | BUG_ON(!tfile); |
| 464 | wake_up_all(&tfile->wq.wait); | 469 | wake_up_all(&tfile->wq.wait); |
| 465 | rcu_assign_pointer(tfile->tun, NULL); | 470 | rcu_assign_pointer(tfile->tun, NULL); |
| @@ -469,8 +474,7 @@ static void tun_detach_all(struct net_device *dev) | |||
| 469 | 474 | ||
| 470 | synchronize_net(); | 475 | synchronize_net(); |
| 471 | for (i = 0; i < n; i++) { | 476 | for (i = 0; i < n; i++) { |
| 472 | tfile = rcu_dereference_protected(tun->tfiles[i], | 477 | tfile = rtnl_dereference(tun->tfiles[i]); |
| 473 | lockdep_rtnl_is_held()); | ||
| 474 | /* Drop read queue */ | 478 | /* Drop read queue */ |
| 475 | skb_queue_purge(&tfile->sk.sk_receive_queue); | 479 | skb_queue_purge(&tfile->sk.sk_receive_queue); |
| 476 | sock_put(&tfile->sk); | 480 | sock_put(&tfile->sk); |
| @@ -481,6 +485,9 @@ static void tun_detach_all(struct net_device *dev) | |||
| 481 | sock_put(&tfile->sk); | 485 | sock_put(&tfile->sk); |
| 482 | } | 486 | } |
| 483 | BUG_ON(tun->numdisabled != 0); | 487 | BUG_ON(tun->numdisabled != 0); |
| 488 | |||
| 489 | if (tun->flags & TUN_PERSIST) | ||
| 490 | module_put(THIS_MODULE); | ||
| 484 | } | 491 | } |
| 485 | 492 | ||
| 486 | static int tun_attach(struct tun_struct *tun, struct file *file) | 493 | static int tun_attach(struct tun_struct *tun, struct file *file) |
| @@ -488,8 +495,12 @@ static int tun_attach(struct tun_struct *tun, struct file *file) | |||
| 488 | struct tun_file *tfile = file->private_data; | 495 | struct tun_file *tfile = file->private_data; |
| 489 | int err; | 496 | int err; |
| 490 | 497 | ||
| 498 | err = security_tun_dev_attach(tfile->socket.sk, tun->security); | ||
| 499 | if (err < 0) | ||
| 500 | goto out; | ||
| 501 | |||
| 491 | err = -EINVAL; | 502 | err = -EINVAL; |
| 492 | if (rcu_dereference_protected(tfile->tun, lockdep_rtnl_is_held())) | 503 | if (rtnl_dereference(tfile->tun)) |
| 493 | goto out; | 504 | goto out; |
| 494 | 505 | ||
| 495 | err = -EBUSY; | 506 | err = -EBUSY; |
| @@ -1371,6 +1382,7 @@ static void tun_free_netdev(struct net_device *dev) | |||
| 1371 | 1382 | ||
| 1372 | BUG_ON(!(list_empty(&tun->disabled))); | 1383 | BUG_ON(!(list_empty(&tun->disabled))); |
| 1373 | tun_flow_uninit(tun); | 1384 | tun_flow_uninit(tun); |
| 1385 | security_tun_dev_free_security(tun->security); | ||
| 1374 | free_netdev(dev); | 1386 | free_netdev(dev); |
| 1375 | } | 1387 | } |
| 1376 | 1388 | ||
| @@ -1544,6 +1556,9 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) | |||
| 1544 | struct net_device *dev; | 1556 | struct net_device *dev; |
| 1545 | int err; | 1557 | int err; |
| 1546 | 1558 | ||
| 1559 | if (tfile->detached) | ||
| 1560 | return -EINVAL; | ||
| 1561 | |||
| 1547 | dev = __dev_get_by_name(net, ifr->ifr_name); | 1562 | dev = __dev_get_by_name(net, ifr->ifr_name); |
| 1548 | if (dev) { | 1563 | if (dev) { |
| 1549 | if (ifr->ifr_flags & IFF_TUN_EXCL) | 1564 | if (ifr->ifr_flags & IFF_TUN_EXCL) |
| @@ -1557,7 +1572,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) | |||
| 1557 | 1572 | ||
| 1558 | if (tun_not_capable(tun)) | 1573 | if (tun_not_capable(tun)) |
| 1559 | return -EPERM; | 1574 | return -EPERM; |
| 1560 | err = security_tun_dev_attach(tfile->socket.sk); | 1575 | err = security_tun_dev_open(tun->security); |
| 1561 | if (err < 0) | 1576 | if (err < 0) |
| 1562 | return err; | 1577 | return err; |
| 1563 | 1578 | ||
| @@ -1572,6 +1587,8 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) | |||
| 1572 | else { | 1587 | else { |
| 1573 | char *name; | 1588 | char *name; |
| 1574 | unsigned long flags = 0; | 1589 | unsigned long flags = 0; |
| 1590 | int queues = ifr->ifr_flags & IFF_MULTI_QUEUE ? | ||
| 1591 | MAX_TAP_QUEUES : 1; | ||
| 1575 | 1592 | ||
| 1576 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) | 1593 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
| 1577 | return -EPERM; | 1594 | return -EPERM; |
| @@ -1595,8 +1612,8 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) | |||
| 1595 | name = ifr->ifr_name; | 1612 | name = ifr->ifr_name; |
| 1596 | 1613 | ||
| 1597 | dev = alloc_netdev_mqs(sizeof(struct tun_struct), name, | 1614 | dev = alloc_netdev_mqs(sizeof(struct tun_struct), name, |
| 1598 | tun_setup, | 1615 | tun_setup, queues, queues); |
| 1599 | MAX_TAP_QUEUES, MAX_TAP_QUEUES); | 1616 | |
| 1600 | if (!dev) | 1617 | if (!dev) |
| 1601 | return -ENOMEM; | 1618 | return -ENOMEM; |
| 1602 | 1619 | ||
| @@ -1614,7 +1631,9 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) | |||
| 1614 | 1631 | ||
| 1615 | spin_lock_init(&tun->lock); | 1632 | spin_lock_init(&tun->lock); |
| 1616 | 1633 | ||
| 1617 | security_tun_dev_post_create(&tfile->sk); | 1634 | err = security_tun_dev_alloc_security(&tun->security); |
| 1635 | if (err < 0) | ||
| 1636 | goto err_free_dev; | ||
| 1618 | 1637 | ||
| 1619 | tun_net_init(dev); | 1638 | tun_net_init(dev); |
| 1620 | 1639 | ||
| @@ -1738,8 +1757,7 @@ static void tun_detach_filter(struct tun_struct *tun, int n) | |||
| 1738 | struct tun_file *tfile; | 1757 | struct tun_file *tfile; |
| 1739 | 1758 | ||
| 1740 | for (i = 0; i < n; i++) { | 1759 | for (i = 0; i < n; i++) { |
| 1741 | tfile = rcu_dereference_protected(tun->tfiles[i], | 1760 | tfile = rtnl_dereference(tun->tfiles[i]); |
| 1742 | lockdep_rtnl_is_held()); | ||
| 1743 | sk_detach_filter(tfile->socket.sk); | 1761 | sk_detach_filter(tfile->socket.sk); |
| 1744 | } | 1762 | } |
| 1745 | 1763 | ||
| @@ -1752,8 +1770,7 @@ static int tun_attach_filter(struct tun_struct *tun) | |||
| 1752 | struct tun_file *tfile; | 1770 | struct tun_file *tfile; |
| 1753 | 1771 | ||
| 1754 | for (i = 0; i < tun->numqueues; i++) { | 1772 | for (i = 0; i < tun->numqueues; i++) { |
| 1755 | tfile = rcu_dereference_protected(tun->tfiles[i], | 1773 | tfile = rtnl_dereference(tun->tfiles[i]); |
| 1756 | lockdep_rtnl_is_held()); | ||
| 1757 | ret = sk_attach_filter(&tun->fprog, tfile->socket.sk); | 1774 | ret = sk_attach_filter(&tun->fprog, tfile->socket.sk); |
| 1758 | if (ret) { | 1775 | if (ret) { |
| 1759 | tun_detach_filter(tun, i); | 1776 | tun_detach_filter(tun, i); |
| @@ -1771,8 +1788,7 @@ static void tun_set_sndbuf(struct tun_struct *tun) | |||
| 1771 | int i; | 1788 | int i; |
| 1772 | 1789 | ||
| 1773 | for (i = 0; i < tun->numqueues; i++) { | 1790 | for (i = 0; i < tun->numqueues; i++) { |
| 1774 | tfile = rcu_dereference_protected(tun->tfiles[i], | 1791 | tfile = rtnl_dereference(tun->tfiles[i]); |
| 1775 | lockdep_rtnl_is_held()); | ||
| 1776 | tfile->socket.sk->sk_sndbuf = tun->sndbuf; | 1792 | tfile->socket.sk->sk_sndbuf = tun->sndbuf; |
| 1777 | } | 1793 | } |
| 1778 | } | 1794 | } |
| @@ -1787,15 +1803,16 @@ static int tun_set_queue(struct file *file, struct ifreq *ifr) | |||
| 1787 | 1803 | ||
| 1788 | if (ifr->ifr_flags & IFF_ATTACH_QUEUE) { | 1804 | if (ifr->ifr_flags & IFF_ATTACH_QUEUE) { |
| 1789 | tun = tfile->detached; | 1805 | tun = tfile->detached; |
| 1790 | if (!tun) | 1806 | if (!tun) { |
| 1791 | ret = -EINVAL; | 1807 | ret = -EINVAL; |
| 1792 | else if (tun_not_capable(tun)) | 1808 | goto unlock; |
| 1793 | ret = -EPERM; | 1809 | } |
| 1794 | else | 1810 | ret = security_tun_dev_attach_queue(tun->security); |
| 1795 | ret = tun_attach(tun, file); | 1811 | if (ret < 0) |
| 1812 | goto unlock; | ||
| 1813 | ret = tun_attach(tun, file); | ||
| 1796 | } else if (ifr->ifr_flags & IFF_DETACH_QUEUE) { | 1814 | } else if (ifr->ifr_flags & IFF_DETACH_QUEUE) { |
| 1797 | tun = rcu_dereference_protected(tfile->tun, | 1815 | tun = rtnl_dereference(tfile->tun); |
| 1798 | lockdep_rtnl_is_held()); | ||
| 1799 | if (!tun || !(tun->flags & TUN_TAP_MQ)) | 1816 | if (!tun || !(tun->flags & TUN_TAP_MQ)) |
| 1800 | ret = -EINVAL; | 1817 | ret = -EINVAL; |
| 1801 | else | 1818 | else |
| @@ -1803,6 +1820,7 @@ static int tun_set_queue(struct file *file, struct ifreq *ifr) | |||
| 1803 | } else | 1820 | } else |
| 1804 | ret = -EINVAL; | 1821 | ret = -EINVAL; |
| 1805 | 1822 | ||
| 1823 | unlock: | ||
| 1806 | rtnl_unlock(); | 1824 | rtnl_unlock(); |
| 1807 | return ret; | 1825 | return ret; |
| 1808 | } | 1826 | } |
| @@ -1880,10 +1898,11 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, | |||
| 1880 | /* Disable/Enable persist mode. Keep an extra reference to the | 1898 | /* Disable/Enable persist mode. Keep an extra reference to the |
| 1881 | * module to prevent the module being unprobed. | 1899 | * module to prevent the module being unprobed. |
| 1882 | */ | 1900 | */ |
| 1883 | if (arg) { | 1901 | if (arg && !(tun->flags & TUN_PERSIST)) { |
| 1884 | tun->flags |= TUN_PERSIST; | 1902 | tun->flags |= TUN_PERSIST; |
| 1885 | __module_get(THIS_MODULE); | 1903 | __module_get(THIS_MODULE); |
| 1886 | } else { | 1904 | } |
| 1905 | if (!arg && (tun->flags & TUN_PERSIST)) { | ||
| 1887 | tun->flags &= ~TUN_PERSIST; | 1906 | tun->flags &= ~TUN_PERSIST; |
| 1888 | module_put(THIS_MODULE); | 1907 | module_put(THIS_MODULE); |
| 1889 | } | 1908 | } |
diff --git a/drivers/net/usb/cdc_mbim.c b/drivers/net/usb/cdc_mbim.c index 42f51c71ec1f..248d2dc765a5 100644 --- a/drivers/net/usb/cdc_mbim.c +++ b/drivers/net/usb/cdc_mbim.c | |||
| @@ -374,6 +374,21 @@ static const struct driver_info cdc_mbim_info = { | |||
| 374 | .tx_fixup = cdc_mbim_tx_fixup, | 374 | .tx_fixup = cdc_mbim_tx_fixup, |
| 375 | }; | 375 | }; |
| 376 | 376 | ||
| 377 | /* MBIM and NCM devices should not need a ZLP after NTBs with | ||
| 378 | * dwNtbOutMaxSize length. This driver_info is for the exceptional | ||
| 379 | * devices requiring it anyway, allowing them to be supported without | ||
| 380 | * forcing the performance penalty on all the sane devices. | ||
| 381 | */ | ||
| 382 | static const struct driver_info cdc_mbim_info_zlp = { | ||
| 383 | .description = "CDC MBIM", | ||
| 384 | .flags = FLAG_NO_SETINT | FLAG_MULTI_PACKET | FLAG_WWAN | FLAG_SEND_ZLP, | ||
| 385 | .bind = cdc_mbim_bind, | ||
| 386 | .unbind = cdc_mbim_unbind, | ||
| 387 | .manage_power = cdc_mbim_manage_power, | ||
| 388 | .rx_fixup = cdc_mbim_rx_fixup, | ||
| 389 | .tx_fixup = cdc_mbim_tx_fixup, | ||
| 390 | }; | ||
| 391 | |||
| 377 | static const struct usb_device_id mbim_devs[] = { | 392 | static const struct usb_device_id mbim_devs[] = { |
| 378 | /* This duplicate NCM entry is intentional. MBIM devices can | 393 | /* This duplicate NCM entry is intentional. MBIM devices can |
| 379 | * be disguised as NCM by default, and this is necessary to | 394 | * be disguised as NCM by default, and this is necessary to |
| @@ -385,6 +400,10 @@ static const struct usb_device_id mbim_devs[] = { | |||
| 385 | { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE), | 400 | { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE), |
| 386 | .driver_info = (unsigned long)&cdc_mbim_info, | 401 | .driver_info = (unsigned long)&cdc_mbim_info, |
| 387 | }, | 402 | }, |
| 403 | /* Sierra Wireless MC7710 need ZLPs */ | ||
| 404 | { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x68a2, USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE), | ||
| 405 | .driver_info = (unsigned long)&cdc_mbim_info_zlp, | ||
| 406 | }, | ||
| 388 | { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE), | 407 | { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE), |
| 389 | .driver_info = (unsigned long)&cdc_mbim_info, | 408 | .driver_info = (unsigned long)&cdc_mbim_info, |
| 390 | }, | 409 | }, |
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 71b6e92b8e9b..9197b2c72ca3 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c | |||
| @@ -435,6 +435,13 @@ advance: | |||
| 435 | len -= temp; | 435 | len -= temp; |
| 436 | } | 436 | } |
| 437 | 437 | ||
| 438 | /* some buggy devices have an IAD but no CDC Union */ | ||
| 439 | if (!ctx->union_desc && intf->intf_assoc && intf->intf_assoc->bInterfaceCount == 2) { | ||
| 440 | ctx->control = intf; | ||
| 441 | ctx->data = usb_ifnum_to_if(dev->udev, intf->cur_altsetting->desc.bInterfaceNumber + 1); | ||
| 442 | dev_dbg(&intf->dev, "CDC Union missing - got slave from IAD\n"); | ||
| 443 | } | ||
| 444 | |||
| 438 | /* check if we got everything */ | 445 | /* check if we got everything */ |
| 439 | if ((ctx->control == NULL) || (ctx->data == NULL) || | 446 | if ((ctx->control == NULL) || (ctx->data == NULL) || |
| 440 | ((!ctx->mbim_desc) && ((ctx->ether_desc == NULL) || (ctx->control != intf)))) | 447 | ((!ctx->mbim_desc) && ((ctx->ether_desc == NULL) || (ctx->control != intf)))) |
| @@ -497,7 +504,8 @@ advance: | |||
| 497 | error2: | 504 | error2: |
| 498 | usb_set_intfdata(ctx->control, NULL); | 505 | usb_set_intfdata(ctx->control, NULL); |
| 499 | usb_set_intfdata(ctx->data, NULL); | 506 | usb_set_intfdata(ctx->data, NULL); |
| 500 | usb_driver_release_interface(driver, ctx->data); | 507 | if (ctx->data != ctx->control) |
| 508 | usb_driver_release_interface(driver, ctx->data); | ||
| 501 | error: | 509 | error: |
| 502 | cdc_ncm_free((struct cdc_ncm_ctx *)dev->data[0]); | 510 | cdc_ncm_free((struct cdc_ncm_ctx *)dev->data[0]); |
| 503 | dev->data[0] = 0; | 511 | dev->data[0] = 0; |
| @@ -1155,6 +1163,20 @@ static const struct driver_info wwan_info = { | |||
| 1155 | .tx_fixup = cdc_ncm_tx_fixup, | 1163 | .tx_fixup = cdc_ncm_tx_fixup, |
| 1156 | }; | 1164 | }; |
| 1157 | 1165 | ||
| 1166 | /* Same as wwan_info, but with FLAG_NOARP */ | ||
| 1167 | static const struct driver_info wwan_noarp_info = { | ||
| 1168 | .description = "Mobile Broadband Network Device (NO ARP)", | ||
| 1169 | .flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET | ||
| 1170 | | FLAG_WWAN | FLAG_NOARP, | ||
| 1171 | .bind = cdc_ncm_bind, | ||
| 1172 | .unbind = cdc_ncm_unbind, | ||
| 1173 | .check_connect = cdc_ncm_check_connect, | ||
| 1174 | .manage_power = usbnet_manage_power, | ||
| 1175 | .status = cdc_ncm_status, | ||
| 1176 | .rx_fixup = cdc_ncm_rx_fixup, | ||
| 1177 | .tx_fixup = cdc_ncm_tx_fixup, | ||
| 1178 | }; | ||
| 1179 | |||
| 1158 | static const struct usb_device_id cdc_devs[] = { | 1180 | static const struct usb_device_id cdc_devs[] = { |
| 1159 | /* Ericsson MBM devices like F5521gw */ | 1181 | /* Ericsson MBM devices like F5521gw */ |
| 1160 | { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | 1182 | { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO |
| @@ -1194,6 +1216,13 @@ static const struct usb_device_id cdc_devs[] = { | |||
| 1194 | .driver_info = (unsigned long)&wwan_info, | 1216 | .driver_info = (unsigned long)&wwan_info, |
| 1195 | }, | 1217 | }, |
| 1196 | 1218 | ||
| 1219 | /* Infineon(now Intel) HSPA Modem platform */ | ||
| 1220 | { USB_DEVICE_AND_INTERFACE_INFO(0x1519, 0x0443, | ||
| 1221 | USB_CLASS_COMM, | ||
| 1222 | USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE), | ||
| 1223 | .driver_info = (unsigned long)&wwan_noarp_info, | ||
| 1224 | }, | ||
| 1225 | |||
| 1197 | /* Generic CDC-NCM devices */ | 1226 | /* Generic CDC-NCM devices */ |
| 1198 | { USB_INTERFACE_INFO(USB_CLASS_COMM, | 1227 | { USB_INTERFACE_INFO(USB_CLASS_COMM, |
| 1199 | USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE), | 1228 | USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE), |
diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c index 3f554c1149f3..d7e99445518e 100644 --- a/drivers/net/usb/dm9601.c +++ b/drivers/net/usb/dm9601.c | |||
| @@ -45,6 +45,12 @@ | |||
| 45 | #define DM_MCAST_ADDR 0x16 /* 8 bytes */ | 45 | #define DM_MCAST_ADDR 0x16 /* 8 bytes */ |
| 46 | #define DM_GPR_CTRL 0x1e | 46 | #define DM_GPR_CTRL 0x1e |
| 47 | #define DM_GPR_DATA 0x1f | 47 | #define DM_GPR_DATA 0x1f |
| 48 | #define DM_CHIP_ID 0x2c | ||
| 49 | #define DM_MODE_CTRL 0x91 /* only on dm9620 */ | ||
| 50 | |||
| 51 | /* chip id values */ | ||
| 52 | #define ID_DM9601 0 | ||
| 53 | #define ID_DM9620 1 | ||
| 48 | 54 | ||
| 49 | #define DM_MAX_MCAST 64 | 55 | #define DM_MAX_MCAST 64 |
| 50 | #define DM_MCAST_SIZE 8 | 56 | #define DM_MCAST_SIZE 8 |
| @@ -53,7 +59,6 @@ | |||
| 53 | #define DM_RX_OVERHEAD 7 /* 3 byte header + 4 byte crc tail */ | 59 | #define DM_RX_OVERHEAD 7 /* 3 byte header + 4 byte crc tail */ |
| 54 | #define DM_TIMEOUT 1000 | 60 | #define DM_TIMEOUT 1000 |
| 55 | 61 | ||
| 56 | |||
| 57 | static int dm_read(struct usbnet *dev, u8 reg, u16 length, void *data) | 62 | static int dm_read(struct usbnet *dev, u8 reg, u16 length, void *data) |
| 58 | { | 63 | { |
| 59 | int err; | 64 | int err; |
| @@ -84,32 +89,23 @@ static int dm_write(struct usbnet *dev, u8 reg, u16 length, void *data) | |||
| 84 | 89 | ||
| 85 | static int dm_write_reg(struct usbnet *dev, u8 reg, u8 value) | 90 | static int dm_write_reg(struct usbnet *dev, u8 reg, u8 value) |
| 86 | { | 91 | { |
| 87 | return usbnet_write_cmd(dev, DM_WRITE_REGS, | 92 | return usbnet_write_cmd(dev, DM_WRITE_REG, |
| 88 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | 93 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, |
| 89 | value, reg, NULL, 0); | 94 | value, reg, NULL, 0); |
| 90 | } | 95 | } |
| 91 | 96 | ||
| 92 | static void dm_write_async_helper(struct usbnet *dev, u8 reg, u8 value, | 97 | static void dm_write_async(struct usbnet *dev, u8 reg, u16 length, void *data) |
| 93 | u16 length, void *data) | ||
| 94 | { | 98 | { |
| 95 | usbnet_write_cmd_async(dev, DM_WRITE_REGS, | 99 | usbnet_write_cmd_async(dev, DM_WRITE_REGS, |
| 96 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | 100 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, |
| 97 | value, reg, data, length); | 101 | 0, reg, data, length); |
| 98 | } | ||
| 99 | |||
| 100 | static void dm_write_async(struct usbnet *dev, u8 reg, u16 length, void *data) | ||
| 101 | { | ||
| 102 | netdev_dbg(dev->net, "dm_write_async() reg=0x%02x length=%d\n", reg, length); | ||
| 103 | |||
| 104 | dm_write_async_helper(dev, reg, 0, length, data); | ||
| 105 | } | 102 | } |
| 106 | 103 | ||
| 107 | static void dm_write_reg_async(struct usbnet *dev, u8 reg, u8 value) | 104 | static void dm_write_reg_async(struct usbnet *dev, u8 reg, u8 value) |
| 108 | { | 105 | { |
| 109 | netdev_dbg(dev->net, "dm_write_reg_async() reg=0x%02x value=0x%02x\n", | 106 | usbnet_write_cmd_async(dev, DM_WRITE_REG, |
| 110 | reg, value); | 107 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, |
| 111 | 108 | value, reg, NULL, 0); | |
| 112 | dm_write_async_helper(dev, reg, value, 0, NULL); | ||
| 113 | } | 109 | } |
| 114 | 110 | ||
| 115 | static int dm_read_shared_word(struct usbnet *dev, int phy, u8 reg, __le16 *value) | 111 | static int dm_read_shared_word(struct usbnet *dev, int phy, u8 reg, __le16 *value) |
| @@ -358,7 +354,7 @@ static const struct net_device_ops dm9601_netdev_ops = { | |||
| 358 | static int dm9601_bind(struct usbnet *dev, struct usb_interface *intf) | 354 | static int dm9601_bind(struct usbnet *dev, struct usb_interface *intf) |
| 359 | { | 355 | { |
| 360 | int ret; | 356 | int ret; |
| 361 | u8 mac[ETH_ALEN]; | 357 | u8 mac[ETH_ALEN], id; |
| 362 | 358 | ||
| 363 | ret = usbnet_get_endpoints(dev, intf); | 359 | ret = usbnet_get_endpoints(dev, intf); |
| 364 | if (ret) | 360 | if (ret) |
| @@ -399,6 +395,24 @@ static int dm9601_bind(struct usbnet *dev, struct usb_interface *intf) | |||
| 399 | __dm9601_set_mac_address(dev); | 395 | __dm9601_set_mac_address(dev); |
| 400 | } | 396 | } |
| 401 | 397 | ||
| 398 | if (dm_read_reg(dev, DM_CHIP_ID, &id) < 0) { | ||
| 399 | netdev_err(dev->net, "Error reading chip ID\n"); | ||
| 400 | ret = -ENODEV; | ||
| 401 | goto out; | ||
| 402 | } | ||
| 403 | |||
| 404 | /* put dm9620 devices in dm9601 mode */ | ||
| 405 | if (id == ID_DM9620) { | ||
| 406 | u8 mode; | ||
| 407 | |||
| 408 | if (dm_read_reg(dev, DM_MODE_CTRL, &mode) < 0) { | ||
| 409 | netdev_err(dev->net, "Error reading MODE_CTRL\n"); | ||
| 410 | ret = -ENODEV; | ||
| 411 | goto out; | ||
| 412 | } | ||
| 413 | dm_write_reg(dev, DM_MODE_CTRL, mode & 0x7f); | ||
| 414 | } | ||
| 415 | |||
| 402 | /* power up phy */ | 416 | /* power up phy */ |
| 403 | dm_write_reg(dev, DM_GPR_CTRL, 1); | 417 | dm_write_reg(dev, DM_GPR_CTRL, 1); |
| 404 | dm_write_reg(dev, DM_GPR_DATA, 0); | 418 | dm_write_reg(dev, DM_GPR_DATA, 0); |
| @@ -581,6 +595,10 @@ static const struct usb_device_id products[] = { | |||
| 581 | USB_DEVICE(0x0a46, 0x9000), /* DM9000E */ | 595 | USB_DEVICE(0x0a46, 0x9000), /* DM9000E */ |
| 582 | .driver_info = (unsigned long)&dm9601_info, | 596 | .driver_info = (unsigned long)&dm9601_info, |
| 583 | }, | 597 | }, |
| 598 | { | ||
| 599 | USB_DEVICE(0x0a46, 0x9620), /* DM9620 USB to Fast Ethernet Adapter */ | ||
| 600 | .driver_info = (unsigned long)&dm9601_info, | ||
| 601 | }, | ||
| 584 | {}, // END | 602 | {}, // END |
| 585 | }; | 603 | }; |
| 586 | 604 | ||
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 6a1ca500e612..575a5839ee34 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c | |||
| @@ -433,6 +433,7 @@ static const struct usb_device_id products[] = { | |||
| 433 | {QMI_FIXED_INTF(0x19d2, 0x0199, 1)}, /* ZTE MF820S */ | 433 | {QMI_FIXED_INTF(0x19d2, 0x0199, 1)}, /* ZTE MF820S */ |
| 434 | {QMI_FIXED_INTF(0x19d2, 0x0200, 1)}, | 434 | {QMI_FIXED_INTF(0x19d2, 0x0200, 1)}, |
| 435 | {QMI_FIXED_INTF(0x19d2, 0x0257, 3)}, /* ZTE MF821 */ | 435 | {QMI_FIXED_INTF(0x19d2, 0x0257, 3)}, /* ZTE MF821 */ |
| 436 | {QMI_FIXED_INTF(0x19d2, 0x0265, 4)}, /* ONDA MT8205 4G LTE */ | ||
| 436 | {QMI_FIXED_INTF(0x19d2, 0x0284, 4)}, /* ZTE MF880 */ | 437 | {QMI_FIXED_INTF(0x19d2, 0x0284, 4)}, /* ZTE MF880 */ |
| 437 | {QMI_FIXED_INTF(0x19d2, 0x0326, 4)}, /* ZTE MF821D */ | 438 | {QMI_FIXED_INTF(0x19d2, 0x0326, 4)}, /* ZTE MF821D */ |
| 438 | {QMI_FIXED_INTF(0x19d2, 0x1008, 4)}, /* ZTE (Vodafone) K3570-Z */ | 439 | {QMI_FIXED_INTF(0x19d2, 0x1008, 4)}, /* ZTE (Vodafone) K3570-Z */ |
| @@ -459,6 +460,7 @@ static const struct usb_device_id products[] = { | |||
| 459 | {QMI_FIXED_INTF(0x1199, 0x68a2, 19)}, /* Sierra Wireless MC7710 in QMI mode */ | 460 | {QMI_FIXED_INTF(0x1199, 0x68a2, 19)}, /* Sierra Wireless MC7710 in QMI mode */ |
| 460 | {QMI_FIXED_INTF(0x1199, 0x901c, 8)}, /* Sierra Wireless EM7700 */ | 461 | {QMI_FIXED_INTF(0x1199, 0x901c, 8)}, /* Sierra Wireless EM7700 */ |
| 461 | {QMI_FIXED_INTF(0x1bbb, 0x011e, 4)}, /* Telekom Speedstick LTE II (Alcatel One Touch L100V LTE) */ | 462 | {QMI_FIXED_INTF(0x1bbb, 0x011e, 4)}, /* Telekom Speedstick LTE II (Alcatel One Touch L100V LTE) */ |
| 463 | {QMI_FIXED_INTF(0x2357, 0x0201, 4)}, /* TP-LINK HSUPA Modem MA180 */ | ||
| 462 | 464 | ||
| 463 | /* 4. Gobi 1000 devices */ | 465 | /* 4. Gobi 1000 devices */ |
| 464 | {QMI_GOBI1K_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */ | 466 | {QMI_GOBI1K_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */ |
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 3d4bf01641b4..f34b2ebee815 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c | |||
| @@ -1448,6 +1448,10 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) | |||
| 1448 | if ((dev->driver_info->flags & FLAG_WWAN) != 0) | 1448 | if ((dev->driver_info->flags & FLAG_WWAN) != 0) |
| 1449 | strcpy(net->name, "wwan%d"); | 1449 | strcpy(net->name, "wwan%d"); |
| 1450 | 1450 | ||
| 1451 | /* devices that cannot do ARP */ | ||
| 1452 | if ((dev->driver_info->flags & FLAG_NOARP) != 0) | ||
| 1453 | net->flags |= IFF_NOARP; | ||
| 1454 | |||
| 1451 | /* maybe the remote can't receive an Ethernet MTU */ | 1455 | /* maybe the remote can't receive an Ethernet MTU */ |
| 1452 | if (net->mtu > (dev->hard_mtu - net->hard_header_len)) | 1456 | if (net->mtu > (dev->hard_mtu - net->hard_header_len)) |
| 1453 | net->mtu = dev->hard_mtu - net->hard_header_len; | 1457 | net->mtu = dev->hard_mtu - net->hard_header_len; |
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index a6fcf15adc4f..35c00c5ea02a 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | #include <linux/scatterlist.h> | 26 | #include <linux/scatterlist.h> |
| 27 | #include <linux/if_vlan.h> | 27 | #include <linux/if_vlan.h> |
| 28 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
| 29 | #include <linux/cpu.h> | ||
| 29 | 30 | ||
| 30 | static int napi_weight = 128; | 31 | static int napi_weight = 128; |
| 31 | module_param(napi_weight, int, 0444); | 32 | module_param(napi_weight, int, 0444); |
| @@ -123,6 +124,12 @@ struct virtnet_info { | |||
| 123 | 124 | ||
| 124 | /* Does the affinity hint is set for virtqueues? */ | 125 | /* Does the affinity hint is set for virtqueues? */ |
| 125 | bool affinity_hint_set; | 126 | bool affinity_hint_set; |
| 127 | |||
| 128 | /* Per-cpu variable to show the mapping from CPU to virtqueue */ | ||
| 129 | int __percpu *vq_index; | ||
| 130 | |||
| 131 | /* CPU hot plug notifier */ | ||
| 132 | struct notifier_block nb; | ||
| 126 | }; | 133 | }; |
| 127 | 134 | ||
| 128 | struct skb_vnet_hdr { | 135 | struct skb_vnet_hdr { |
| @@ -1013,32 +1020,75 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev, u16 vid) | |||
| 1013 | return 0; | 1020 | return 0; |
| 1014 | } | 1021 | } |
| 1015 | 1022 | ||
| 1016 | static void virtnet_set_affinity(struct virtnet_info *vi, bool set) | 1023 | static void virtnet_clean_affinity(struct virtnet_info *vi, long hcpu) |
| 1017 | { | 1024 | { |
| 1018 | int i; | 1025 | int i; |
| 1026 | int cpu; | ||
| 1027 | |||
| 1028 | if (vi->affinity_hint_set) { | ||
| 1029 | for (i = 0; i < vi->max_queue_pairs; i++) { | ||
| 1030 | virtqueue_set_affinity(vi->rq[i].vq, -1); | ||
| 1031 | virtqueue_set_affinity(vi->sq[i].vq, -1); | ||
| 1032 | } | ||
| 1033 | |||
| 1034 | vi->affinity_hint_set = false; | ||
| 1035 | } | ||
| 1036 | |||
| 1037 | i = 0; | ||
| 1038 | for_each_online_cpu(cpu) { | ||
| 1039 | if (cpu == hcpu) { | ||
| 1040 | *per_cpu_ptr(vi->vq_index, cpu) = -1; | ||
| 1041 | } else { | ||
| 1042 | *per_cpu_ptr(vi->vq_index, cpu) = | ||
| 1043 | ++i % vi->curr_queue_pairs; | ||
| 1044 | } | ||
| 1045 | } | ||
| 1046 | } | ||
| 1047 | |||
| 1048 | static void virtnet_set_affinity(struct virtnet_info *vi) | ||
| 1049 | { | ||
| 1050 | int i; | ||
| 1051 | int cpu; | ||
| 1019 | 1052 | ||
| 1020 | /* In multiqueue mode, when the number of cpu is equal to the number of | 1053 | /* In multiqueue mode, when the number of cpu is equal to the number of |
| 1021 | * queue pairs, we let the queue pairs to be private to one cpu by | 1054 | * queue pairs, we let the queue pairs to be private to one cpu by |
| 1022 | * setting the affinity hint to eliminate the contention. | 1055 | * setting the affinity hint to eliminate the contention. |
| 1023 | */ | 1056 | */ |
| 1024 | if ((vi->curr_queue_pairs == 1 || | 1057 | if (vi->curr_queue_pairs == 1 || |
| 1025 | vi->max_queue_pairs != num_online_cpus()) && set) { | 1058 | vi->max_queue_pairs != num_online_cpus()) { |
| 1026 | if (vi->affinity_hint_set) | 1059 | virtnet_clean_affinity(vi, -1); |
| 1027 | set = false; | 1060 | return; |
| 1028 | else | ||
| 1029 | return; | ||
| 1030 | } | 1061 | } |
| 1031 | 1062 | ||
| 1032 | for (i = 0; i < vi->max_queue_pairs; i++) { | 1063 | i = 0; |
| 1033 | int cpu = set ? i : -1; | 1064 | for_each_online_cpu(cpu) { |
| 1034 | virtqueue_set_affinity(vi->rq[i].vq, cpu); | 1065 | virtqueue_set_affinity(vi->rq[i].vq, cpu); |
| 1035 | virtqueue_set_affinity(vi->sq[i].vq, cpu); | 1066 | virtqueue_set_affinity(vi->sq[i].vq, cpu); |
| 1067 | *per_cpu_ptr(vi->vq_index, cpu) = i; | ||
| 1068 | i++; | ||
| 1036 | } | 1069 | } |
| 1037 | 1070 | ||
| 1038 | if (set) | 1071 | vi->affinity_hint_set = true; |
| 1039 | vi->affinity_hint_set = true; | 1072 | } |
| 1040 | else | 1073 | |
| 1041 | vi->affinity_hint_set = false; | 1074 | static int virtnet_cpu_callback(struct notifier_block *nfb, |
| 1075 | unsigned long action, void *hcpu) | ||
| 1076 | { | ||
| 1077 | struct virtnet_info *vi = container_of(nfb, struct virtnet_info, nb); | ||
| 1078 | |||
| 1079 | switch(action & ~CPU_TASKS_FROZEN) { | ||
| 1080 | case CPU_ONLINE: | ||
| 1081 | case CPU_DOWN_FAILED: | ||
| 1082 | case CPU_DEAD: | ||
| 1083 | virtnet_set_affinity(vi); | ||
| 1084 | break; | ||
| 1085 | case CPU_DOWN_PREPARE: | ||
| 1086 | virtnet_clean_affinity(vi, (long)hcpu); | ||
| 1087 | break; | ||
| 1088 | default: | ||
| 1089 | break; | ||
| 1090 | } | ||
| 1091 | return NOTIFY_OK; | ||
| 1042 | } | 1092 | } |
| 1043 | 1093 | ||
| 1044 | static void virtnet_get_ringparam(struct net_device *dev, | 1094 | static void virtnet_get_ringparam(struct net_device *dev, |
| @@ -1082,13 +1132,15 @@ static int virtnet_set_channels(struct net_device *dev, | |||
| 1082 | if (queue_pairs > vi->max_queue_pairs) | 1132 | if (queue_pairs > vi->max_queue_pairs) |
| 1083 | return -EINVAL; | 1133 | return -EINVAL; |
| 1084 | 1134 | ||
| 1135 | get_online_cpus(); | ||
| 1085 | err = virtnet_set_queues(vi, queue_pairs); | 1136 | err = virtnet_set_queues(vi, queue_pairs); |
| 1086 | if (!err) { | 1137 | if (!err) { |
| 1087 | netif_set_real_num_tx_queues(dev, queue_pairs); | 1138 | netif_set_real_num_tx_queues(dev, queue_pairs); |
| 1088 | netif_set_real_num_rx_queues(dev, queue_pairs); | 1139 | netif_set_real_num_rx_queues(dev, queue_pairs); |
| 1089 | 1140 | ||
| 1090 | virtnet_set_affinity(vi, true); | 1141 | virtnet_set_affinity(vi); |
| 1091 | } | 1142 | } |
| 1143 | put_online_cpus(); | ||
| 1092 | 1144 | ||
| 1093 | return err; | 1145 | return err; |
| 1094 | } | 1146 | } |
| @@ -1127,12 +1179,19 @@ static int virtnet_change_mtu(struct net_device *dev, int new_mtu) | |||
| 1127 | 1179 | ||
| 1128 | /* To avoid contending a lock hold by a vcpu who would exit to host, select the | 1180 | /* To avoid contending a lock hold by a vcpu who would exit to host, select the |
| 1129 | * txq based on the processor id. | 1181 | * txq based on the processor id. |
| 1130 | * TODO: handle cpu hotplug. | ||
| 1131 | */ | 1182 | */ |
| 1132 | static u16 virtnet_select_queue(struct net_device *dev, struct sk_buff *skb) | 1183 | static u16 virtnet_select_queue(struct net_device *dev, struct sk_buff *skb) |
| 1133 | { | 1184 | { |
| 1134 | int txq = skb_rx_queue_recorded(skb) ? skb_get_rx_queue(skb) : | 1185 | int txq; |
| 1135 | smp_processor_id(); | 1186 | struct virtnet_info *vi = netdev_priv(dev); |
| 1187 | |||
| 1188 | if (skb_rx_queue_recorded(skb)) { | ||
| 1189 | txq = skb_get_rx_queue(skb); | ||
| 1190 | } else { | ||
| 1191 | txq = *__this_cpu_ptr(vi->vq_index); | ||
| 1192 | if (txq == -1) | ||
| 1193 | txq = 0; | ||
| 1194 | } | ||
| 1136 | 1195 | ||
| 1137 | while (unlikely(txq >= dev->real_num_tx_queues)) | 1196 | while (unlikely(txq >= dev->real_num_tx_queues)) |
| 1138 | txq -= dev->real_num_tx_queues; | 1197 | txq -= dev->real_num_tx_queues; |
| @@ -1248,7 +1307,7 @@ static void virtnet_del_vqs(struct virtnet_info *vi) | |||
| 1248 | { | 1307 | { |
| 1249 | struct virtio_device *vdev = vi->vdev; | 1308 | struct virtio_device *vdev = vi->vdev; |
| 1250 | 1309 | ||
| 1251 | virtnet_set_affinity(vi, false); | 1310 | virtnet_clean_affinity(vi, -1); |
| 1252 | 1311 | ||
| 1253 | vdev->config->del_vqs(vdev); | 1312 | vdev->config->del_vqs(vdev); |
| 1254 | 1313 | ||
| @@ -1371,7 +1430,10 @@ static int init_vqs(struct virtnet_info *vi) | |||
| 1371 | if (ret) | 1430 | if (ret) |
| 1372 | goto err_free; | 1431 | goto err_free; |
| 1373 | 1432 | ||
| 1374 | virtnet_set_affinity(vi, true); | 1433 | get_online_cpus(); |
| 1434 | virtnet_set_affinity(vi); | ||
| 1435 | put_online_cpus(); | ||
| 1436 | |||
| 1375 | return 0; | 1437 | return 0; |
| 1376 | 1438 | ||
| 1377 | err_free: | 1439 | err_free: |
| @@ -1453,6 +1515,10 @@ static int virtnet_probe(struct virtio_device *vdev) | |||
| 1453 | if (vi->stats == NULL) | 1515 | if (vi->stats == NULL) |
| 1454 | goto free; | 1516 | goto free; |
| 1455 | 1517 | ||
| 1518 | vi->vq_index = alloc_percpu(int); | ||
| 1519 | if (vi->vq_index == NULL) | ||
| 1520 | goto free_stats; | ||
| 1521 | |||
| 1456 | mutex_init(&vi->config_lock); | 1522 | mutex_init(&vi->config_lock); |
| 1457 | vi->config_enable = true; | 1523 | vi->config_enable = true; |
| 1458 | INIT_WORK(&vi->config_work, virtnet_config_changed_work); | 1524 | INIT_WORK(&vi->config_work, virtnet_config_changed_work); |
| @@ -1476,7 +1542,7 @@ static int virtnet_probe(struct virtio_device *vdev) | |||
| 1476 | /* Allocate/initialize the rx/tx queues, and invoke find_vqs */ | 1542 | /* Allocate/initialize the rx/tx queues, and invoke find_vqs */ |
| 1477 | err = init_vqs(vi); | 1543 | err = init_vqs(vi); |
| 1478 | if (err) | 1544 | if (err) |
| 1479 | goto free_stats; | 1545 | goto free_index; |
| 1480 | 1546 | ||
| 1481 | netif_set_real_num_tx_queues(dev, 1); | 1547 | netif_set_real_num_tx_queues(dev, 1); |
| 1482 | netif_set_real_num_rx_queues(dev, 1); | 1548 | netif_set_real_num_rx_queues(dev, 1); |
| @@ -1499,6 +1565,13 @@ static int virtnet_probe(struct virtio_device *vdev) | |||
| 1499 | } | 1565 | } |
| 1500 | } | 1566 | } |
| 1501 | 1567 | ||
| 1568 | vi->nb.notifier_call = &virtnet_cpu_callback; | ||
| 1569 | err = register_hotcpu_notifier(&vi->nb); | ||
| 1570 | if (err) { | ||
| 1571 | pr_debug("virtio_net: registering cpu notifier failed\n"); | ||
| 1572 | goto free_recv_bufs; | ||
| 1573 | } | ||
| 1574 | |||
| 1502 | /* Assume link up if device can't report link status, | 1575 | /* Assume link up if device can't report link status, |
| 1503 | otherwise get link status from config. */ | 1576 | otherwise get link status from config. */ |
| 1504 | if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) { | 1577 | if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) { |
| @@ -1520,6 +1593,8 @@ free_recv_bufs: | |||
| 1520 | free_vqs: | 1593 | free_vqs: |
| 1521 | cancel_delayed_work_sync(&vi->refill); | 1594 | cancel_delayed_work_sync(&vi->refill); |
| 1522 | virtnet_del_vqs(vi); | 1595 | virtnet_del_vqs(vi); |
| 1596 | free_index: | ||
| 1597 | free_percpu(vi->vq_index); | ||
| 1523 | free_stats: | 1598 | free_stats: |
| 1524 | free_percpu(vi->stats); | 1599 | free_percpu(vi->stats); |
| 1525 | free: | 1600 | free: |
| @@ -1543,6 +1618,8 @@ static void virtnet_remove(struct virtio_device *vdev) | |||
| 1543 | { | 1618 | { |
| 1544 | struct virtnet_info *vi = vdev->priv; | 1619 | struct virtnet_info *vi = vdev->priv; |
| 1545 | 1620 | ||
| 1621 | unregister_hotcpu_notifier(&vi->nb); | ||
| 1622 | |||
| 1546 | /* Prevent config work handler from accessing the device. */ | 1623 | /* Prevent config work handler from accessing the device. */ |
| 1547 | mutex_lock(&vi->config_lock); | 1624 | mutex_lock(&vi->config_lock); |
| 1548 | vi->config_enable = false; | 1625 | vi->config_enable = false; |
| @@ -1554,6 +1631,7 @@ static void virtnet_remove(struct virtio_device *vdev) | |||
| 1554 | 1631 | ||
| 1555 | flush_work(&vi->config_work); | 1632 | flush_work(&vi->config_work); |
| 1556 | 1633 | ||
| 1634 | free_percpu(vi->vq_index); | ||
| 1557 | free_percpu(vi->stats); | 1635 | free_percpu(vi->stats); |
| 1558 | free_netdev(vi->dev); | 1636 | free_netdev(vi->dev); |
| 1559 | } | 1637 | } |
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/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 8b0d8dcd7625..56317b0fb6b6 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c | |||
| @@ -976,6 +976,8 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, | |||
| 976 | AR_PHY_CL_TAB_1, | 976 | AR_PHY_CL_TAB_1, |
| 977 | AR_PHY_CL_TAB_2 }; | 977 | AR_PHY_CL_TAB_2 }; |
| 978 | 978 | ||
| 979 | ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask); | ||
| 980 | |||
| 979 | if (rtt) { | 981 | if (rtt) { |
| 980 | if (!ar9003_hw_rtt_restore(ah, chan)) | 982 | if (!ar9003_hw_rtt_restore(ah, chan)) |
| 981 | run_rtt_cal = true; | 983 | run_rtt_cal = true; |
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index ce19c09fa8e8..3afc24bde6d6 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c | |||
| @@ -586,32 +586,19 @@ static void ar9003_hw_init_bb(struct ath_hw *ah, | |||
| 586 | ath9k_hw_synth_delay(ah, chan, synthDelay); | 586 | ath9k_hw_synth_delay(ah, chan, synthDelay); |
| 587 | } | 587 | } |
| 588 | 588 | ||
| 589 | static void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx) | 589 | void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx) |
| 590 | { | 590 | { |
| 591 | switch (rx) { | 591 | if (ah->caps.tx_chainmask == 5 || ah->caps.rx_chainmask == 5) |
| 592 | case 0x5: | ||
| 593 | REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, | 592 | REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, |
| 594 | AR_PHY_SWAP_ALT_CHAIN); | 593 | AR_PHY_SWAP_ALT_CHAIN); |
| 595 | case 0x3: | 594 | |
| 596 | case 0x1: | 595 | REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx); |
| 597 | case 0x2: | 596 | REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx); |
| 598 | case 0x7: | ||
| 599 | REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx); | ||
| 600 | REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx); | ||
| 601 | break; | ||
| 602 | default: | ||
| 603 | break; | ||
| 604 | } | ||
| 605 | 597 | ||
| 606 | if ((ah->caps.hw_caps & ATH9K_HW_CAP_APM) && (tx == 0x7)) | 598 | if ((ah->caps.hw_caps & ATH9K_HW_CAP_APM) && (tx == 0x7)) |
| 607 | REG_WRITE(ah, AR_SELFGEN_MASK, 0x3); | 599 | tx = 3; |
| 608 | else | ||
| 609 | REG_WRITE(ah, AR_SELFGEN_MASK, tx); | ||
| 610 | 600 | ||
| 611 | if (tx == 0x5) { | 601 | REG_WRITE(ah, AR_SELFGEN_MASK, tx); |
| 612 | REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, | ||
| 613 | AR_PHY_SWAP_ALT_CHAIN); | ||
| 614 | } | ||
| 615 | } | 602 | } |
| 616 | 603 | ||
| 617 | /* | 604 | /* |
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 86e26a19efda..42794c546a40 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | |||
| @@ -317,7 +317,6 @@ struct ath_rx { | |||
| 317 | u32 *rxlink; | 317 | u32 *rxlink; |
| 318 | u32 num_pkts; | 318 | u32 num_pkts; |
| 319 | unsigned int rxfilter; | 319 | unsigned int rxfilter; |
| 320 | spinlock_t rxbuflock; | ||
| 321 | struct list_head rxbuf; | 320 | struct list_head rxbuf; |
| 322 | struct ath_descdma rxdma; | 321 | struct ath_descdma rxdma; |
| 323 | struct ath_buf *rx_bufptr; | 322 | struct ath_buf *rx_bufptr; |
| @@ -328,7 +327,6 @@ struct ath_rx { | |||
| 328 | 327 | ||
| 329 | int ath_startrecv(struct ath_softc *sc); | 328 | int ath_startrecv(struct ath_softc *sc); |
| 330 | bool ath_stoprecv(struct ath_softc *sc); | 329 | bool ath_stoprecv(struct ath_softc *sc); |
| 331 | void ath_flushrecv(struct ath_softc *sc); | ||
| 332 | u32 ath_calcrxfilter(struct ath_softc *sc); | 330 | u32 ath_calcrxfilter(struct ath_softc *sc); |
| 333 | int ath_rx_init(struct ath_softc *sc, int nbufs); | 331 | int ath_rx_init(struct ath_softc *sc, int nbufs); |
| 334 | void ath_rx_cleanup(struct ath_softc *sc); | 332 | void ath_rx_cleanup(struct ath_softc *sc); |
| @@ -646,7 +644,6 @@ void ath_ant_comb_update(struct ath_softc *sc); | |||
| 646 | enum sc_op_flags { | 644 | enum sc_op_flags { |
| 647 | SC_OP_INVALID, | 645 | SC_OP_INVALID, |
| 648 | SC_OP_BEACONS, | 646 | SC_OP_BEACONS, |
| 649 | SC_OP_RXFLUSH, | ||
| 650 | SC_OP_ANI_RUN, | 647 | SC_OP_ANI_RUN, |
| 651 | SC_OP_PRIM_STA_VIF, | 648 | SC_OP_PRIM_STA_VIF, |
| 652 | SC_OP_HW_RESET, | 649 | SC_OP_HW_RESET, |
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 531fffd801a3..2ca355e94da6 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c | |||
| @@ -147,6 +147,7 @@ static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw, | |||
| 147 | skb->len, DMA_TO_DEVICE); | 147 | skb->len, DMA_TO_DEVICE); |
| 148 | dev_kfree_skb_any(skb); | 148 | dev_kfree_skb_any(skb); |
| 149 | bf->bf_buf_addr = 0; | 149 | bf->bf_buf_addr = 0; |
| 150 | bf->bf_mpdu = NULL; | ||
| 150 | } | 151 | } |
| 151 | 152 | ||
| 152 | skb = ieee80211_beacon_get(hw, vif); | 153 | skb = ieee80211_beacon_get(hw, vif); |
| @@ -359,7 +360,6 @@ void ath9k_beacon_tasklet(unsigned long data) | |||
| 359 | return; | 360 | return; |
| 360 | 361 | ||
| 361 | bf = ath9k_beacon_generate(sc->hw, vif); | 362 | bf = ath9k_beacon_generate(sc->hw, vif); |
| 362 | WARN_ON(!bf); | ||
| 363 | 363 | ||
| 364 | if (sc->beacon.bmisscnt != 0) { | 364 | if (sc->beacon.bmisscnt != 0) { |
| 365 | ath_dbg(common, BSTUCK, "resume beacon xmit after %u misses\n", | 365 | ath_dbg(common, BSTUCK, "resume beacon xmit after %u misses\n", |
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 13ff9edc2401..e585fc827c50 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c | |||
| @@ -861,7 +861,6 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf, | |||
| 861 | RXS_ERR("RX-LENGTH-ERR", rx_len_err); | 861 | RXS_ERR("RX-LENGTH-ERR", rx_len_err); |
| 862 | RXS_ERR("RX-OOM-ERR", rx_oom_err); | 862 | RXS_ERR("RX-OOM-ERR", rx_oom_err); |
| 863 | RXS_ERR("RX-RATE-ERR", rx_rate_err); | 863 | RXS_ERR("RX-RATE-ERR", rx_rate_err); |
| 864 | RXS_ERR("RX-DROP-RXFLUSH", rx_drop_rxflush); | ||
| 865 | RXS_ERR("RX-TOO-MANY-FRAGS", rx_too_many_frags_err); | 864 | RXS_ERR("RX-TOO-MANY-FRAGS", rx_too_many_frags_err); |
| 866 | 865 | ||
| 867 | PHY_ERR("UNDERRUN ERR", ATH9K_PHYERR_UNDERRUN); | 866 | PHY_ERR("UNDERRUN ERR", ATH9K_PHYERR_UNDERRUN); |
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index 375c3b46411e..6df2ab62dcb7 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h | |||
| @@ -216,7 +216,6 @@ struct ath_tx_stats { | |||
| 216 | * @rx_oom_err: No. of frames dropped due to OOM issues. | 216 | * @rx_oom_err: No. of frames dropped due to OOM issues. |
| 217 | * @rx_rate_err: No. of frames dropped due to rate errors. | 217 | * @rx_rate_err: No. of frames dropped due to rate errors. |
| 218 | * @rx_too_many_frags_err: Frames dropped due to too-many-frags received. | 218 | * @rx_too_many_frags_err: Frames dropped due to too-many-frags received. |
| 219 | * @rx_drop_rxflush: No. of frames dropped due to RX-FLUSH. | ||
| 220 | * @rx_beacons: No. of beacons received. | 219 | * @rx_beacons: No. of beacons received. |
| 221 | * @rx_frags: No. of rx-fragements received. | 220 | * @rx_frags: No. of rx-fragements received. |
| 222 | */ | 221 | */ |
| @@ -235,7 +234,6 @@ struct ath_rx_stats { | |||
| 235 | u32 rx_oom_err; | 234 | u32 rx_oom_err; |
| 236 | u32 rx_rate_err; | 235 | u32 rx_rate_err; |
| 237 | u32 rx_too_many_frags_err; | 236 | u32 rx_too_many_frags_err; |
| 238 | u32 rx_drop_rxflush; | ||
| 239 | u32 rx_beacons; | 237 | u32 rx_beacons; |
| 240 | u32 rx_frags; | 238 | u32 rx_frags; |
| 241 | }; | 239 | }; |
diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c index 4a9570dfba72..aac4a406a513 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.c +++ b/drivers/net/wireless/ath/ath9k/htc_hst.c | |||
| @@ -344,6 +344,8 @@ void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle, | |||
| 344 | endpoint->ep_callbacks.tx(endpoint->ep_callbacks.priv, | 344 | endpoint->ep_callbacks.tx(endpoint->ep_callbacks.priv, |
| 345 | skb, htc_hdr->endpoint_id, | 345 | skb, htc_hdr->endpoint_id, |
| 346 | txok); | 346 | txok); |
| 347 | } else { | ||
| 348 | kfree_skb(skb); | ||
| 347 | } | 349 | } |
| 348 | } | 350 | } |
| 349 | 351 | ||
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 7f1a8e91c908..9d26fc56ca56 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h | |||
| @@ -1066,6 +1066,7 @@ void ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain); | |||
| 1066 | int ar9003_paprd_init_table(struct ath_hw *ah); | 1066 | int ar9003_paprd_init_table(struct ath_hw *ah); |
| 1067 | bool ar9003_paprd_is_done(struct ath_hw *ah); | 1067 | bool ar9003_paprd_is_done(struct ath_hw *ah); |
| 1068 | bool ar9003_is_paprd_enabled(struct ath_hw *ah); | 1068 | bool ar9003_is_paprd_enabled(struct ath_hw *ah); |
| 1069 | void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx); | ||
| 1069 | 1070 | ||
| 1070 | /* Hardware family op attach helpers */ | 1071 | /* Hardware family op attach helpers */ |
| 1071 | void ar5008_hw_attach_phy_ops(struct ath_hw *ah); | 1072 | void ar5008_hw_attach_phy_ops(struct ath_hw *ah); |
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index be30a9af1528..dd91f8fdc01c 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
| @@ -182,7 +182,7 @@ static void ath_restart_work(struct ath_softc *sc) | |||
| 182 | ath_start_ani(sc); | 182 | ath_start_ani(sc); |
| 183 | } | 183 | } |
| 184 | 184 | ||
| 185 | static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush) | 185 | static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx) |
| 186 | { | 186 | { |
| 187 | struct ath_hw *ah = sc->sc_ah; | 187 | struct ath_hw *ah = sc->sc_ah; |
| 188 | bool ret = true; | 188 | bool ret = true; |
| @@ -202,14 +202,6 @@ static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush) | |||
| 202 | if (!ath_drain_all_txq(sc, retry_tx)) | 202 | if (!ath_drain_all_txq(sc, retry_tx)) |
| 203 | ret = false; | 203 | ret = false; |
| 204 | 204 | ||
| 205 | if (!flush) { | ||
| 206 | if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) | ||
| 207 | ath_rx_tasklet(sc, 1, true); | ||
| 208 | ath_rx_tasklet(sc, 1, false); | ||
| 209 | } else { | ||
| 210 | ath_flushrecv(sc); | ||
| 211 | } | ||
| 212 | |||
| 213 | return ret; | 205 | return ret; |
| 214 | } | 206 | } |
| 215 | 207 | ||
| @@ -262,11 +254,11 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan, | |||
| 262 | struct ath_common *common = ath9k_hw_common(ah); | 254 | struct ath_common *common = ath9k_hw_common(ah); |
| 263 | struct ath9k_hw_cal_data *caldata = NULL; | 255 | struct ath9k_hw_cal_data *caldata = NULL; |
| 264 | bool fastcc = true; | 256 | bool fastcc = true; |
| 265 | bool flush = false; | ||
| 266 | int r; | 257 | int r; |
| 267 | 258 | ||
| 268 | __ath_cancel_work(sc); | 259 | __ath_cancel_work(sc); |
| 269 | 260 | ||
| 261 | tasklet_disable(&sc->intr_tq); | ||
| 270 | spin_lock_bh(&sc->sc_pcu_lock); | 262 | spin_lock_bh(&sc->sc_pcu_lock); |
| 271 | 263 | ||
| 272 | if (!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) { | 264 | if (!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) { |
| @@ -276,11 +268,10 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan, | |||
| 276 | 268 | ||
| 277 | if (!hchan) { | 269 | if (!hchan) { |
| 278 | fastcc = false; | 270 | fastcc = false; |
| 279 | flush = true; | ||
| 280 | hchan = ah->curchan; | 271 | hchan = ah->curchan; |
| 281 | } | 272 | } |
| 282 | 273 | ||
| 283 | if (!ath_prepare_reset(sc, retry_tx, flush)) | 274 | if (!ath_prepare_reset(sc, retry_tx)) |
| 284 | fastcc = false; | 275 | fastcc = false; |
| 285 | 276 | ||
| 286 | ath_dbg(common, CONFIG, "Reset to %u MHz, HT40: %d fastcc: %d\n", | 277 | ath_dbg(common, CONFIG, "Reset to %u MHz, HT40: %d fastcc: %d\n", |
| @@ -302,6 +293,8 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan, | |||
| 302 | 293 | ||
| 303 | out: | 294 | out: |
| 304 | spin_unlock_bh(&sc->sc_pcu_lock); | 295 | spin_unlock_bh(&sc->sc_pcu_lock); |
| 296 | tasklet_enable(&sc->intr_tq); | ||
| 297 | |||
| 305 | return r; | 298 | return r; |
| 306 | } | 299 | } |
| 307 | 300 | ||
| @@ -804,7 +797,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) | |||
| 804 | ath9k_hw_cfg_gpio_input(ah, ah->led_pin); | 797 | ath9k_hw_cfg_gpio_input(ah, ah->led_pin); |
| 805 | } | 798 | } |
| 806 | 799 | ||
| 807 | ath_prepare_reset(sc, false, true); | 800 | ath_prepare_reset(sc, false); |
| 808 | 801 | ||
| 809 | if (sc->rx.frag) { | 802 | if (sc->rx.frag) { |
| 810 | dev_kfree_skb_any(sc->rx.frag); | 803 | dev_kfree_skb_any(sc->rx.frag); |
| @@ -1833,6 +1826,9 @@ static u32 fill_chainmask(u32 cap, u32 new) | |||
| 1833 | 1826 | ||
| 1834 | static bool validate_antenna_mask(struct ath_hw *ah, u32 val) | 1827 | static bool validate_antenna_mask(struct ath_hw *ah, u32 val) |
| 1835 | { | 1828 | { |
| 1829 | if (AR_SREV_9300_20_OR_LATER(ah)) | ||
| 1830 | return true; | ||
| 1831 | |||
| 1836 | switch (val & 0x7) { | 1832 | switch (val & 0x7) { |
| 1837 | case 0x1: | 1833 | case 0x1: |
| 1838 | case 0x3: | 1834 | case 0x3: |
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index d4df98a938bf..90752f246970 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c | |||
| @@ -254,8 +254,6 @@ rx_init_fail: | |||
| 254 | 254 | ||
| 255 | static void ath_edma_start_recv(struct ath_softc *sc) | 255 | static void ath_edma_start_recv(struct ath_softc *sc) |
| 256 | { | 256 | { |
| 257 | spin_lock_bh(&sc->rx.rxbuflock); | ||
| 258 | |||
| 259 | ath9k_hw_rxena(sc->sc_ah); | 257 | ath9k_hw_rxena(sc->sc_ah); |
| 260 | 258 | ||
| 261 | ath_rx_addbuffer_edma(sc, ATH9K_RX_QUEUE_HP, | 259 | ath_rx_addbuffer_edma(sc, ATH9K_RX_QUEUE_HP, |
| @@ -267,8 +265,6 @@ static void ath_edma_start_recv(struct ath_softc *sc) | |||
| 267 | ath_opmode_init(sc); | 265 | ath_opmode_init(sc); |
| 268 | 266 | ||
| 269 | ath9k_hw_startpcureceive(sc->sc_ah, !!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)); | 267 | ath9k_hw_startpcureceive(sc->sc_ah, !!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)); |
| 270 | |||
| 271 | spin_unlock_bh(&sc->rx.rxbuflock); | ||
| 272 | } | 268 | } |
| 273 | 269 | ||
| 274 | static void ath_edma_stop_recv(struct ath_softc *sc) | 270 | static void ath_edma_stop_recv(struct ath_softc *sc) |
| @@ -285,8 +281,6 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) | |||
| 285 | int error = 0; | 281 | int error = 0; |
| 286 | 282 | ||
| 287 | spin_lock_init(&sc->sc_pcu_lock); | 283 | spin_lock_init(&sc->sc_pcu_lock); |
| 288 | spin_lock_init(&sc->rx.rxbuflock); | ||
| 289 | clear_bit(SC_OP_RXFLUSH, &sc->sc_flags); | ||
| 290 | 284 | ||
| 291 | common->rx_bufsize = IEEE80211_MAX_MPDU_LEN / 2 + | 285 | common->rx_bufsize = IEEE80211_MAX_MPDU_LEN / 2 + |
| 292 | sc->sc_ah->caps.rx_status_len; | 286 | sc->sc_ah->caps.rx_status_len; |
| @@ -447,7 +441,6 @@ int ath_startrecv(struct ath_softc *sc) | |||
| 447 | return 0; | 441 | return 0; |
| 448 | } | 442 | } |
| 449 | 443 | ||
| 450 | spin_lock_bh(&sc->rx.rxbuflock); | ||
| 451 | if (list_empty(&sc->rx.rxbuf)) | 444 | if (list_empty(&sc->rx.rxbuf)) |
| 452 | goto start_recv; | 445 | goto start_recv; |
| 453 | 446 | ||
| @@ -468,26 +461,31 @@ start_recv: | |||
| 468 | ath_opmode_init(sc); | 461 | ath_opmode_init(sc); |
| 469 | ath9k_hw_startpcureceive(ah, !!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)); | 462 | ath9k_hw_startpcureceive(ah, !!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)); |
| 470 | 463 | ||
| 471 | spin_unlock_bh(&sc->rx.rxbuflock); | ||
| 472 | |||
| 473 | return 0; | 464 | return 0; |
| 474 | } | 465 | } |
| 475 | 466 | ||
| 467 | static void ath_flushrecv(struct ath_softc *sc) | ||
| 468 | { | ||
| 469 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) | ||
| 470 | ath_rx_tasklet(sc, 1, true); | ||
| 471 | ath_rx_tasklet(sc, 1, false); | ||
| 472 | } | ||
| 473 | |||
| 476 | bool ath_stoprecv(struct ath_softc *sc) | 474 | bool ath_stoprecv(struct ath_softc *sc) |
| 477 | { | 475 | { |
| 478 | struct ath_hw *ah = sc->sc_ah; | 476 | struct ath_hw *ah = sc->sc_ah; |
| 479 | bool stopped, reset = false; | 477 | bool stopped, reset = false; |
| 480 | 478 | ||
| 481 | spin_lock_bh(&sc->rx.rxbuflock); | ||
| 482 | ath9k_hw_abortpcurecv(ah); | 479 | ath9k_hw_abortpcurecv(ah); |
| 483 | ath9k_hw_setrxfilter(ah, 0); | 480 | ath9k_hw_setrxfilter(ah, 0); |
| 484 | stopped = ath9k_hw_stopdmarecv(ah, &reset); | 481 | stopped = ath9k_hw_stopdmarecv(ah, &reset); |
| 485 | 482 | ||
| 483 | ath_flushrecv(sc); | ||
| 484 | |||
| 486 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) | 485 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) |
| 487 | ath_edma_stop_recv(sc); | 486 | ath_edma_stop_recv(sc); |
| 488 | else | 487 | else |
| 489 | sc->rx.rxlink = NULL; | 488 | sc->rx.rxlink = NULL; |
| 490 | spin_unlock_bh(&sc->rx.rxbuflock); | ||
| 491 | 489 | ||
| 492 | if (!(ah->ah_flags & AH_UNPLUGGED) && | 490 | if (!(ah->ah_flags & AH_UNPLUGGED) && |
| 493 | unlikely(!stopped)) { | 491 | unlikely(!stopped)) { |
| @@ -499,15 +497,6 @@ bool ath_stoprecv(struct ath_softc *sc) | |||
| 499 | return stopped && !reset; | 497 | return stopped && !reset; |
| 500 | } | 498 | } |
| 501 | 499 | ||
| 502 | void ath_flushrecv(struct ath_softc *sc) | ||
| 503 | { | ||
| 504 | set_bit(SC_OP_RXFLUSH, &sc->sc_flags); | ||
| 505 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) | ||
| 506 | ath_rx_tasklet(sc, 1, true); | ||
| 507 | ath_rx_tasklet(sc, 1, false); | ||
| 508 | clear_bit(SC_OP_RXFLUSH, &sc->sc_flags); | ||
| 509 | } | ||
| 510 | |||
| 511 | static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb) | 500 | static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb) |
| 512 | { | 501 | { |
| 513 | /* Check whether the Beacon frame has DTIM indicating buffered bc/mc */ | 502 | /* Check whether the Beacon frame has DTIM indicating buffered bc/mc */ |
| @@ -744,6 +733,7 @@ static struct ath_buf *ath_get_next_rx_buf(struct ath_softc *sc, | |||
| 744 | return NULL; | 733 | return NULL; |
| 745 | } | 734 | } |
| 746 | 735 | ||
| 736 | list_del(&bf->list); | ||
| 747 | if (!bf->bf_mpdu) | 737 | if (!bf->bf_mpdu) |
| 748 | return bf; | 738 | return bf; |
| 749 | 739 | ||
| @@ -1059,16 +1049,12 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) | |||
| 1059 | dma_type = DMA_FROM_DEVICE; | 1049 | dma_type = DMA_FROM_DEVICE; |
| 1060 | 1050 | ||
| 1061 | qtype = hp ? ATH9K_RX_QUEUE_HP : ATH9K_RX_QUEUE_LP; | 1051 | qtype = hp ? ATH9K_RX_QUEUE_HP : ATH9K_RX_QUEUE_LP; |
| 1062 | spin_lock_bh(&sc->rx.rxbuflock); | ||
| 1063 | 1052 | ||
| 1064 | tsf = ath9k_hw_gettsf64(ah); | 1053 | tsf = ath9k_hw_gettsf64(ah); |
| 1065 | tsf_lower = tsf & 0xffffffff; | 1054 | tsf_lower = tsf & 0xffffffff; |
| 1066 | 1055 | ||
| 1067 | do { | 1056 | do { |
| 1068 | bool decrypt_error = false; | 1057 | bool decrypt_error = false; |
| 1069 | /* If handling rx interrupt and flush is in progress => exit */ | ||
| 1070 | if (test_bit(SC_OP_RXFLUSH, &sc->sc_flags) && (flush == 0)) | ||
| 1071 | break; | ||
| 1072 | 1058 | ||
| 1073 | memset(&rs, 0, sizeof(rs)); | 1059 | memset(&rs, 0, sizeof(rs)); |
| 1074 | if (edma) | 1060 | if (edma) |
| @@ -1111,15 +1097,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) | |||
| 1111 | 1097 | ||
| 1112 | ath_debug_stat_rx(sc, &rs); | 1098 | ath_debug_stat_rx(sc, &rs); |
| 1113 | 1099 | ||
| 1114 | /* | ||
| 1115 | * If we're asked to flush receive queue, directly | ||
| 1116 | * chain it back at the queue without processing it. | ||
| 1117 | */ | ||
| 1118 | if (test_bit(SC_OP_RXFLUSH, &sc->sc_flags)) { | ||
| 1119 | RX_STAT_INC(rx_drop_rxflush); | ||
| 1120 | goto requeue_drop_frag; | ||
| 1121 | } | ||
| 1122 | |||
| 1123 | memset(rxs, 0, sizeof(struct ieee80211_rx_status)); | 1100 | memset(rxs, 0, sizeof(struct ieee80211_rx_status)); |
| 1124 | 1101 | ||
| 1125 | rxs->mactime = (tsf & ~0xffffffffULL) | rs.rs_tstamp; | 1102 | rxs->mactime = (tsf & ~0xffffffffULL) | rs.rs_tstamp; |
| @@ -1254,19 +1231,18 @@ requeue_drop_frag: | |||
| 1254 | sc->rx.frag = NULL; | 1231 | sc->rx.frag = NULL; |
| 1255 | } | 1232 | } |
| 1256 | requeue: | 1233 | requeue: |
| 1234 | list_add_tail(&bf->list, &sc->rx.rxbuf); | ||
| 1235 | if (flush) | ||
| 1236 | continue; | ||
| 1237 | |||
| 1257 | if (edma) { | 1238 | if (edma) { |
| 1258 | list_add_tail(&bf->list, &sc->rx.rxbuf); | ||
| 1259 | ath_rx_edma_buf_link(sc, qtype); | 1239 | ath_rx_edma_buf_link(sc, qtype); |
| 1260 | } else { | 1240 | } else { |
| 1261 | list_move_tail(&bf->list, &sc->rx.rxbuf); | ||
| 1262 | ath_rx_buf_link(sc, bf); | 1241 | ath_rx_buf_link(sc, bf); |
| 1263 | if (!flush) | 1242 | ath9k_hw_rxena(ah); |
| 1264 | ath9k_hw_rxena(ah); | ||
| 1265 | } | 1243 | } |
| 1266 | } while (1); | 1244 | } while (1); |
| 1267 | 1245 | ||
| 1268 | spin_unlock_bh(&sc->rx.rxbuflock); | ||
| 1269 | |||
| 1270 | if (!(ah->imask & ATH9K_INT_RXEOL)) { | 1246 | if (!(ah->imask & ATH9K_INT_RXEOL)) { |
| 1271 | ah->imask |= (ATH9K_INT_RXEOL | ATH9K_INT_RXORN); | 1247 | ah->imask |= (ATH9K_INT_RXEOL | ATH9K_INT_RXORN); |
| 1272 | ath9k_hw_set_interrupts(ah); | 1248 | ath9k_hw_set_interrupts(ah); |
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/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index 1fbd8ecbe2ea..0f71d1d4339d 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c | |||
| @@ -1407,9 +1407,10 @@ void brcms_add_timer(struct brcms_timer *t, uint ms, int periodic) | |||
| 1407 | #endif | 1407 | #endif |
| 1408 | t->ms = ms; | 1408 | t->ms = ms; |
| 1409 | t->periodic = (bool) periodic; | 1409 | t->periodic = (bool) periodic; |
| 1410 | t->set = true; | 1410 | if (!t->set) { |
| 1411 | 1411 | t->set = true; | |
| 1412 | atomic_inc(&t->wl->callbacks); | 1412 | atomic_inc(&t->wl->callbacks); |
| 1413 | } | ||
| 1413 | 1414 | ||
| 1414 | ieee80211_queue_delayed_work(hw, &t->dly_wrk, msecs_to_jiffies(ms)); | 1415 | ieee80211_queue_delayed_work(hw, &t->dly_wrk, msecs_to_jiffies(ms)); |
| 1415 | } | 1416 | } |
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/iwlegacy/common.c b/drivers/net/wireless/iwlegacy/common.c index 7e16d10a7f14..90b8970eadf0 100644 --- a/drivers/net/wireless/iwlegacy/common.c +++ b/drivers/net/wireless/iwlegacy/common.c | |||
| @@ -3958,17 +3958,21 @@ il_connection_init_rx_config(struct il_priv *il) | |||
| 3958 | 3958 | ||
| 3959 | memset(&il->staging, 0, sizeof(il->staging)); | 3959 | memset(&il->staging, 0, sizeof(il->staging)); |
| 3960 | 3960 | ||
| 3961 | if (!il->vif) { | 3961 | switch (il->iw_mode) { |
| 3962 | case NL80211_IFTYPE_UNSPECIFIED: | ||
| 3962 | il->staging.dev_type = RXON_DEV_TYPE_ESS; | 3963 | il->staging.dev_type = RXON_DEV_TYPE_ESS; |
| 3963 | } else if (il->vif->type == NL80211_IFTYPE_STATION) { | 3964 | break; |
| 3965 | case NL80211_IFTYPE_STATION: | ||
| 3964 | il->staging.dev_type = RXON_DEV_TYPE_ESS; | 3966 | il->staging.dev_type = RXON_DEV_TYPE_ESS; |
| 3965 | il->staging.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK; | 3967 | il->staging.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK; |
| 3966 | } else if (il->vif->type == NL80211_IFTYPE_ADHOC) { | 3968 | break; |
| 3969 | case NL80211_IFTYPE_ADHOC: | ||
| 3967 | il->staging.dev_type = RXON_DEV_TYPE_IBSS; | 3970 | il->staging.dev_type = RXON_DEV_TYPE_IBSS; |
| 3968 | il->staging.flags = RXON_FLG_SHORT_PREAMBLE_MSK; | 3971 | il->staging.flags = RXON_FLG_SHORT_PREAMBLE_MSK; |
| 3969 | il->staging.filter_flags = | 3972 | il->staging.filter_flags = |
| 3970 | RXON_FILTER_BCON_AWARE_MSK | RXON_FILTER_ACCEPT_GRP_MSK; | 3973 | RXON_FILTER_BCON_AWARE_MSK | RXON_FILTER_ACCEPT_GRP_MSK; |
| 3971 | } else { | 3974 | break; |
| 3975 | default: | ||
| 3972 | IL_ERR("Unsupported interface type %d\n", il->vif->type); | 3976 | IL_ERR("Unsupported interface type %d\n", il->vif->type); |
| 3973 | return; | 3977 | return; |
| 3974 | } | 3978 | } |
| @@ -4550,8 +4554,7 @@ out: | |||
| 4550 | EXPORT_SYMBOL(il_mac_add_interface); | 4554 | EXPORT_SYMBOL(il_mac_add_interface); |
| 4551 | 4555 | ||
| 4552 | static void | 4556 | static void |
| 4553 | il_teardown_interface(struct il_priv *il, struct ieee80211_vif *vif, | 4557 | il_teardown_interface(struct il_priv *il, struct ieee80211_vif *vif) |
| 4554 | bool mode_change) | ||
| 4555 | { | 4558 | { |
| 4556 | lockdep_assert_held(&il->mutex); | 4559 | lockdep_assert_held(&il->mutex); |
| 4557 | 4560 | ||
| @@ -4560,9 +4563,7 @@ il_teardown_interface(struct il_priv *il, struct ieee80211_vif *vif, | |||
| 4560 | il_force_scan_end(il); | 4563 | il_force_scan_end(il); |
| 4561 | } | 4564 | } |
| 4562 | 4565 | ||
| 4563 | if (!mode_change) | 4566 | il_set_mode(il); |
| 4564 | il_set_mode(il); | ||
| 4565 | |||
| 4566 | } | 4567 | } |
| 4567 | 4568 | ||
| 4568 | void | 4569 | void |
| @@ -4575,8 +4576,8 @@ il_mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | |||
| 4575 | 4576 | ||
| 4576 | WARN_ON(il->vif != vif); | 4577 | WARN_ON(il->vif != vif); |
| 4577 | il->vif = NULL; | 4578 | il->vif = NULL; |
| 4578 | 4579 | il->iw_mode = NL80211_IFTYPE_UNSPECIFIED; | |
| 4579 | il_teardown_interface(il, vif, false); | 4580 | il_teardown_interface(il, vif); |
| 4580 | memset(il->bssid, 0, ETH_ALEN); | 4581 | memset(il->bssid, 0, ETH_ALEN); |
| 4581 | 4582 | ||
| 4582 | D_MAC80211("leave\n"); | 4583 | D_MAC80211("leave\n"); |
| @@ -4685,18 +4686,10 @@ il_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | |||
| 4685 | } | 4686 | } |
| 4686 | 4687 | ||
| 4687 | /* success */ | 4688 | /* success */ |
| 4688 | il_teardown_interface(il, vif, true); | ||
| 4689 | vif->type = newtype; | 4689 | vif->type = newtype; |
| 4690 | vif->p2p = false; | 4690 | vif->p2p = false; |
| 4691 | err = il_set_mode(il); | 4691 | il->iw_mode = newtype; |
| 4692 | WARN_ON(err); | 4692 | il_teardown_interface(il, vif); |
| 4693 | /* | ||
| 4694 | * We've switched internally, but submitting to the | ||
| 4695 | * device may have failed for some reason. Mask this | ||
| 4696 | * error, because otherwise mac80211 will not switch | ||
| 4697 | * (and set the interface type back) and we'll be | ||
| 4698 | * out of sync with it. | ||
| 4699 | */ | ||
| 4700 | err = 0; | 4693 | err = 0; |
| 4701 | 4694 | ||
| 4702 | out: | 4695 | out: |
diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c index da21328ca8ed..31534f7c0548 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/iwlwifi/dvm/tx.c | |||
| @@ -1079,6 +1079,8 @@ static void iwlagn_set_tx_status(struct iwl_priv *priv, | |||
| 1079 | { | 1079 | { |
| 1080 | u16 status = le16_to_cpu(tx_resp->status.status); | 1080 | u16 status = le16_to_cpu(tx_resp->status.status); |
| 1081 | 1081 | ||
| 1082 | info->flags &= ~IEEE80211_TX_CTL_AMPDU; | ||
| 1083 | |||
| 1082 | info->status.rates[0].count = tx_resp->failure_frame + 1; | 1084 | info->status.rates[0].count = tx_resp->failure_frame + 1; |
| 1083 | info->flags |= iwl_tx_status_to_mac80211(status); | 1085 | info->flags |= iwl_tx_status_to_mac80211(status); |
| 1084 | iwlagn_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags), | 1086 | iwlagn_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags), |
| @@ -1151,13 +1153,6 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, | |||
| 1151 | next_reclaimed = ssn; | 1153 | next_reclaimed = ssn; |
| 1152 | } | 1154 | } |
| 1153 | 1155 | ||
| 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); | 1156 | iwl_trans_reclaim(priv->trans, txq_id, ssn, &skbs); |
| 1162 | 1157 | ||
| 1163 | iwlagn_check_ratid_empty(priv, sta_id, tid); | 1158 | iwlagn_check_ratid_empty(priv, sta_id, tid); |
| @@ -1208,11 +1203,28 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, | |||
| 1208 | if (!is_agg) | 1203 | if (!is_agg) |
| 1209 | iwlagn_non_agg_tx_status(priv, ctx, hdr->addr1); | 1204 | iwlagn_non_agg_tx_status(priv, ctx, hdr->addr1); |
| 1210 | 1205 | ||
| 1206 | /* | ||
| 1207 | * W/A for FW bug - the seq_ctl isn't updated when the | ||
| 1208 | * queues are flushed. Fetch it from the packet itself | ||
| 1209 | */ | ||
| 1210 | if (!is_agg && status == TX_STATUS_FAIL_FIFO_FLUSHED) { | ||
| 1211 | next_reclaimed = le16_to_cpu(hdr->seq_ctrl); | ||
| 1212 | next_reclaimed = | ||
| 1213 | SEQ_TO_SN(next_reclaimed + 0x10); | ||
| 1214 | } | ||
| 1215 | |||
| 1211 | is_offchannel_skb = | 1216 | is_offchannel_skb = |
| 1212 | (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN); | 1217 | (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN); |
| 1213 | freed++; | 1218 | freed++; |
| 1214 | } | 1219 | } |
| 1215 | 1220 | ||
| 1221 | if (tid != IWL_TID_NON_QOS) { | ||
| 1222 | priv->tid_data[sta_id][tid].next_reclaimed = | ||
| 1223 | next_reclaimed; | ||
| 1224 | IWL_DEBUG_TX_REPLY(priv, "Next reclaimed packet:%d\n", | ||
| 1225 | next_reclaimed); | ||
| 1226 | } | ||
| 1227 | |||
| 1216 | WARN_ON(!is_agg && freed != 1); | 1228 | WARN_ON(!is_agg && freed != 1); |
| 1217 | 1229 | ||
| 1218 | /* | 1230 | /* |
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..cdb11b3964e2 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c | |||
| @@ -1459,7 +1459,7 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, | |||
| 1459 | struct cfg80211_ssid req_ssid; | 1459 | struct cfg80211_ssid req_ssid; |
| 1460 | int ret, auth_type = 0; | 1460 | int ret, auth_type = 0; |
| 1461 | struct cfg80211_bss *bss = NULL; | 1461 | struct cfg80211_bss *bss = NULL; |
| 1462 | u8 is_scanning_required = 0, config_bands = 0; | 1462 | u8 is_scanning_required = 0; |
| 1463 | 1463 | ||
| 1464 | memset(&req_ssid, 0, sizeof(struct cfg80211_ssid)); | 1464 | memset(&req_ssid, 0, sizeof(struct cfg80211_ssid)); |
| 1465 | 1465 | ||
| @@ -1478,19 +1478,6 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, | |||
| 1478 | /* disconnect before try to associate */ | 1478 | /* disconnect before try to associate */ |
| 1479 | mwifiex_deauthenticate(priv, NULL); | 1479 | mwifiex_deauthenticate(priv, NULL); |
| 1480 | 1480 | ||
| 1481 | if (channel) { | ||
| 1482 | if (mode == NL80211_IFTYPE_STATION) { | ||
| 1483 | if (channel->band == IEEE80211_BAND_2GHZ) | ||
| 1484 | config_bands = BAND_B | BAND_G | BAND_GN; | ||
| 1485 | else | ||
| 1486 | config_bands = BAND_A | BAND_AN; | ||
| 1487 | |||
| 1488 | if (!((config_bands | priv->adapter->fw_bands) & | ||
| 1489 | ~priv->adapter->fw_bands)) | ||
| 1490 | priv->adapter->config_bands = config_bands; | ||
| 1491 | } | ||
| 1492 | } | ||
| 1493 | |||
| 1494 | /* As this is new association, clear locally stored | 1481 | /* As this is new association, clear locally stored |
| 1495 | * keys and security related flags */ | 1482 | * keys and security related flags */ |
| 1496 | priv->sec_info.wpa_enabled = false; | 1483 | priv->sec_info.wpa_enabled = false; |
| @@ -1707,9 +1694,9 @@ static int mwifiex_set_ibss_params(struct mwifiex_private *priv, | |||
| 1707 | 1694 | ||
| 1708 | if (cfg80211_get_chandef_type(¶ms->chandef) != | 1695 | if (cfg80211_get_chandef_type(¶ms->chandef) != |
| 1709 | NL80211_CHAN_NO_HT) | 1696 | NL80211_CHAN_NO_HT) |
| 1710 | config_bands |= BAND_GN; | 1697 | config_bands |= BAND_G | BAND_GN; |
| 1711 | } else { | 1698 | } else { |
| 1712 | if (cfg80211_get_chandef_type(¶ms->chandef) != | 1699 | if (cfg80211_get_chandef_type(¶ms->chandef) == |
| 1713 | NL80211_CHAN_NO_HT) | 1700 | NL80211_CHAN_NO_HT) |
| 1714 | config_bands = BAND_A; | 1701 | config_bands = BAND_A; |
| 1715 | else | 1702 | else |
diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index 13fbc4eb1595..b879e1338a54 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c | |||
| @@ -161,7 +161,7 @@ static int mwifiex_pcie_suspend(struct pci_dev *pdev, pm_message_t state) | |||
| 161 | 161 | ||
| 162 | if (pdev) { | 162 | if (pdev) { |
| 163 | card = (struct pcie_service_card *) pci_get_drvdata(pdev); | 163 | card = (struct pcie_service_card *) pci_get_drvdata(pdev); |
| 164 | if (!card || card->adapter) { | 164 | if (!card || !card->adapter) { |
| 165 | pr_err("Card or adapter structure is not valid\n"); | 165 | pr_err("Card or adapter structure is not valid\n"); |
| 166 | return 0; | 166 | return 0; |
| 167 | } | 167 | } |
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index cb682561c438..f542bb8ccbc8 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; |
| @@ -287,6 +283,20 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, | |||
| 287 | if (ret) | 283 | if (ret) |
| 288 | goto done; | 284 | goto done; |
| 289 | 285 | ||
| 286 | if (bss_desc) { | ||
| 287 | u8 config_bands = 0; | ||
| 288 | |||
| 289 | if (mwifiex_band_to_radio_type((u8) bss_desc->bss_band) | ||
| 290 | == HostCmd_SCAN_RADIO_TYPE_BG) | ||
| 291 | config_bands = BAND_B | BAND_G | BAND_GN; | ||
| 292 | else | ||
| 293 | config_bands = BAND_A | BAND_AN; | ||
| 294 | |||
| 295 | if (!((config_bands | adapter->fw_bands) & | ||
| 296 | ~adapter->fw_bands)) | ||
| 297 | adapter->config_bands = config_bands; | ||
| 298 | } | ||
| 299 | |||
| 290 | ret = mwifiex_check_network_compatibility(priv, bss_desc); | 300 | ret = mwifiex_check_network_compatibility(priv, bss_desc); |
| 291 | if (ret) | 301 | if (ret) |
| 292 | goto done; | 302 | goto done; |
| @@ -496,8 +506,11 @@ int mwifiex_enable_hs(struct mwifiex_adapter *adapter) | |||
| 496 | return false; | 506 | return false; |
| 497 | } | 507 | } |
| 498 | 508 | ||
| 499 | wait_event_interruptible(adapter->hs_activate_wait_q, | 509 | if (wait_event_interruptible(adapter->hs_activate_wait_q, |
| 500 | adapter->hs_activate_wait_q_woken); | 510 | adapter->hs_activate_wait_q_woken)) { |
| 511 | dev_err(adapter->dev, "hs_activate_wait_q terminated\n"); | ||
| 512 | return false; | ||
| 513 | } | ||
| 501 | 514 | ||
| 502 | return true; | 515 | return true; |
| 503 | } | 516 | } |
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/Kconfig b/drivers/net/wireless/rtlwifi/Kconfig index 21b1bbb93a7e..b80bc4612581 100644 --- a/drivers/net/wireless/rtlwifi/Kconfig +++ b/drivers/net/wireless/rtlwifi/Kconfig | |||
| @@ -57,12 +57,12 @@ config RTL8192CU | |||
| 57 | 57 | ||
| 58 | config RTLWIFI | 58 | config RTLWIFI |
| 59 | tristate | 59 | tristate |
| 60 | depends on RTL8192CE || RTL8192CU || RTL8192SE || RTL8192DE | 60 | depends on RTL8192CE || RTL8192CU || RTL8192SE || RTL8192DE || RTL8723AE |
| 61 | default m | 61 | default m |
| 62 | 62 | ||
| 63 | config RTLWIFI_DEBUG | 63 | config RTLWIFI_DEBUG |
| 64 | bool "Additional debugging output" | 64 | bool "Additional debugging output" |
| 65 | depends on RTL8192CE || RTL8192CU || RTL8192SE || RTL8192DE | 65 | depends on RTL8192CE || RTL8192CU || RTL8192SE || RTL8192DE || RTL8723AE |
| 66 | default y | 66 | default y |
| 67 | 67 | ||
| 68 | config RTL8192C_COMMON | 68 | config RTL8192C_COMMON |
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/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index c31aeb01bb00..efaecefe3f8c 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig | |||
| @@ -181,7 +181,6 @@ config PINCTRL_COH901 | |||
| 181 | 181 | ||
| 182 | config PINCTRL_SAMSUNG | 182 | config PINCTRL_SAMSUNG |
| 183 | bool | 183 | bool |
| 184 | depends on OF && GPIOLIB | ||
| 185 | select PINMUX | 184 | select PINMUX |
| 186 | select PINCONF | 185 | select PINCONF |
| 187 | 186 | ||
diff --git a/drivers/pinctrl/mvebu/pinctrl-dove.c b/drivers/pinctrl/mvebu/pinctrl-dove.c index 69aba3697287..428ea96a94d3 100644 --- a/drivers/pinctrl/mvebu/pinctrl-dove.c +++ b/drivers/pinctrl/mvebu/pinctrl-dove.c | |||
| @@ -588,7 +588,7 @@ static int dove_pinctrl_probe(struct platform_device *pdev) | |||
| 588 | { | 588 | { |
| 589 | const struct of_device_id *match = | 589 | const struct of_device_id *match = |
| 590 | of_match_device(dove_pinctrl_of_match, &pdev->dev); | 590 | of_match_device(dove_pinctrl_of_match, &pdev->dev); |
| 591 | pdev->dev.platform_data = match->data; | 591 | pdev->dev.platform_data = (void *)match->data; |
| 592 | 592 | ||
| 593 | /* | 593 | /* |
| 594 | * General MPP Configuration Register is part of pdma registers. | 594 | * General MPP Configuration Register is part of pdma registers. |
diff --git a/drivers/pinctrl/mvebu/pinctrl-kirkwood.c b/drivers/pinctrl/mvebu/pinctrl-kirkwood.c index f12084e18057..cdd483df673e 100644 --- a/drivers/pinctrl/mvebu/pinctrl-kirkwood.c +++ b/drivers/pinctrl/mvebu/pinctrl-kirkwood.c | |||
| @@ -66,9 +66,9 @@ static struct mvebu_mpp_mode mv88f6xxx_mpp_modes[] = { | |||
| 66 | MPP_VAR_FUNCTION(0x5, "sata0", "act", V(0, 1, 1, 1, 1, 0)), | 66 | MPP_VAR_FUNCTION(0x5, "sata0", "act", V(0, 1, 1, 1, 1, 0)), |
| 67 | MPP_VAR_FUNCTION(0xb, "lcd", "vsync", V(0, 0, 0, 0, 1, 0))), | 67 | MPP_VAR_FUNCTION(0xb, "lcd", "vsync", V(0, 0, 0, 0, 1, 0))), |
| 68 | MPP_MODE(6, | 68 | MPP_MODE(6, |
| 69 | MPP_VAR_FUNCTION(0x0, "sysrst", "out", V(1, 1, 1, 1, 1, 1)), | 69 | MPP_VAR_FUNCTION(0x1, "sysrst", "out", V(1, 1, 1, 1, 1, 1)), |
| 70 | MPP_VAR_FUNCTION(0x1, "spi", "mosi", V(1, 1, 1, 1, 1, 1)), | 70 | MPP_VAR_FUNCTION(0x2, "spi", "mosi", V(1, 1, 1, 1, 1, 1)), |
| 71 | MPP_VAR_FUNCTION(0x2, "ptp", "trig", V(1, 1, 1, 1, 0, 0))), | 71 | MPP_VAR_FUNCTION(0x3, "ptp", "trig", V(1, 1, 1, 1, 0, 0))), |
| 72 | MPP_MODE(7, | 72 | MPP_MODE(7, |
| 73 | MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1)), | 73 | MPP_VAR_FUNCTION(0x0, "gpo", NULL, V(1, 1, 1, 1, 1, 1)), |
| 74 | MPP_VAR_FUNCTION(0x1, "pex", "rsto", V(1, 1, 1, 1, 0, 1)), | 74 | MPP_VAR_FUNCTION(0x1, "pex", "rsto", V(1, 1, 1, 1, 0, 1)), |
| @@ -458,7 +458,7 @@ static int kirkwood_pinctrl_probe(struct platform_device *pdev) | |||
| 458 | { | 458 | { |
| 459 | const struct of_device_id *match = | 459 | const struct of_device_id *match = |
| 460 | of_match_device(kirkwood_pinctrl_of_match, &pdev->dev); | 460 | of_match_device(kirkwood_pinctrl_of_match, &pdev->dev); |
| 461 | pdev->dev.platform_data = match->data; | 461 | pdev->dev.platform_data = (void *)match->data; |
| 462 | return mvebu_pinctrl_probe(pdev); | 462 | return mvebu_pinctrl_probe(pdev); |
| 463 | } | 463 | } |
| 464 | 464 | ||
diff --git a/drivers/pinctrl/pinctrl-exynos5440.c b/drivers/pinctrl/pinctrl-exynos5440.c index de05b64f0da6..142729914c34 100644 --- a/drivers/pinctrl/pinctrl-exynos5440.c +++ b/drivers/pinctrl/pinctrl-exynos5440.c | |||
| @@ -599,7 +599,7 @@ static int exynos5440_gpio_direction_output(struct gpio_chip *gc, unsigned offse | |||
| 599 | } | 599 | } |
| 600 | 600 | ||
| 601 | /* parse the pin numbers listed in the 'samsung,exynos5440-pins' property */ | 601 | /* parse the pin numbers listed in the 'samsung,exynos5440-pins' property */ |
| 602 | static int __init exynos5440_pinctrl_parse_dt_pins(struct platform_device *pdev, | 602 | static int exynos5440_pinctrl_parse_dt_pins(struct platform_device *pdev, |
| 603 | struct device_node *cfg_np, unsigned int **pin_list, | 603 | struct device_node *cfg_np, unsigned int **pin_list, |
| 604 | unsigned int *npins) | 604 | unsigned int *npins) |
| 605 | { | 605 | { |
| @@ -630,7 +630,7 @@ static int __init exynos5440_pinctrl_parse_dt_pins(struct platform_device *pdev, | |||
| 630 | * Parse the information about all the available pin groups and pin functions | 630 | * Parse the information about all the available pin groups and pin functions |
| 631 | * from device node of the pin-controller. | 631 | * from device node of the pin-controller. |
| 632 | */ | 632 | */ |
| 633 | static int __init exynos5440_pinctrl_parse_dt(struct platform_device *pdev, | 633 | static int exynos5440_pinctrl_parse_dt(struct platform_device *pdev, |
| 634 | struct exynos5440_pinctrl_priv_data *priv) | 634 | struct exynos5440_pinctrl_priv_data *priv) |
| 635 | { | 635 | { |
| 636 | struct device *dev = &pdev->dev; | 636 | struct device *dev = &pdev->dev; |
| @@ -723,7 +723,7 @@ static int __init exynos5440_pinctrl_parse_dt(struct platform_device *pdev, | |||
| 723 | } | 723 | } |
| 724 | 724 | ||
| 725 | /* register the pinctrl interface with the pinctrl subsystem */ | 725 | /* register the pinctrl interface with the pinctrl subsystem */ |
| 726 | static int __init exynos5440_pinctrl_register(struct platform_device *pdev, | 726 | static int exynos5440_pinctrl_register(struct platform_device *pdev, |
| 727 | struct exynos5440_pinctrl_priv_data *priv) | 727 | struct exynos5440_pinctrl_priv_data *priv) |
| 728 | { | 728 | { |
| 729 | struct device *dev = &pdev->dev; | 729 | struct device *dev = &pdev->dev; |
| @@ -798,7 +798,7 @@ static int __init exynos5440_pinctrl_register(struct platform_device *pdev, | |||
| 798 | } | 798 | } |
| 799 | 799 | ||
| 800 | /* register the gpiolib interface with the gpiolib subsystem */ | 800 | /* register the gpiolib interface with the gpiolib subsystem */ |
| 801 | static int __init exynos5440_gpiolib_register(struct platform_device *pdev, | 801 | static int exynos5440_gpiolib_register(struct platform_device *pdev, |
| 802 | struct exynos5440_pinctrl_priv_data *priv) | 802 | struct exynos5440_pinctrl_priv_data *priv) |
| 803 | { | 803 | { |
| 804 | struct gpio_chip *gc; | 804 | struct gpio_chip *gc; |
| @@ -831,7 +831,7 @@ static int __init exynos5440_gpiolib_register(struct platform_device *pdev, | |||
| 831 | } | 831 | } |
| 832 | 832 | ||
| 833 | /* unregister the gpiolib interface with the gpiolib subsystem */ | 833 | /* unregister the gpiolib interface with the gpiolib subsystem */ |
| 834 | static int __init exynos5440_gpiolib_unregister(struct platform_device *pdev, | 834 | static int exynos5440_gpiolib_unregister(struct platform_device *pdev, |
| 835 | struct exynos5440_pinctrl_priv_data *priv) | 835 | struct exynos5440_pinctrl_priv_data *priv) |
| 836 | { | 836 | { |
| 837 | int ret = gpiochip_remove(priv->gc); | 837 | int ret = gpiochip_remove(priv->gc); |
diff --git a/drivers/pinctrl/pinctrl-mxs.c b/drivers/pinctrl/pinctrl-mxs.c index dd227d21dcf2..23af9f1f9c35 100644 --- a/drivers/pinctrl/pinctrl-mxs.c +++ b/drivers/pinctrl/pinctrl-mxs.c | |||
| @@ -146,7 +146,7 @@ free: | |||
| 146 | static void mxs_dt_free_map(struct pinctrl_dev *pctldev, | 146 | static void mxs_dt_free_map(struct pinctrl_dev *pctldev, |
| 147 | struct pinctrl_map *map, unsigned num_maps) | 147 | struct pinctrl_map *map, unsigned num_maps) |
| 148 | { | 148 | { |
| 149 | int i; | 149 | u32 i; |
| 150 | 150 | ||
| 151 | for (i = 0; i < num_maps; i++) { | 151 | for (i = 0; i < num_maps; i++) { |
| 152 | if (map[i].type == PIN_MAP_TYPE_MUX_GROUP) | 152 | if (map[i].type == PIN_MAP_TYPE_MUX_GROUP) |
| @@ -203,7 +203,7 @@ static int mxs_pinctrl_enable(struct pinctrl_dev *pctldev, unsigned selector, | |||
| 203 | void __iomem *reg; | 203 | void __iomem *reg; |
| 204 | u8 bank, shift; | 204 | u8 bank, shift; |
| 205 | u16 pin; | 205 | u16 pin; |
| 206 | int i; | 206 | u32 i; |
| 207 | 207 | ||
| 208 | for (i = 0; i < g->npins; i++) { | 208 | for (i = 0; i < g->npins; i++) { |
| 209 | bank = PINID_TO_BANK(g->pins[i]); | 209 | bank = PINID_TO_BANK(g->pins[i]); |
| @@ -256,7 +256,7 @@ static int mxs_pinconf_group_set(struct pinctrl_dev *pctldev, | |||
| 256 | void __iomem *reg; | 256 | void __iomem *reg; |
| 257 | u8 ma, vol, pull, bank, shift; | 257 | u8 ma, vol, pull, bank, shift; |
| 258 | u16 pin; | 258 | u16 pin; |
| 259 | int i; | 259 | u32 i; |
| 260 | 260 | ||
| 261 | ma = CONFIG_TO_MA(config); | 261 | ma = CONFIG_TO_MA(config); |
| 262 | vol = CONFIG_TO_VOL(config); | 262 | vol = CONFIG_TO_VOL(config); |
| @@ -345,8 +345,7 @@ static int mxs_pinctrl_parse_group(struct platform_device *pdev, | |||
| 345 | const char *propname = "fsl,pinmux-ids"; | 345 | const char *propname = "fsl,pinmux-ids"; |
| 346 | char *group; | 346 | char *group; |
| 347 | int length = strlen(np->name) + SUFFIX_LEN; | 347 | int length = strlen(np->name) + SUFFIX_LEN; |
| 348 | int i; | 348 | u32 val, i; |
| 349 | u32 val; | ||
| 350 | 349 | ||
| 351 | group = devm_kzalloc(&pdev->dev, length, GFP_KERNEL); | 350 | group = devm_kzalloc(&pdev->dev, length, GFP_KERNEL); |
| 352 | if (!group) | 351 | if (!group) |
diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c index 1bb16ffb4e41..5767b18ebdff 100644 --- a/drivers/pinctrl/pinctrl-nomadik.c +++ b/drivers/pinctrl/pinctrl-nomadik.c | |||
| @@ -676,7 +676,7 @@ int nmk_gpio_set_mode(int gpio, int gpio_mode) | |||
| 676 | } | 676 | } |
| 677 | EXPORT_SYMBOL(nmk_gpio_set_mode); | 677 | EXPORT_SYMBOL(nmk_gpio_set_mode); |
| 678 | 678 | ||
| 679 | static int nmk_prcm_gpiocr_get_mode(struct pinctrl_dev *pctldev, int gpio) | 679 | static int __maybe_unused nmk_prcm_gpiocr_get_mode(struct pinctrl_dev *pctldev, int gpio) |
| 680 | { | 680 | { |
| 681 | int i; | 681 | int i; |
| 682 | u16 reg; | 682 | u16 reg; |
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index f6a360b86eb6..5c32e880bcb2 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c | |||
| @@ -30,7 +30,6 @@ | |||
| 30 | #define PCS_MUX_BITS_NAME "pinctrl-single,bits" | 30 | #define PCS_MUX_BITS_NAME "pinctrl-single,bits" |
| 31 | #define PCS_REG_NAME_LEN ((sizeof(unsigned long) * 2) + 1) | 31 | #define PCS_REG_NAME_LEN ((sizeof(unsigned long) * 2) + 1) |
| 32 | #define PCS_OFF_DISABLED ~0U | 32 | #define PCS_OFF_DISABLED ~0U |
| 33 | #define PCS_MAX_GPIO_VALUES 2 | ||
| 34 | 33 | ||
| 35 | /** | 34 | /** |
| 36 | * struct pcs_pingroup - pingroups for a function | 35 | * struct pcs_pingroup - pingroups for a function |
| @@ -78,16 +77,6 @@ struct pcs_function { | |||
| 78 | }; | 77 | }; |
| 79 | 78 | ||
| 80 | /** | 79 | /** |
| 81 | * struct pcs_gpio_range - pinctrl gpio range | ||
| 82 | * @range: subrange of the GPIO number space | ||
| 83 | * @gpio_func: gpio function value in the pinmux register | ||
| 84 | */ | ||
| 85 | struct pcs_gpio_range { | ||
| 86 | struct pinctrl_gpio_range range; | ||
| 87 | int gpio_func; | ||
| 88 | }; | ||
| 89 | |||
| 90 | /** | ||
| 91 | * struct pcs_data - wrapper for data needed by pinctrl framework | 80 | * struct pcs_data - wrapper for data needed by pinctrl framework |
| 92 | * @pa: pindesc array | 81 | * @pa: pindesc array |
| 93 | * @cur: index to current element | 82 | * @cur: index to current element |
| @@ -414,26 +403,9 @@ static void pcs_disable(struct pinctrl_dev *pctldev, unsigned fselector, | |||
| 414 | } | 403 | } |
| 415 | 404 | ||
| 416 | static int pcs_request_gpio(struct pinctrl_dev *pctldev, | 405 | static int pcs_request_gpio(struct pinctrl_dev *pctldev, |
| 417 | struct pinctrl_gpio_range *range, unsigned pin) | 406 | struct pinctrl_gpio_range *range, unsigned offset) |
| 418 | { | 407 | { |
| 419 | struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev); | 408 | return -ENOTSUPP; |
| 420 | struct pcs_gpio_range *gpio = NULL; | ||
| 421 | int end, mux_bytes; | ||
| 422 | unsigned data; | ||
| 423 | |||
| 424 | gpio = container_of(range, struct pcs_gpio_range, range); | ||
| 425 | end = range->pin_base + range->npins - 1; | ||
| 426 | if (pin < range->pin_base || pin > end) { | ||
| 427 | dev_err(pctldev->dev, | ||
| 428 | "pin %d isn't in the range of %d to %d\n", | ||
| 429 | pin, range->pin_base, end); | ||
| 430 | return -EINVAL; | ||
| 431 | } | ||
| 432 | mux_bytes = pcs->width / BITS_PER_BYTE; | ||
| 433 | data = pcs->read(pcs->base + pin * mux_bytes) & ~pcs->fmask; | ||
| 434 | data |= gpio->gpio_func; | ||
| 435 | pcs->write(data, pcs->base + pin * mux_bytes); | ||
| 436 | return 0; | ||
| 437 | } | 409 | } |
| 438 | 410 | ||
| 439 | static struct pinmux_ops pcs_pinmux_ops = { | 411 | static struct pinmux_ops pcs_pinmux_ops = { |
| @@ -907,49 +879,6 @@ static void pcs_free_resources(struct pcs_device *pcs) | |||
| 907 | 879 | ||
| 908 | static struct of_device_id pcs_of_match[]; | 880 | static struct of_device_id pcs_of_match[]; |
| 909 | 881 | ||
| 910 | static int pcs_add_gpio_range(struct device_node *node, struct pcs_device *pcs) | ||
| 911 | { | ||
| 912 | struct pcs_gpio_range *gpio; | ||
| 913 | struct device_node *child; | ||
| 914 | struct resource r; | ||
| 915 | const char name[] = "pinctrl-single"; | ||
| 916 | u32 gpiores[PCS_MAX_GPIO_VALUES]; | ||
| 917 | int ret, i = 0, mux_bytes = 0; | ||
| 918 | |||
| 919 | for_each_child_of_node(node, child) { | ||
| 920 | ret = of_address_to_resource(child, 0, &r); | ||
| 921 | if (ret < 0) | ||
| 922 | continue; | ||
| 923 | memset(gpiores, 0, sizeof(u32) * PCS_MAX_GPIO_VALUES); | ||
| 924 | ret = of_property_read_u32_array(child, "pinctrl-single,gpio", | ||
| 925 | gpiores, PCS_MAX_GPIO_VALUES); | ||
| 926 | if (ret < 0) | ||
| 927 | continue; | ||
| 928 | gpio = devm_kzalloc(pcs->dev, sizeof(*gpio), GFP_KERNEL); | ||
| 929 | if (!gpio) { | ||
| 930 | dev_err(pcs->dev, "failed to allocate pcs gpio\n"); | ||
| 931 | return -ENOMEM; | ||
| 932 | } | ||
| 933 | gpio->range.name = devm_kzalloc(pcs->dev, sizeof(name), | ||
| 934 | GFP_KERNEL); | ||
| 935 | if (!gpio->range.name) { | ||
| 936 | dev_err(pcs->dev, "failed to allocate range name\n"); | ||
| 937 | return -ENOMEM; | ||
| 938 | } | ||
| 939 | memcpy((char *)gpio->range.name, name, sizeof(name)); | ||
| 940 | |||
| 941 | gpio->range.id = i++; | ||
| 942 | gpio->range.base = gpiores[0]; | ||
| 943 | gpio->gpio_func = gpiores[1]; | ||
| 944 | mux_bytes = pcs->width / BITS_PER_BYTE; | ||
| 945 | gpio->range.pin_base = (r.start - pcs->res->start) / mux_bytes; | ||
| 946 | gpio->range.npins = (r.end - r.start) / mux_bytes + 1; | ||
| 947 | |||
| 948 | pinctrl_add_gpio_range(pcs->pctl, &gpio->range); | ||
| 949 | } | ||
| 950 | return 0; | ||
| 951 | } | ||
| 952 | |||
| 953 | static int pcs_probe(struct platform_device *pdev) | 882 | static int pcs_probe(struct platform_device *pdev) |
| 954 | { | 883 | { |
| 955 | struct device_node *np = pdev->dev.of_node; | 884 | struct device_node *np = pdev->dev.of_node; |
| @@ -1046,10 +975,6 @@ static int pcs_probe(struct platform_device *pdev) | |||
| 1046 | goto free; | 975 | goto free; |
| 1047 | } | 976 | } |
| 1048 | 977 | ||
| 1049 | ret = pcs_add_gpio_range(np, pcs); | ||
| 1050 | if (ret < 0) | ||
| 1051 | goto free; | ||
| 1052 | |||
| 1053 | dev_info(pcs->dev, "%i pins at pa %p size %u\n", | 978 | dev_info(pcs->dev, "%i pins at pa %p size %u\n", |
| 1054 | pcs->desc.npins, pcs->base, pcs->size); | 979 | pcs->desc.npins, pcs->base, pcs->size); |
| 1055 | 980 | ||
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/ibm_rtl.c b/drivers/platform/x86/ibm_rtl.c index 7481146a5b47..97c2be195efc 100644 --- a/drivers/platform/x86/ibm_rtl.c +++ b/drivers/platform/x86/ibm_rtl.c | |||
| @@ -244,7 +244,7 @@ static int __init ibm_rtl_init(void) { | |||
| 244 | if (force) | 244 | if (force) |
| 245 | pr_warn("module loaded by force\n"); | 245 | pr_warn("module loaded by force\n"); |
| 246 | /* first ensure that we are running on IBM HW */ | 246 | /* first ensure that we are running on IBM HW */ |
| 247 | else if (efi_enabled || !dmi_check_system(ibm_rtl_dmi_table)) | 247 | else if (efi_enabled(EFI_BOOT) || !dmi_check_system(ibm_rtl_dmi_table)) |
| 248 | return -ENODEV; | 248 | return -ENODEV; |
| 249 | 249 | ||
| 250 | /* Get the address for the Extended BIOS Data Area */ | 250 | /* Get the address for the Extended BIOS Data Area */ |
diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index dd90d15f5210..d1f030053176 100644 --- a/drivers/platform/x86/samsung-laptop.c +++ b/drivers/platform/x86/samsung-laptop.c | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | #include <linux/seq_file.h> | 26 | #include <linux/seq_file.h> |
| 27 | #include <linux/debugfs.h> | 27 | #include <linux/debugfs.h> |
| 28 | #include <linux/ctype.h> | 28 | #include <linux/ctype.h> |
| 29 | #include <linux/efi.h> | ||
| 29 | #include <acpi/video.h> | 30 | #include <acpi/video.h> |
| 30 | 31 | ||
| 31 | /* | 32 | /* |
| @@ -1523,6 +1524,16 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = { | |||
| 1523 | }, | 1524 | }, |
| 1524 | .driver_data = &samsung_broken_acpi_video, | 1525 | .driver_data = &samsung_broken_acpi_video, |
| 1525 | }, | 1526 | }, |
| 1527 | { | ||
| 1528 | .callback = samsung_dmi_matched, | ||
| 1529 | .ident = "N250P", | ||
| 1530 | .matches = { | ||
| 1531 | DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), | ||
| 1532 | DMI_MATCH(DMI_PRODUCT_NAME, "N250P"), | ||
| 1533 | DMI_MATCH(DMI_BOARD_NAME, "N250P"), | ||
| 1534 | }, | ||
| 1535 | .driver_data = &samsung_broken_acpi_video, | ||
| 1536 | }, | ||
| 1526 | { }, | 1537 | { }, |
| 1527 | }; | 1538 | }; |
| 1528 | MODULE_DEVICE_TABLE(dmi, samsung_dmi_table); | 1539 | MODULE_DEVICE_TABLE(dmi, samsung_dmi_table); |
| @@ -1534,6 +1545,9 @@ static int __init samsung_init(void) | |||
| 1534 | struct samsung_laptop *samsung; | 1545 | struct samsung_laptop *samsung; |
| 1535 | int ret; | 1546 | int ret; |
| 1536 | 1547 | ||
| 1548 | if (efi_enabled(EFI_BOOT)) | ||
| 1549 | return -ENODEV; | ||
| 1550 | |||
| 1537 | quirks = &samsung_unknown; | 1551 | quirks = &samsung_unknown; |
| 1538 | if (!force && !dmi_check_system(samsung_dmi_table)) | 1552 | if (!force && !dmi_check_system(samsung_dmi_table)) |
| 1539 | return -ENODEV; | 1553 | return -ENODEV; |
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/dbx500-prcmu.c b/drivers/regulator/dbx500-prcmu.c index 261f3d2299bc..89bd2faaef8c 100644 --- a/drivers/regulator/dbx500-prcmu.c +++ b/drivers/regulator/dbx500-prcmu.c | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include <linux/debugfs.h> | 14 | #include <linux/debugfs.h> |
| 15 | #include <linux/seq_file.h> | 15 | #include <linux/seq_file.h> |
| 16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
| 17 | #include <linux/module.h> | ||
| 17 | 18 | ||
| 18 | #include "dbx500-prcmu.h" | 19 | #include "dbx500-prcmu.h" |
| 19 | 20 | ||
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/regulator/tps80031-regulator.c b/drivers/regulator/tps80031-regulator.c index b15d711bc8c6..9019d0e7ecb6 100644 --- a/drivers/regulator/tps80031-regulator.c +++ b/drivers/regulator/tps80031-regulator.c | |||
| @@ -728,7 +728,7 @@ static int tps80031_regulator_probe(struct platform_device *pdev) | |||
| 728 | } | 728 | } |
| 729 | } | 729 | } |
| 730 | rdev = regulator_register(&ri->rinfo->desc, &config); | 730 | rdev = regulator_register(&ri->rinfo->desc, &config); |
| 731 | if (IS_ERR_OR_NULL(rdev)) { | 731 | if (IS_ERR(rdev)) { |
| 732 | dev_err(&pdev->dev, | 732 | dev_err(&pdev->dev, |
| 733 | "register regulator failed %s\n", | 733 | "register regulator failed %s\n", |
| 734 | ri->rinfo->desc.name); | 734 | ri->rinfo->desc.name); |
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 923a9da9c829..20354b43932e 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig | |||
| @@ -1023,7 +1023,7 @@ config RTC_DRV_TX4939 | |||
| 1023 | 1023 | ||
| 1024 | config RTC_DRV_MV | 1024 | config RTC_DRV_MV |
| 1025 | tristate "Marvell SoC RTC" | 1025 | tristate "Marvell SoC RTC" |
| 1026 | depends on ARCH_KIRKWOOD || ARCH_DOVE | 1026 | depends on ARCH_KIRKWOOD || ARCH_DOVE || ARCH_MVEBU |
| 1027 | help | 1027 | help |
| 1028 | If you say yes here you will get support for the in-chip RTC | 1028 | If you say yes here you will get support for the in-chip RTC |
| 1029 | that can be found in some of Marvell's SoC devices, such as | 1029 | that can be found in some of Marvell's SoC devices, such as |
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/scsi/isci/init.c b/drivers/scsi/isci/init.c index d73fdcfeb45a..2839baa82a5a 100644 --- a/drivers/scsi/isci/init.c +++ b/drivers/scsi/isci/init.c | |||
| @@ -633,7 +633,7 @@ static int isci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 633 | return -ENOMEM; | 633 | return -ENOMEM; |
| 634 | pci_set_drvdata(pdev, pci_info); | 634 | pci_set_drvdata(pdev, pci_info); |
| 635 | 635 | ||
| 636 | if (efi_enabled) | 636 | if (efi_enabled(EFI_RUNTIME_SERVICES)) |
| 637 | orom = isci_get_efi_var(pdev); | 637 | orom = isci_get_efi_var(pdev); |
| 638 | 638 | ||
| 639 | if (!orom) | 639 | if (!orom) |
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/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c index 448a8cc71df3..e5dce91b74ca 100644 --- a/drivers/spi/spi-tegra20-sflash.c +++ b/drivers/spi/spi-tegra20-sflash.c | |||
| @@ -34,7 +34,7 @@ | |||
| 34 | #include <linux/of_device.h> | 34 | #include <linux/of_device.h> |
| 35 | #include <linux/spi/spi.h> | 35 | #include <linux/spi/spi.h> |
| 36 | #include <linux/spi/spi-tegra.h> | 36 | #include <linux/spi/spi-tegra.h> |
| 37 | #include <mach/clk.h> | 37 | #include <linux/clk/tegra.h> |
| 38 | 38 | ||
| 39 | #define SPI_COMMAND 0x000 | 39 | #define SPI_COMMAND 0x000 |
| 40 | #define SPI_GO BIT(30) | 40 | #define SPI_GO BIT(30) |
| @@ -525,7 +525,7 @@ static int tegra_sflash_probe(struct platform_device *pdev) | |||
| 525 | goto exit_free_master; | 525 | goto exit_free_master; |
| 526 | } | 526 | } |
| 527 | 527 | ||
| 528 | tsd->clk = devm_clk_get(&pdev->dev, "spi"); | 528 | tsd->clk = devm_clk_get(&pdev->dev, NULL); |
| 529 | if (IS_ERR(tsd->clk)) { | 529 | if (IS_ERR(tsd->clk)) { |
| 530 | dev_err(&pdev->dev, "can not get clock\n"); | 530 | dev_err(&pdev->dev, "can not get clock\n"); |
| 531 | ret = PTR_ERR(tsd->clk); | 531 | ret = PTR_ERR(tsd->clk); |
diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c index 651167f2e0af..e255e7a35678 100644 --- a/drivers/spi/spi-tegra20-slink.c +++ b/drivers/spi/spi-tegra20-slink.c | |||
| @@ -35,7 +35,7 @@ | |||
| 35 | #include <linux/of_device.h> | 35 | #include <linux/of_device.h> |
| 36 | #include <linux/spi/spi.h> | 36 | #include <linux/spi/spi.h> |
| 37 | #include <linux/spi/spi-tegra.h> | 37 | #include <linux/spi/spi-tegra.h> |
| 38 | #include <mach/clk.h> | 38 | #include <linux/clk/tegra.h> |
| 39 | 39 | ||
| 40 | #define SLINK_COMMAND 0x000 | 40 | #define SLINK_COMMAND 0x000 |
| 41 | #define SLINK_BIT_LENGTH(x) (((x) & 0x1f) << 0) | 41 | #define SLINK_BIT_LENGTH(x) (((x) & 0x1f) << 0) |
| @@ -1191,7 +1191,7 @@ static int tegra_slink_probe(struct platform_device *pdev) | |||
| 1191 | goto exit_free_master; | 1191 | goto exit_free_master; |
| 1192 | } | 1192 | } |
| 1193 | 1193 | ||
| 1194 | tspi->clk = devm_clk_get(&pdev->dev, "slink"); | 1194 | tspi->clk = devm_clk_get(&pdev->dev, NULL); |
| 1195 | if (IS_ERR(tspi->clk)) { | 1195 | if (IS_ERR(tspi->clk)) { |
| 1196 | dev_err(&pdev->dev, "can not get clock\n"); | 1196 | dev_err(&pdev->dev, "can not get clock\n"); |
| 1197 | ret = PTR_ERR(tspi->clk); | 1197 | ret = PTR_ERR(tspi->clk); |
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/nvec/TODO b/drivers/staging/nvec/TODO index f950ab890e2e..e5ae42a0b44a 100644 --- a/drivers/staging/nvec/TODO +++ b/drivers/staging/nvec/TODO | |||
| @@ -1,9 +1,5 @@ | |||
| 1 | ToDo list (incomplete, unordered) | 1 | ToDo list (incomplete, unordered) |
| 2 | - add compile as module support | 2 | - add compile as module support |
| 3 | - fix clk usage | ||
| 4 | should not be using clk_get_sys(), but clk_get(&pdev->dev, conn) | ||
| 5 | where conn is either NULL if the device only has one clock, or | ||
| 6 | the device specific name if it has multiple clocks. | ||
| 7 | - move half of the nvec init stuff to i2c-tegra.c | 3 | - move half of the nvec init stuff to i2c-tegra.c |
| 8 | - move event handling to nvec_events | 4 | - move event handling to nvec_events |
| 9 | - finish suspend/resume support | 5 | - finish suspend/resume support |
diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c index 2830946860d1..9417941974f7 100644 --- a/drivers/staging/nvec/nvec.c +++ b/drivers/staging/nvec/nvec.c | |||
| @@ -37,8 +37,7 @@ | |||
| 37 | #include <linux/slab.h> | 37 | #include <linux/slab.h> |
| 38 | #include <linux/spinlock.h> | 38 | #include <linux/spinlock.h> |
| 39 | #include <linux/workqueue.h> | 39 | #include <linux/workqueue.h> |
| 40 | 40 | #include <linux/clk/tegra.h> | |
| 41 | #include <mach/clk.h> | ||
| 42 | 41 | ||
| 43 | #include "nvec.h" | 42 | #include "nvec.h" |
| 44 | 43 | ||
| @@ -771,7 +770,7 @@ static int tegra_nvec_probe(struct platform_device *pdev) | |||
| 771 | return -ENODEV; | 770 | return -ENODEV; |
| 772 | } | 771 | } |
| 773 | 772 | ||
| 774 | i2c_clk = clk_get_sys("tegra-i2c.2", "div-clk"); | 773 | i2c_clk = clk_get(&pdev->dev, "div-clk"); |
| 775 | if (IS_ERR(i2c_clk)) { | 774 | if (IS_ERR(i2c_clk)) { |
| 776 | dev_err(nvec->dev, "failed to get controller clock\n"); | 775 | dev_err(nvec->dev, "failed to get controller clock\n"); |
| 777 | return -ENODEV; | 776 | return -ENODEV; |
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-tegra.c b/drivers/usb/host/ehci-tegra.c index acf17556bd87..568aecc7075b 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | * EHCI-compliant USB host controller driver for NVIDIA Tegra SoCs | 2 | * EHCI-compliant USB host controller driver for NVIDIA Tegra SoCs |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2010 Google, Inc. | 4 | * Copyright (C) 2010 Google, Inc. |
| 5 | * Copyright (C) 2009 NVIDIA Corporation | 5 | * Copyright (C) 2009 - 2013 NVIDIA Corporation |
| 6 | * | 6 | * |
| 7 | * This program is free software; you can redistribute it and/or modify it | 7 | * This program is free software; you can redistribute it and/or modify it |
| 8 | * under the terms of the GNU General Public License as published by the | 8 | * under the terms of the GNU General Public License as published by the |
| @@ -26,23 +26,28 @@ | |||
| 26 | #include <linux/of.h> | 26 | #include <linux/of.h> |
| 27 | #include <linux/of_gpio.h> | 27 | #include <linux/of_gpio.h> |
| 28 | #include <linux/pm_runtime.h> | 28 | #include <linux/pm_runtime.h> |
| 29 | 29 | #include <linux/usb/ehci_def.h> | |
| 30 | #include <linux/usb/tegra_usb_phy.h> | 30 | #include <linux/usb/tegra_usb_phy.h> |
| 31 | 31 | ||
| 32 | #define TEGRA_USB_BASE 0xC5000000 | 32 | #define TEGRA_USB_BASE 0xC5000000 |
| 33 | #define TEGRA_USB2_BASE 0xC5004000 | 33 | #define TEGRA_USB2_BASE 0xC5004000 |
| 34 | #define TEGRA_USB3_BASE 0xC5008000 | 34 | #define TEGRA_USB3_BASE 0xC5008000 |
| 35 | 35 | ||
| 36 | /* PORTSC registers */ | ||
| 37 | #define TEGRA_USB_PORTSC1 0x184 | ||
| 38 | #define TEGRA_USB_PORTSC1_PTS(x) (((x) & 0x3) << 30) | ||
| 39 | #define TEGRA_USB_PORTSC1_PHCD (1 << 23) | ||
| 40 | |||
| 36 | #define TEGRA_USB_DMA_ALIGN 32 | 41 | #define TEGRA_USB_DMA_ALIGN 32 |
| 37 | 42 | ||
| 38 | struct tegra_ehci_hcd { | 43 | struct tegra_ehci_hcd { |
| 39 | struct ehci_hcd *ehci; | 44 | struct ehci_hcd *ehci; |
| 40 | struct tegra_usb_phy *phy; | 45 | struct tegra_usb_phy *phy; |
| 41 | struct clk *clk; | 46 | struct clk *clk; |
| 42 | struct clk *emc_clk; | ||
| 43 | struct usb_phy *transceiver; | 47 | struct usb_phy *transceiver; |
| 44 | int host_resumed; | 48 | int host_resumed; |
| 45 | int port_resuming; | 49 | int port_resuming; |
| 50 | bool needs_double_reset; | ||
| 46 | enum tegra_usb_phy_port_speed port_speed; | 51 | enum tegra_usb_phy_port_speed port_speed; |
| 47 | }; | 52 | }; |
| 48 | 53 | ||
| @@ -50,9 +55,8 @@ static void tegra_ehci_power_up(struct usb_hcd *hcd) | |||
| 50 | { | 55 | { |
| 51 | struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); | 56 | struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); |
| 52 | 57 | ||
| 53 | clk_prepare_enable(tegra->emc_clk); | ||
| 54 | clk_prepare_enable(tegra->clk); | 58 | clk_prepare_enable(tegra->clk); |
| 55 | usb_phy_set_suspend(&tegra->phy->u_phy, 0); | 59 | usb_phy_set_suspend(hcd->phy, 0); |
| 56 | tegra->host_resumed = 1; | 60 | tegra->host_resumed = 1; |
| 57 | } | 61 | } |
| 58 | 62 | ||
| @@ -61,9 +65,8 @@ static void tegra_ehci_power_down(struct usb_hcd *hcd) | |||
| 61 | struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); | 65 | struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); |
| 62 | 66 | ||
| 63 | tegra->host_resumed = 0; | 67 | tegra->host_resumed = 0; |
| 64 | usb_phy_set_suspend(&tegra->phy->u_phy, 1); | 68 | usb_phy_set_suspend(hcd->phy, 1); |
| 65 | clk_disable_unprepare(tegra->clk); | 69 | clk_disable_unprepare(tegra->clk); |
| 66 | clk_disable_unprepare(tegra->emc_clk); | ||
| 67 | } | 70 | } |
| 68 | 71 | ||
| 69 | static int tegra_ehci_internal_port_reset( | 72 | static int tegra_ehci_internal_port_reset( |
| @@ -156,7 +159,7 @@ static int tegra_ehci_hub_control( | |||
| 156 | if (tegra->port_resuming && !(temp & PORT_SUSPEND)) { | 159 | if (tegra->port_resuming && !(temp & PORT_SUSPEND)) { |
| 157 | /* Resume completed, re-enable disconnect detection */ | 160 | /* Resume completed, re-enable disconnect detection */ |
| 158 | tegra->port_resuming = 0; | 161 | tegra->port_resuming = 0; |
| 159 | tegra_usb_phy_postresume(tegra->phy); | 162 | tegra_usb_phy_postresume(hcd->phy); |
| 160 | } | 163 | } |
| 161 | } | 164 | } |
| 162 | 165 | ||
| @@ -184,7 +187,7 @@ static int tegra_ehci_hub_control( | |||
| 184 | } | 187 | } |
| 185 | 188 | ||
| 186 | /* For USB1 port we need to issue Port Reset twice internally */ | 189 | /* For USB1 port we need to issue Port Reset twice internally */ |
| 187 | if (tegra->phy->instance == 0 && | 190 | if (tegra->needs_double_reset && |
| 188 | (typeReq == SetPortFeature && wValue == USB_PORT_FEAT_RESET)) { | 191 | (typeReq == SetPortFeature && wValue == USB_PORT_FEAT_RESET)) { |
| 189 | spin_unlock_irqrestore(&ehci->lock, flags); | 192 | spin_unlock_irqrestore(&ehci->lock, flags); |
| 190 | return tegra_ehci_internal_port_reset(ehci, status_reg); | 193 | return tegra_ehci_internal_port_reset(ehci, status_reg); |
| @@ -209,7 +212,7 @@ static int tegra_ehci_hub_control( | |||
| 209 | goto done; | 212 | goto done; |
| 210 | 213 | ||
| 211 | /* Disable disconnect detection during port resume */ | 214 | /* Disable disconnect detection during port resume */ |
| 212 | tegra_usb_phy_preresume(tegra->phy); | 215 | tegra_usb_phy_preresume(hcd->phy); |
| 213 | 216 | ||
| 214 | ehci->reset_done[wIndex-1] = jiffies + msecs_to_jiffies(25); | 217 | ehci->reset_done[wIndex-1] = jiffies + msecs_to_jiffies(25); |
| 215 | 218 | ||
| @@ -473,7 +476,7 @@ static int controller_resume(struct device *dev) | |||
| 473 | } | 476 | } |
| 474 | 477 | ||
| 475 | /* Force the phy to keep data lines in suspend state */ | 478 | /* Force the phy to keep data lines in suspend state */ |
| 476 | tegra_ehci_phy_restore_start(tegra->phy, tegra->port_speed); | 479 | tegra_ehci_phy_restore_start(hcd->phy, tegra->port_speed); |
| 477 | 480 | ||
| 478 | /* Enable host mode */ | 481 | /* Enable host mode */ |
| 479 | tdi_reset(ehci); | 482 | tdi_reset(ehci); |
| @@ -540,17 +543,17 @@ static int controller_resume(struct device *dev) | |||
| 540 | } | 543 | } |
| 541 | } | 544 | } |
| 542 | 545 | ||
| 543 | tegra_ehci_phy_restore_end(tegra->phy); | 546 | tegra_ehci_phy_restore_end(hcd->phy); |
| 544 | goto done; | 547 | goto done; |
| 545 | 548 | ||
| 546 | restart: | 549 | restart: |
| 547 | if (tegra->port_speed <= TEGRA_USB_PHY_PORT_SPEED_HIGH) | 550 | if (tegra->port_speed <= TEGRA_USB_PHY_PORT_SPEED_HIGH) |
| 548 | tegra_ehci_phy_restore_end(tegra->phy); | 551 | tegra_ehci_phy_restore_end(hcd->phy); |
| 549 | 552 | ||
| 550 | tegra_ehci_restart(hcd); | 553 | tegra_ehci_restart(hcd); |
| 551 | 554 | ||
| 552 | done: | 555 | done: |
| 553 | tegra_usb_phy_preresume(tegra->phy); | 556 | tegra_usb_phy_preresume(hcd->phy); |
| 554 | tegra->port_resuming = 1; | 557 | tegra->port_resuming = 1; |
| 555 | return 0; | 558 | return 0; |
| 556 | } | 559 | } |
| @@ -604,6 +607,37 @@ static const struct dev_pm_ops tegra_ehci_pm_ops = { | |||
| 604 | 607 | ||
| 605 | #endif | 608 | #endif |
| 606 | 609 | ||
| 610 | /* Bits of PORTSC1, which will get cleared by writing 1 into them */ | ||
| 611 | #define TEGRA_PORTSC1_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC) | ||
| 612 | |||
| 613 | void tegra_ehci_set_pts(struct usb_phy *x, u8 pts_val) | ||
| 614 | { | ||
| 615 | unsigned long val; | ||
| 616 | struct usb_hcd *hcd = bus_to_hcd(x->otg->host); | ||
| 617 | void __iomem *base = hcd->regs; | ||
| 618 | |||
| 619 | val = readl(base + TEGRA_USB_PORTSC1) & ~TEGRA_PORTSC1_RWC_BITS; | ||
| 620 | val &= ~TEGRA_USB_PORTSC1_PTS(3); | ||
| 621 | val |= TEGRA_USB_PORTSC1_PTS(pts_val & 3); | ||
| 622 | writel(val, base + TEGRA_USB_PORTSC1); | ||
| 623 | } | ||
| 624 | EXPORT_SYMBOL_GPL(tegra_ehci_set_pts); | ||
| 625 | |||
| 626 | void tegra_ehci_set_phcd(struct usb_phy *x, bool enable) | ||
| 627 | { | ||
| 628 | unsigned long val; | ||
| 629 | struct usb_hcd *hcd = bus_to_hcd(x->otg->host); | ||
| 630 | void __iomem *base = hcd->regs; | ||
| 631 | |||
| 632 | val = readl(base + TEGRA_USB_PORTSC1) & ~TEGRA_PORTSC1_RWC_BITS; | ||
| 633 | if (enable) | ||
| 634 | val |= TEGRA_USB_PORTSC1_PHCD; | ||
| 635 | else | ||
| 636 | val &= ~TEGRA_USB_PORTSC1_PHCD; | ||
| 637 | writel(val, base + TEGRA_USB_PORTSC1); | ||
| 638 | } | ||
| 639 | EXPORT_SYMBOL_GPL(tegra_ehci_set_phcd); | ||
| 640 | |||
| 607 | static u64 tegra_ehci_dma_mask = DMA_BIT_MASK(32); | 641 | static u64 tegra_ehci_dma_mask = DMA_BIT_MASK(32); |
| 608 | 642 | ||
| 609 | static int tegra_ehci_probe(struct platform_device *pdev) | 643 | static int tegra_ehci_probe(struct platform_device *pdev) |
| @@ -615,6 +649,7 @@ static int tegra_ehci_probe(struct platform_device *pdev) | |||
| 615 | int err = 0; | 649 | int err = 0; |
| 616 | int irq; | 650 | int irq; |
| 617 | int instance = pdev->id; | 651 | int instance = pdev->id; |
| 652 | struct usb_phy *u_phy; | ||
| 618 | 653 | ||
| 619 | pdata = pdev->dev.platform_data; | 654 | pdata = pdev->dev.platform_data; |
| 620 | if (!pdata) { | 655 | if (!pdata) { |
| @@ -656,15 +691,8 @@ static int tegra_ehci_probe(struct platform_device *pdev) | |||
| 656 | if (err) | 691 | if (err) |
| 657 | goto fail_clk; | 692 | goto fail_clk; |
| 658 | 693 | ||
| 659 | tegra->emc_clk = devm_clk_get(&pdev->dev, "emc"); | 694 | tegra->needs_double_reset = of_property_read_bool(pdev->dev.of_node, |
| 660 | if (IS_ERR(tegra->emc_clk)) { | 695 | "nvidia,needs-double-reset"); |
| 661 | dev_err(&pdev->dev, "Can't get emc clock\n"); | ||
| 662 | err = PTR_ERR(tegra->emc_clk); | ||
| 663 | goto fail_emc_clk; | ||
| 664 | } | ||
| 665 | |||
| 666 | clk_prepare_enable(tegra->emc_clk); | ||
| 667 | clk_set_rate(tegra->emc_clk, 400000000); | ||
| 668 | 696 | ||
| 669 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 697 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 670 | if (!res) { | 698 | if (!res) { |
| @@ -712,9 +740,19 @@ static int tegra_ehci_probe(struct platform_device *pdev) | |||
| 712 | goto fail_io; | 740 | goto fail_io; |
| 713 | } | 741 | } |
| 714 | 742 | ||
| 715 | usb_phy_init(&tegra->phy->u_phy); | 743 | hcd->phy = u_phy = &tegra->phy->u_phy; |
| 744 | usb_phy_init(hcd->phy); | ||
| 745 | |||
| 746 | u_phy->otg = devm_kzalloc(&pdev->dev, sizeof(struct usb_otg), | ||
| 747 | GFP_KERNEL); | ||
| 748 | if (!u_phy->otg) { | ||
| 749 | dev_err(&pdev->dev, "Failed to alloc memory for otg\n"); | ||
| 750 | err = -ENOMEM; | ||
| 751 | goto fail_io; | ||
| 752 | } | ||
| 753 | u_phy->otg->host = hcd_to_bus(hcd); | ||
| 716 | 754 | ||
| 717 | err = usb_phy_set_suspend(&tegra->phy->u_phy, 0); | 755 | err = usb_phy_set_suspend(hcd->phy, 0); |
| 718 | if (err) { | 756 | if (err) { |
| 719 | dev_err(&pdev->dev, "Failed to power on the phy\n"); | 757 | dev_err(&pdev->dev, "Failed to power on the phy\n"); |
| 720 | goto fail; | 758 | goto fail; |
| @@ -760,10 +798,8 @@ fail: | |||
| 760 | if (!IS_ERR_OR_NULL(tegra->transceiver)) | 798 | if (!IS_ERR_OR_NULL(tegra->transceiver)) |
| 761 | otg_set_host(tegra->transceiver->otg, NULL); | 799 | otg_set_host(tegra->transceiver->otg, NULL); |
| 762 | #endif | 800 | #endif |
| 763 | usb_phy_shutdown(&tegra->phy->u_phy); | 801 | usb_phy_shutdown(hcd->phy); |
| 764 | fail_io: | 802 | fail_io: |
| 765 | clk_disable_unprepare(tegra->emc_clk); | ||
| 766 | fail_emc_clk: | ||
| 767 | clk_disable_unprepare(tegra->clk); | 803 | clk_disable_unprepare(tegra->clk); |
| 768 | fail_clk: | 804 | fail_clk: |
| 769 | usb_put_hcd(hcd); | 805 | usb_put_hcd(hcd); |
| @@ -784,15 +820,12 @@ static int tegra_ehci_remove(struct platform_device *pdev) | |||
| 784 | otg_set_host(tegra->transceiver->otg, NULL); | 820 | otg_set_host(tegra->transceiver->otg, NULL); |
| 785 | #endif | 821 | #endif |
| 786 | 822 | ||
| 823 | usb_phy_shutdown(hcd->phy); | ||
| 787 | usb_remove_hcd(hcd); | 824 | usb_remove_hcd(hcd); |
| 788 | usb_put_hcd(hcd); | 825 | usb_put_hcd(hcd); |
| 789 | 826 | ||
| 790 | usb_phy_shutdown(&tegra->phy->u_phy); | ||
| 791 | |||
| 792 | clk_disable_unprepare(tegra->clk); | 827 | clk_disable_unprepare(tegra->clk); |
| 793 | 828 | ||
| 794 | clk_disable_unprepare(tegra->emc_clk); | ||
| 795 | |||
| 796 | return 0; | 829 | return 0; |
| 797 | } | 830 | } |
| 798 | 831 | ||
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/phy/tegra_usb_phy.c b/drivers/usb/phy/tegra_usb_phy.c index 9d13c81754e0..5487d38481af 100644 --- a/drivers/usb/phy/tegra_usb_phy.c +++ b/drivers/usb/phy/tegra_usb_phy.c | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #include <linux/platform_device.h> | 24 | #include <linux/platform_device.h> |
| 25 | #include <linux/io.h> | 25 | #include <linux/io.h> |
| 26 | #include <linux/gpio.h> | 26 | #include <linux/gpio.h> |
| 27 | #include <linux/of.h> | ||
| 27 | #include <linux/of_gpio.h> | 28 | #include <linux/of_gpio.h> |
| 28 | #include <linux/usb/otg.h> | 29 | #include <linux/usb/otg.h> |
| 29 | #include <linux/usb/ulpi.h> | 30 | #include <linux/usb/ulpi.h> |
| @@ -35,19 +36,6 @@ | |||
| 35 | 36 | ||
| 36 | #define ULPI_VIEWPORT 0x170 | 37 | #define ULPI_VIEWPORT 0x170 |
| 37 | 38 | ||
| 38 | #define USB_PORTSC1 0x184 | ||
| 39 | #define USB_PORTSC1_PTS(x) (((x) & 0x3) << 30) | ||
| 40 | #define USB_PORTSC1_PSPD(x) (((x) & 0x3) << 26) | ||
| 41 | #define USB_PORTSC1_PHCD (1 << 23) | ||
| 42 | #define USB_PORTSC1_WKOC (1 << 22) | ||
| 43 | #define USB_PORTSC1_WKDS (1 << 21) | ||
| 44 | #define USB_PORTSC1_WKCN (1 << 20) | ||
| 45 | #define USB_PORTSC1_PTC(x) (((x) & 0xf) << 16) | ||
| 46 | #define USB_PORTSC1_PP (1 << 12) | ||
| 47 | #define USB_PORTSC1_SUSP (1 << 7) | ||
| 48 | #define USB_PORTSC1_PE (1 << 2) | ||
| 49 | #define USB_PORTSC1_CCS (1 << 0) | ||
| 50 | |||
| 51 | #define USB_SUSP_CTRL 0x400 | 39 | #define USB_SUSP_CTRL 0x400 |
| 52 | #define USB_WAKE_ON_CNNT_EN_DEV (1 << 3) | 40 | #define USB_WAKE_ON_CNNT_EN_DEV (1 << 3) |
| 53 | #define USB_WAKE_ON_DISCON_EN_DEV (1 << 4) | 41 | #define USB_WAKE_ON_DISCON_EN_DEV (1 << 4) |
| @@ -208,11 +196,6 @@ static struct tegra_utmip_config utmip_default[] = { | |||
| 208 | }, | 196 | }, |
| 209 | }; | 197 | }; |
| 210 | 198 | ||
| 211 | static inline bool phy_is_ulpi(struct tegra_usb_phy *phy) | ||
| 212 | { | ||
| 213 | return (phy->instance == 1); | ||
| 214 | } | ||
| 215 | |||
| 216 | static int utmip_pad_open(struct tegra_usb_phy *phy) | 199 | static int utmip_pad_open(struct tegra_usb_phy *phy) |
| 217 | { | 200 | { |
| 218 | phy->pad_clk = clk_get_sys("utmip-pad", NULL); | 201 | phy->pad_clk = clk_get_sys("utmip-pad", NULL); |
| @@ -221,7 +204,7 @@ static int utmip_pad_open(struct tegra_usb_phy *phy) | |||
| 221 | return PTR_ERR(phy->pad_clk); | 204 | return PTR_ERR(phy->pad_clk); |
| 222 | } | 205 | } |
| 223 | 206 | ||
| 224 | if (phy->instance == 0) { | 207 | if (phy->is_legacy_phy) { |
| 225 | phy->pad_regs = phy->regs; | 208 | phy->pad_regs = phy->regs; |
| 226 | } else { | 209 | } else { |
| 227 | phy->pad_regs = ioremap(TEGRA_USB_BASE, TEGRA_USB_SIZE); | 210 | phy->pad_regs = ioremap(TEGRA_USB_BASE, TEGRA_USB_SIZE); |
| @@ -236,7 +219,7 @@ static int utmip_pad_open(struct tegra_usb_phy *phy) | |||
| 236 | 219 | ||
| 237 | static void utmip_pad_close(struct tegra_usb_phy *phy) | 220 | static void utmip_pad_close(struct tegra_usb_phy *phy) |
| 238 | { | 221 | { |
| 239 | if (phy->instance != 0) | 222 | if (!phy->is_legacy_phy) |
| 240 | iounmap(phy->pad_regs); | 223 | iounmap(phy->pad_regs); |
| 241 | clk_put(phy->pad_clk); | 224 | clk_put(phy->pad_clk); |
| 242 | } | 225 | } |
| @@ -305,7 +288,7 @@ static void utmi_phy_clk_disable(struct tegra_usb_phy *phy) | |||
| 305 | unsigned long val; | 288 | unsigned long val; |
| 306 | void __iomem *base = phy->regs; | 289 | void __iomem *base = phy->regs; |
| 307 | 290 | ||
| 308 | if (phy->instance == 0) { | 291 | if (phy->is_legacy_phy) { |
| 309 | val = readl(base + USB_SUSP_CTRL); | 292 | val = readl(base + USB_SUSP_CTRL); |
| 310 | val |= USB_SUSP_SET; | 293 | val |= USB_SUSP_SET; |
| 311 | writel(val, base + USB_SUSP_CTRL); | 294 | writel(val, base + USB_SUSP_CTRL); |
| @@ -315,13 +298,8 @@ static void utmi_phy_clk_disable(struct tegra_usb_phy *phy) | |||
| 315 | val = readl(base + USB_SUSP_CTRL); | 298 | val = readl(base + USB_SUSP_CTRL); |
| 316 | val &= ~USB_SUSP_SET; | 299 | val &= ~USB_SUSP_SET; |
| 317 | writel(val, base + USB_SUSP_CTRL); | 300 | writel(val, base + USB_SUSP_CTRL); |
| 318 | } | 301 | } else |
| 319 | 302 | tegra_ehci_set_phcd(&phy->u_phy, true); | |
| 320 | if (phy->instance == 2) { | ||
| 321 | val = readl(base + USB_PORTSC1); | ||
| 322 | val |= USB_PORTSC1_PHCD; | ||
| 323 | writel(val, base + USB_PORTSC1); | ||
| 324 | } | ||
| 325 | 303 | ||
| 326 | if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, 0) < 0) | 304 | if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, 0) < 0) |
| 327 | pr_err("%s: timeout waiting for phy to stabilize\n", __func__); | 305 | pr_err("%s: timeout waiting for phy to stabilize\n", __func__); |
| @@ -332,7 +310,7 @@ static void utmi_phy_clk_enable(struct tegra_usb_phy *phy) | |||
| 332 | unsigned long val; | 310 | unsigned long val; |
| 333 | void __iomem *base = phy->regs; | 311 | void __iomem *base = phy->regs; |
| 334 | 312 | ||
| 335 | if (phy->instance == 0) { | 313 | if (phy->is_legacy_phy) { |
| 336 | val = readl(base + USB_SUSP_CTRL); | 314 | val = readl(base + USB_SUSP_CTRL); |
| 337 | val |= USB_SUSP_CLR; | 315 | val |= USB_SUSP_CLR; |
| 338 | writel(val, base + USB_SUSP_CTRL); | 316 | writel(val, base + USB_SUSP_CTRL); |
| @@ -342,13 +320,8 @@ static void utmi_phy_clk_enable(struct tegra_usb_phy *phy) | |||
| 342 | val = readl(base + USB_SUSP_CTRL); | 320 | val = readl(base + USB_SUSP_CTRL); |
| 343 | val &= ~USB_SUSP_CLR; | 321 | val &= ~USB_SUSP_CLR; |
| 344 | writel(val, base + USB_SUSP_CTRL); | 322 | writel(val, base + USB_SUSP_CTRL); |
| 345 | } | 323 | } else |
| 346 | 324 | tegra_ehci_set_phcd(&phy->u_phy, false); | |
| 347 | if (phy->instance == 2) { | ||
| 348 | val = readl(base + USB_PORTSC1); | ||
| 349 | val &= ~USB_PORTSC1_PHCD; | ||
| 350 | writel(val, base + USB_PORTSC1); | ||
| 351 | } | ||
| 352 | 325 | ||
| 353 | if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, | 326 | if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, |
| 354 | USB_PHY_CLK_VALID)) | 327 | USB_PHY_CLK_VALID)) |
| @@ -365,7 +338,7 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) | |||
| 365 | val |= UTMIP_RESET; | 338 | val |= UTMIP_RESET; |
| 366 | writel(val, base + USB_SUSP_CTRL); | 339 | writel(val, base + USB_SUSP_CTRL); |
| 367 | 340 | ||
| 368 | if (phy->instance == 0) { | 341 | if (phy->is_legacy_phy) { |
| 369 | val = readl(base + USB1_LEGACY_CTRL); | 342 | val = readl(base + USB1_LEGACY_CTRL); |
| 370 | val |= USB1_NO_LEGACY_MODE; | 343 | val |= USB1_NO_LEGACY_MODE; |
| 371 | writel(val, base + USB1_LEGACY_CTRL); | 344 | writel(val, base + USB1_LEGACY_CTRL); |
| @@ -440,16 +413,14 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) | |||
| 440 | val |= UTMIP_BIAS_PDTRK_COUNT(0x5); | 413 | val |= UTMIP_BIAS_PDTRK_COUNT(0x5); |
| 441 | writel(val, base + UTMIP_BIAS_CFG1); | 414 | writel(val, base + UTMIP_BIAS_CFG1); |
| 442 | 415 | ||
| 443 | if (phy->instance == 0) { | 416 | if (phy->is_legacy_phy) { |
| 444 | val = readl(base + UTMIP_SPARE_CFG0); | 417 | val = readl(base + UTMIP_SPARE_CFG0); |
| 445 | if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) | 418 | if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) |
| 446 | val &= ~FUSE_SETUP_SEL; | 419 | val &= ~FUSE_SETUP_SEL; |
| 447 | else | 420 | else |
| 448 | val |= FUSE_SETUP_SEL; | 421 | val |= FUSE_SETUP_SEL; |
| 449 | writel(val, base + UTMIP_SPARE_CFG0); | 422 | writel(val, base + UTMIP_SPARE_CFG0); |
| 450 | } | 423 | } else { |
| 451 | |||
| 452 | if (phy->instance == 2) { | ||
| 453 | val = readl(base + USB_SUSP_CTRL); | 424 | val = readl(base + USB_SUSP_CTRL); |
| 454 | val |= UTMIP_PHY_ENABLE; | 425 | val |= UTMIP_PHY_ENABLE; |
| 455 | writel(val, base + USB_SUSP_CTRL); | 426 | writel(val, base + USB_SUSP_CTRL); |
| @@ -459,7 +430,7 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) | |||
| 459 | val &= ~UTMIP_RESET; | 430 | val &= ~UTMIP_RESET; |
| 460 | writel(val, base + USB_SUSP_CTRL); | 431 | writel(val, base + USB_SUSP_CTRL); |
| 461 | 432 | ||
| 462 | if (phy->instance == 0) { | 433 | if (phy->is_legacy_phy) { |
| 463 | val = readl(base + USB1_LEGACY_CTRL); | 434 | val = readl(base + USB1_LEGACY_CTRL); |
| 464 | val &= ~USB1_VBUS_SENSE_CTL_MASK; | 435 | val &= ~USB1_VBUS_SENSE_CTL_MASK; |
| 465 | val |= USB1_VBUS_SENSE_CTL_A_SESS_VLD; | 436 | val |= USB1_VBUS_SENSE_CTL_A_SESS_VLD; |
| @@ -472,11 +443,8 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) | |||
| 472 | 443 | ||
| 473 | utmi_phy_clk_enable(phy); | 444 | utmi_phy_clk_enable(phy); |
| 474 | 445 | ||
| 475 | if (phy->instance == 2) { | 446 | if (!phy->is_legacy_phy) |
| 476 | val = readl(base + USB_PORTSC1); | 447 | tegra_ehci_set_pts(&phy->u_phy, 0); |
| 477 | val &= ~USB_PORTSC1_PTS(~0); | ||
| 478 | writel(val, base + USB_PORTSC1); | ||
| 479 | } | ||
| 480 | 448 | ||
| 481 | return 0; | 449 | return 0; |
| 482 | } | 450 | } |
| @@ -621,10 +589,6 @@ static int ulpi_phy_power_on(struct tegra_usb_phy *phy) | |||
| 621 | return ret; | 589 | return ret; |
| 622 | } | 590 | } |
| 623 | 591 | ||
| 624 | val = readl(base + USB_PORTSC1); | ||
| 625 | val |= USB_PORTSC1_WKOC | USB_PORTSC1_WKDS | USB_PORTSC1_WKCN; | ||
| 626 | writel(val, base + USB_PORTSC1); | ||
| 627 | |||
| 628 | val = readl(base + USB_SUSP_CTRL); | 592 | val = readl(base + USB_SUSP_CTRL); |
| 629 | val |= USB_SUSP_CLR; | 593 | val |= USB_SUSP_CLR; |
| 630 | writel(val, base + USB_SUSP_CTRL); | 594 | writel(val, base + USB_SUSP_CTRL); |
| @@ -639,17 +603,8 @@ static int ulpi_phy_power_on(struct tegra_usb_phy *phy) | |||
| 639 | 603 | ||
| 640 | static int ulpi_phy_power_off(struct tegra_usb_phy *phy) | 604 | static int ulpi_phy_power_off(struct tegra_usb_phy *phy) |
| 641 | { | 605 | { |
| 642 | unsigned long val; | ||
| 643 | void __iomem *base = phy->regs; | ||
| 644 | struct tegra_ulpi_config *config = phy->config; | 606 | struct tegra_ulpi_config *config = phy->config; |
| 645 | 607 | ||
| 646 | /* Clear WKCN/WKDS/WKOC wake-on events that can cause the USB | ||
| 647 | * Controller to immediately bring the ULPI PHY out of low power | ||
| 648 | */ | ||
| 649 | val = readl(base + USB_PORTSC1); | ||
| 650 | val &= ~(USB_PORTSC1_WKOC | USB_PORTSC1_WKDS | USB_PORTSC1_WKCN); | ||
| 651 | writel(val, base + USB_PORTSC1); | ||
| 652 | |||
| 653 | clk_disable(phy->clk); | 608 | clk_disable(phy->clk); |
| 654 | return gpio_direction_output(config->reset_gpio, 0); | 609 | return gpio_direction_output(config->reset_gpio, 0); |
| 655 | } | 610 | } |
| @@ -660,7 +615,7 @@ static int tegra_phy_init(struct usb_phy *x) | |||
| 660 | struct tegra_ulpi_config *ulpi_config; | 615 | struct tegra_ulpi_config *ulpi_config; |
| 661 | int err; | 616 | int err; |
| 662 | 617 | ||
| 663 | if (phy_is_ulpi(phy)) { | 618 | if (phy->is_ulpi_phy) { |
| 664 | ulpi_config = phy->config; | 619 | ulpi_config = phy->config; |
| 665 | phy->clk = clk_get_sys(NULL, ulpi_config->clk); | 620 | phy->clk = clk_get_sys(NULL, ulpi_config->clk); |
| 666 | if (IS_ERR(phy->clk)) { | 621 | if (IS_ERR(phy->clk)) { |
| @@ -698,7 +653,7 @@ static void tegra_usb_phy_close(struct usb_phy *x) | |||
| 698 | { | 653 | { |
| 699 | struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy); | 654 | struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy); |
| 700 | 655 | ||
| 701 | if (phy_is_ulpi(phy)) | 656 | if (phy->is_ulpi_phy) |
| 702 | clk_put(phy->clk); | 657 | clk_put(phy->clk); |
| 703 | else | 658 | else |
| 704 | utmip_pad_close(phy); | 659 | utmip_pad_close(phy); |
| @@ -709,7 +664,7 @@ static void tegra_usb_phy_close(struct usb_phy *x) | |||
| 709 | 664 | ||
| 710 | static int tegra_usb_phy_power_on(struct tegra_usb_phy *phy) | 665 | static int tegra_usb_phy_power_on(struct tegra_usb_phy *phy) |
| 711 | { | 666 | { |
| 712 | if (phy_is_ulpi(phy)) | 667 | if (phy->is_ulpi_phy) |
| 713 | return ulpi_phy_power_on(phy); | 668 | return ulpi_phy_power_on(phy); |
| 714 | else | 669 | else |
| 715 | return utmi_phy_power_on(phy); | 670 | return utmi_phy_power_on(phy); |
| @@ -717,7 +672,7 @@ static int tegra_usb_phy_power_on(struct tegra_usb_phy *phy) | |||
| 717 | 672 | ||
| 718 | static int tegra_usb_phy_power_off(struct tegra_usb_phy *phy) | 673 | static int tegra_usb_phy_power_off(struct tegra_usb_phy *phy) |
| 719 | { | 674 | { |
| 720 | if (phy_is_ulpi(phy)) | 675 | if (phy->is_ulpi_phy) |
| 721 | return ulpi_phy_power_off(phy); | 676 | return ulpi_phy_power_off(phy); |
| 722 | else | 677 | else |
| 723 | return utmi_phy_power_off(phy); | 678 | return utmi_phy_power_off(phy); |
| @@ -739,8 +694,9 @@ struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance, | |||
| 739 | unsigned long parent_rate; | 694 | unsigned long parent_rate; |
| 740 | int i; | 695 | int i; |
| 741 | int err; | 696 | int err; |
| 697 | struct device_node *np = dev->of_node; | ||
| 742 | 698 | ||
| 743 | phy = kmalloc(sizeof(struct tegra_usb_phy), GFP_KERNEL); | 699 | phy = kzalloc(sizeof(struct tegra_usb_phy), GFP_KERNEL); |
| 744 | if (!phy) | 700 | if (!phy) |
| 745 | return ERR_PTR(-ENOMEM); | 701 | return ERR_PTR(-ENOMEM); |
| 746 | 702 | ||
| @@ -749,9 +705,16 @@ struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance, | |||
| 749 | phy->config = config; | 705 | phy->config = config; |
| 750 | phy->mode = phy_mode; | 706 | phy->mode = phy_mode; |
| 751 | phy->dev = dev; | 707 | phy->dev = dev; |
| 708 | phy->is_legacy_phy = | ||
| 709 | of_property_read_bool(np, "nvidia,has-legacy-mode"); | ||
| 710 | err = of_property_match_string(np, "phy_type", "ulpi"); | ||
| 711 | if (err < 0) | ||
| 712 | phy->is_ulpi_phy = false; | ||
| 713 | else | ||
| 714 | phy->is_ulpi_phy = true; | ||
| 752 | 715 | ||
| 753 | if (!phy->config) { | 716 | if (!phy->config) { |
| 754 | if (phy_is_ulpi(phy)) { | 717 | if (phy->is_ulpi_phy) { |
| 755 | pr_err("%s: ulpi phy configuration missing", __func__); | 718 | pr_err("%s: ulpi phy configuration missing", __func__); |
| 756 | err = -EINVAL; | 719 | err = -EINVAL; |
| 757 | goto err0; | 720 | goto err0; |
| @@ -796,45 +759,40 @@ err0: | |||
| 796 | } | 759 | } |
| 797 | EXPORT_SYMBOL_GPL(tegra_usb_phy_open); | 760 | EXPORT_SYMBOL_GPL(tegra_usb_phy_open); |
| 798 | 761 | ||
| 799 | void tegra_usb_phy_preresume(struct tegra_usb_phy *phy) | 762 | void tegra_usb_phy_preresume(struct usb_phy *x) |
| 800 | { | 763 | { |
| 801 | if (!phy_is_ulpi(phy)) | 764 | struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy); |
| 765 | |||
| 766 | if (!phy->is_ulpi_phy) | ||
| 802 | utmi_phy_preresume(phy); | 767 | utmi_phy_preresume(phy); |
| 803 | } | 768 | } |
| 804 | EXPORT_SYMBOL_GPL(tegra_usb_phy_preresume); | 769 | EXPORT_SYMBOL_GPL(tegra_usb_phy_preresume); |
| 805 | 770 | ||
| 806 | void tegra_usb_phy_postresume(struct tegra_usb_phy *phy) | 771 | void tegra_usb_phy_postresume(struct usb_phy *x) |
| 807 | { | 772 | { |
| 808 | if (!phy_is_ulpi(phy)) | 773 | struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy); |
| 774 | |||
| 775 | if (!phy->is_ulpi_phy) | ||
| 809 | utmi_phy_postresume(phy); | 776 | utmi_phy_postresume(phy); |
| 810 | } | 777 | } |
| 811 | EXPORT_SYMBOL_GPL(tegra_usb_phy_postresume); | 778 | EXPORT_SYMBOL_GPL(tegra_usb_phy_postresume); |
| 812 | 779 | ||
| 813 | void tegra_ehci_phy_restore_start(struct tegra_usb_phy *phy, | 780 | void tegra_ehci_phy_restore_start(struct usb_phy *x, |
| 814 | enum tegra_usb_phy_port_speed port_speed) | 781 | enum tegra_usb_phy_port_speed port_speed) |
| 815 | { | 782 | { |
| 816 | if (!phy_is_ulpi(phy)) | 783 | struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy); |
| 784 | |||
| 785 | if (!phy->is_ulpi_phy) | ||
| 817 | utmi_phy_restore_start(phy, port_speed); | 786 | utmi_phy_restore_start(phy, port_speed); |
| 818 | } | 787 | } |
| 819 | EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_start); | 788 | EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_start); |
| 820 | 789 | ||
| 821 | void tegra_ehci_phy_restore_end(struct tegra_usb_phy *phy) | 790 | void tegra_ehci_phy_restore_end(struct usb_phy *x) |
| 822 | { | 791 | { |
| 823 | if (!phy_is_ulpi(phy)) | 792 | struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy); |
| 793 | |||
| 794 | if (!phy->is_ulpi_phy) | ||
| 824 | utmi_phy_restore_end(phy); | 795 | utmi_phy_restore_end(phy); |
| 825 | } | 796 | } |
| 826 | EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_end); | 797 | EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_end); |
| 827 | 798 | ||
| 828 | void tegra_usb_phy_clk_disable(struct tegra_usb_phy *phy) | ||
| 829 | { | ||
| 830 | if (!phy_is_ulpi(phy)) | ||
| 831 | utmi_phy_clk_disable(phy); | ||
| 832 | } | ||
| 833 | EXPORT_SYMBOL_GPL(tegra_usb_phy_clk_disable); | ||
| 834 | |||
| 835 | void tegra_usb_phy_clk_enable(struct tegra_usb_phy *phy) | ||
| 836 | { | ||
| 837 | if (!phy_is_ulpi(phy)) | ||
| 838 | utmi_phy_clk_enable(phy); | ||
| 839 | } | ||
| 840 | EXPORT_SYMBOL_GPL(tegra_usb_phy_clk_enable); | ||
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 | ||
