diff options
author | Paul Cercueil <paul@crapouillou.net> | 2022-04-18 22:44:36 +0300 |
---|---|---|
committer | Paul Cercueil <paul@crapouillou.net> | 2022-04-18 22:46:55 +0300 |
commit | 40f458b7816bd3ddddc068998523b4e039c04818 (patch) | |
tree | f88d18bd293fb646a53cc025fa72329b0f738e97 /drivers | |
parent | c6ed9f66eb70aeaac9998bd3552ada740d90e20c (diff) | |
parent | c54b39a565227538c52ead2349eb17d54aadd6f7 (diff) | |
download | linux-40f458b7816bd3ddddc068998523b4e039c04818.tar.xz |
Merge drm/drm-next into drm-misc-next
drm/drm-next has a build fix for the NewVision NV3052C panel
(drivers/gpu/drm/panel/panel-newvision-nv3052c.c), which needs to be
merged back to drm-misc-next, as it was failing to build there.
Signed-off-by: Paul Cercueil <paul@crapouillou.net>
Diffstat (limited to 'drivers')
341 files changed, 6475 insertions, 5251 deletions
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 32b20efff5f8..4556c86c3465 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -570,8 +570,7 @@ static int acpi_idle_play_dead(struct cpuidle_device *dev, int index) { struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu); - if (cx->type == ACPI_STATE_C3) - ACPI_FLUSH_CPU_CACHE(); + ACPI_FLUSH_CPU_CACHE(); while (1) { diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 9efbfe087de7..762b61f67e6c 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -588,19 +588,6 @@ static struct acpi_device *handle_to_device(acpi_handle handle, return adev; } -int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device) -{ - if (!device) - return -EINVAL; - - *device = handle_to_device(handle, NULL); - if (!*device) - return -ENODEV; - - return 0; -} -EXPORT_SYMBOL(acpi_bus_get_device); - /** * acpi_fetch_acpi_dev - Retrieve ACPI device object. * @handle: ACPI handle associated with the requested ACPI device object. diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index e5641e6c52ee..bb45a9c00514 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -115,14 +115,16 @@ config SATA_AHCI If unsure, say N. -config SATA_LPM_POLICY +config SATA_MOBILE_LPM_POLICY int "Default SATA Link Power Management policy for low power chipsets" range 0 4 default 0 depends on SATA_AHCI help Select the Default SATA Link Power Management (LPM) policy to use - for chipsets / "South Bridges" designated as supporting low power. + for chipsets / "South Bridges" supporting low-power modes. Such + chipsets are typically found on most laptops but desktops and + servers now also widely use chipsets supporting low power modes. The value set has the following meanings: 0 => Keep firmware settings diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 84456c05e845..397dfd27c90d 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1595,7 +1595,7 @@ static int ahci_init_msi(struct pci_dev *pdev, unsigned int n_ports, static void ahci_update_initial_lpm_policy(struct ata_port *ap, struct ahci_host_priv *hpriv) { - int policy = CONFIG_SATA_LPM_POLICY; + int policy = CONFIG_SATA_MOBILE_LPM_POLICY; /* Ignore processing for chipsets that don't use policy */ diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index 6ead58c1b6e5..ad11a4c52fbe 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -236,7 +236,7 @@ enum { AHCI_HFLAG_NO_WRITE_TO_RO = (1 << 24), /* don't write to read only registers */ AHCI_HFLAG_USE_LPM_POLICY = (1 << 25), /* chipset that should use - SATA_LPM_POLICY + SATA_MOBILE_LPM_POLICY as default lpm_policy */ AHCI_HFLAG_SUSPEND_PHYS = (1 << 26), /* handle PHYs during suspend/resume */ diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index cceedde51126..ca64837641be 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4014,6 +4014,9 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { ATA_HORKAGE_ZERO_AFTER_TRIM, }, { "Crucial_CT*MX100*", "MU01", ATA_HORKAGE_NO_NCQ_TRIM | ATA_HORKAGE_ZERO_AFTER_TRIM, }, + { "Samsung SSD 840 EVO*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | + ATA_HORKAGE_NO_DMA_LOG | + ATA_HORKAGE_ZERO_AFTER_TRIM, }, { "Samsung SSD 840*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | ATA_HORKAGE_ZERO_AFTER_TRIM, }, { "Samsung SSD 850*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index b3be7a8f5bea..b1666adc1c3a 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -1634,7 +1634,7 @@ EXPORT_SYMBOL_GPL(ata_sff_interrupt); void ata_sff_lost_interrupt(struct ata_port *ap) { - u8 status; + u8 status = 0; struct ata_queued_cmd *qc; /* Only one outstanding command per SFF channel */ diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_460ex.c index bec33d781ae0..e3263e961045 100644 --- a/drivers/ata/sata_dwc_460ex.c +++ b/drivers/ata/sata_dwc_460ex.c @@ -137,7 +137,11 @@ struct sata_dwc_device { #endif }; -#define SATA_DWC_QCMD_MAX 32 +/* + * Allow one extra special slot for commands and DMA management + * to account for libata internal commands. + */ +#define SATA_DWC_QCMD_MAX (ATA_MAX_QUEUE + 1) struct sata_dwc_device_port { struct sata_dwc_device *hsdev; diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 4b55e864a0a3..4d3efaa20b7b 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1638,22 +1638,22 @@ struct sib_info { }; void drbd_bcast_event(struct drbd_device *device, const struct sib_info *sib); -extern void notify_resource_state(struct sk_buff *, +extern int notify_resource_state(struct sk_buff *, unsigned int, struct drbd_resource *, struct resource_info *, enum drbd_notification_type); -extern void notify_device_state(struct sk_buff *, +extern int notify_device_state(struct sk_buff *, unsigned int, struct drbd_device *, struct device_info *, enum drbd_notification_type); -extern void notify_connection_state(struct sk_buff *, +extern int notify_connection_state(struct sk_buff *, unsigned int, struct drbd_connection *, struct connection_info *, enum drbd_notification_type); -extern void notify_peer_device_state(struct sk_buff *, +extern int notify_peer_device_state(struct sk_buff *, unsigned int, struct drbd_peer_device *, struct peer_device_info *, diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 9676a1d214bc..4b0b25cc916e 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -2719,6 +2719,7 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig sprintf(disk->disk_name, "drbd%d", minor); disk->private_data = device; + blk_queue_flag_set(QUEUE_FLAG_STABLE_WRITES, disk->queue); blk_queue_write_cache(disk->queue, true, true); /* Setting the max_hw_sectors to an odd value of 8kibyte here This triggers a max_bio_size message upon first attach or connect */ @@ -2773,12 +2774,12 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig if (init_submitter(device)) { err = ERR_NOMEM; - goto out_idr_remove_vol; + goto out_idr_remove_from_resource; } err = add_disk(disk); if (err) - goto out_idr_remove_vol; + goto out_idr_remove_from_resource; /* inherit the connection state */ device->state.conn = first_connection(resource)->cstate; @@ -2792,8 +2793,6 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig drbd_debugfs_device_add(device); return NO_ERROR; -out_idr_remove_vol: - idr_remove(&connection->peer_devices, vnr); out_idr_remove_from_resource: for_each_connection(connection, resource) { peer_device = idr_remove(&connection->peer_devices, vnr); diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 02030c9c4d3b..b7216c186ba4 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -4549,7 +4549,7 @@ static int nla_put_notification_header(struct sk_buff *msg, return drbd_notification_header_to_skb(msg, &nh, true); } -void notify_resource_state(struct sk_buff *skb, +int notify_resource_state(struct sk_buff *skb, unsigned int seq, struct drbd_resource *resource, struct resource_info *resource_info, @@ -4591,16 +4591,17 @@ void notify_resource_state(struct sk_buff *skb, if (err && err != -ESRCH) goto failed; } - return; + return 0; nla_put_failure: nlmsg_free(skb); failed: drbd_err(resource, "Error %d while broadcasting event. Event seq:%u\n", err, seq); + return err; } -void notify_device_state(struct sk_buff *skb, +int notify_device_state(struct sk_buff *skb, unsigned int seq, struct drbd_device *device, struct device_info *device_info, @@ -4640,16 +4641,17 @@ void notify_device_state(struct sk_buff *skb, if (err && err != -ESRCH) goto failed; } - return; + return 0; nla_put_failure: nlmsg_free(skb); failed: drbd_err(device, "Error %d while broadcasting event. Event seq:%u\n", err, seq); + return err; } -void notify_connection_state(struct sk_buff *skb, +int notify_connection_state(struct sk_buff *skb, unsigned int seq, struct drbd_connection *connection, struct connection_info *connection_info, @@ -4689,16 +4691,17 @@ void notify_connection_state(struct sk_buff *skb, if (err && err != -ESRCH) goto failed; } - return; + return 0; nla_put_failure: nlmsg_free(skb); failed: drbd_err(connection, "Error %d while broadcasting event. Event seq:%u\n", err, seq); + return err; } -void notify_peer_device_state(struct sk_buff *skb, +int notify_peer_device_state(struct sk_buff *skb, unsigned int seq, struct drbd_peer_device *peer_device, struct peer_device_info *peer_device_info, @@ -4739,13 +4742,14 @@ void notify_peer_device_state(struct sk_buff *skb, if (err && err != -ESRCH) goto failed; } - return; + return 0; nla_put_failure: nlmsg_free(skb); failed: drbd_err(peer_device, "Error %d while broadcasting event. Event seq:%u\n", err, seq); + return err; } void notify_helper(enum drbd_notification_type type, @@ -4796,7 +4800,7 @@ fail: err, seq); } -static void notify_initial_state_done(struct sk_buff *skb, unsigned int seq) +static int notify_initial_state_done(struct sk_buff *skb, unsigned int seq) { struct drbd_genlmsghdr *dh; int err; @@ -4810,11 +4814,12 @@ static void notify_initial_state_done(struct sk_buff *skb, unsigned int seq) if (nla_put_notification_header(skb, NOTIFY_EXISTS)) goto nla_put_failure; genlmsg_end(skb, dh); - return; + return 0; nla_put_failure: nlmsg_free(skb); pr_err("Error %d sending event. Event seq:%u\n", err, seq); + return err; } static void free_state_changes(struct list_head *list) @@ -4841,6 +4846,7 @@ static int get_initial_state(struct sk_buff *skb, struct netlink_callback *cb) unsigned int seq = cb->args[2]; unsigned int n; enum drbd_notification_type flags = 0; + int err = 0; /* There is no need for taking notification_mutex here: it doesn't matter if the initial state events mix with later state chage @@ -4849,32 +4855,32 @@ static int get_initial_state(struct sk_buff *skb, struct netlink_callback *cb) cb->args[5]--; if (cb->args[5] == 1) { - notify_initial_state_done(skb, seq); + err = notify_initial_state_done(skb, seq); goto out; } n = cb->args[4]++; if (cb->args[4] < cb->args[3]) flags |= NOTIFY_CONTINUES; if (n < 1) { - notify_resource_state_change(skb, seq, state_change->resource, + err = notify_resource_state_change(skb, seq, state_change->resource, NOTIFY_EXISTS | flags); goto next; } n--; if (n < state_change->n_connections) { - notify_connection_state_change(skb, seq, &state_change->connections[n], + err = notify_connection_state_change(skb, seq, &state_change->connections[n], NOTIFY_EXISTS | flags); goto next; } n -= state_change->n_connections; if (n < state_change->n_devices) { - notify_device_state_change(skb, seq, &state_change->devices[n], + err = notify_device_state_change(skb, seq, &state_change->devices[n], NOTIFY_EXISTS | flags); goto next; } n -= state_change->n_devices; if (n < state_change->n_devices * state_change->n_connections) { - notify_peer_device_state_change(skb, seq, &state_change->peer_devices[n], + err = notify_peer_device_state_change(skb, seq, &state_change->peer_devices[n], NOTIFY_EXISTS | flags); goto next; } @@ -4889,7 +4895,10 @@ next: cb->args[4] = 0; } out: - return skb->len; + if (err) + return err; + else + return skb->len; } int drbd_adm_get_initial_state(struct sk_buff *skb, struct netlink_callback *cb) diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c index b8a27818ab3f..4ee11aef6672 100644 --- a/drivers/block/drbd/drbd_state.c +++ b/drivers/block/drbd/drbd_state.c @@ -1537,7 +1537,7 @@ int drbd_bitmap_io_from_worker(struct drbd_device *device, return rv; } -void notify_resource_state_change(struct sk_buff *skb, +int notify_resource_state_change(struct sk_buff *skb, unsigned int seq, struct drbd_resource_state_change *resource_state_change, enum drbd_notification_type type) @@ -1550,10 +1550,10 @@ void notify_resource_state_change(struct sk_buff *skb, .res_susp_fen = resource_state_change->susp_fen[NEW], }; - notify_resource_state(skb, seq, resource, &resource_info, type); + return notify_resource_state(skb, seq, resource, &resource_info, type); } -void notify_connection_state_change(struct sk_buff *skb, +int notify_connection_state_change(struct sk_buff *skb, unsigned int seq, struct drbd_connection_state_change *connection_state_change, enum drbd_notification_type type) @@ -1564,10 +1564,10 @@ void notify_connection_state_change(struct sk_buff *skb, .conn_role = connection_state_change->peer_role[NEW], }; - notify_connection_state(skb, seq, connection, &connection_info, type); + return notify_connection_state(skb, seq, connection, &connection_info, type); } -void notify_device_state_change(struct sk_buff *skb, +int notify_device_state_change(struct sk_buff *skb, unsigned int seq, struct drbd_device_state_change *device_state_change, enum drbd_notification_type type) @@ -1577,10 +1577,10 @@ void notify_device_state_change(struct sk_buff *skb, .dev_disk_state = device_state_change->disk_state[NEW], }; - notify_device_state(skb, seq, device, &device_info, type); + return notify_device_state(skb, seq, device, &device_info, type); } -void notify_peer_device_state_change(struct sk_buff *skb, +int notify_peer_device_state_change(struct sk_buff *skb, unsigned int seq, struct drbd_peer_device_state_change *p, enum drbd_notification_type type) @@ -1594,7 +1594,7 @@ void notify_peer_device_state_change(struct sk_buff *skb, .peer_resync_susp_dependency = p->resync_susp_dependency[NEW], }; - notify_peer_device_state(skb, seq, peer_device, &peer_device_info, type); + return notify_peer_device_state(skb, seq, peer_device, &peer_device_info, type); } static void broadcast_state_change(struct drbd_state_change *state_change) @@ -1602,7 +1602,7 @@ static void broadcast_state_change(struct drbd_state_change *state_change) struct drbd_resource_state_change *resource_state_change = &state_change->resource[0]; bool resource_state_has_changed; unsigned int n_device, n_connection, n_peer_device, n_peer_devices; - void (*last_func)(struct sk_buff *, unsigned int, void *, + int (*last_func)(struct sk_buff *, unsigned int, void *, enum drbd_notification_type) = NULL; void *last_arg = NULL; diff --git a/drivers/block/drbd/drbd_state_change.h b/drivers/block/drbd/drbd_state_change.h index ba80f612d6ab..d5b0479bc9a6 100644 --- a/drivers/block/drbd/drbd_state_change.h +++ b/drivers/block/drbd/drbd_state_change.h @@ -44,19 +44,19 @@ extern struct drbd_state_change *remember_old_state(struct drbd_resource *, gfp_ extern void copy_old_to_new_state_change(struct drbd_state_change *); extern void forget_state_change(struct drbd_state_change *); -extern void notify_resource_state_change(struct sk_buff *, +extern int notify_resource_state_change(struct sk_buff *, unsigned int, struct drbd_resource_state_change *, enum drbd_notification_type type); -extern void notify_connection_state_change(struct sk_buff *, +extern int notify_connection_state_change(struct sk_buff *, unsigned int, struct drbd_connection_state_change *, enum drbd_notification_type type); -extern void notify_device_state_change(struct sk_buff *, +extern int notify_device_state_change(struct sk_buff *, unsigned int, struct drbd_device_state_change *, enum drbd_notification_type type); -extern void notify_peer_device_state_change(struct sk_buff *, +extern int notify_peer_device_state_change(struct sk_buff *, unsigned int, struct drbd_peer_device_state_change *, enum drbd_notification_type type); diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 7bd10d63ddbe..2dc9da683a13 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -1365,7 +1365,6 @@ out_free: */ int cdrom_number_of_slots(struct cdrom_device_info *cdi) { - int status; int nslots = 1; struct cdrom_changer_info *info; @@ -1377,7 +1376,7 @@ int cdrom_number_of_slots(struct cdrom_device_info *cdi) if (!info) return -ENOMEM; - if ((status = cdrom_read_mech_status(cdi, info)) == 0) + if (cdrom_read_mech_status(cdi, info) == 0) nslots = info->hdr.nslots; kfree(info); diff --git a/drivers/char/random.c b/drivers/char/random.c index 1d8242969751..e15063d61460 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -437,11 +437,8 @@ static void crng_make_state(u32 chacha_state[CHACHA_STATE_WORDS], * This shouldn't be set by functions like add_device_randomness(), * where we can't trust the buffer passed to it is guaranteed to be * unpredictable (so it might not have any entropy at all). - * - * Returns the number of bytes processed from input, which is bounded - * by CRNG_INIT_CNT_THRESH if account is true. */ -static size_t crng_pre_init_inject(const void *input, size_t len, bool account) +static void crng_pre_init_inject(const void *input, size_t len, bool account) { static int crng_init_cnt = 0; struct blake2s_state hash; @@ -452,18 +449,15 @@ static size_t crng_pre_init_inject(const void *input, size_t len, bool account) spin_lock_irqsave(&base_crng.lock, flags); if (crng_init != 0) { spin_unlock_irqrestore(&base_crng.lock, flags); - return 0; + return; } - if (account) - len = min_t(size_t, len, CRNG_INIT_CNT_THRESH - crng_init_cnt); - blake2s_update(&hash, base_crng.key, sizeof(base_crng.key)); blake2s_update(&hash, input, len); blake2s_final(&hash, base_crng.key); if (account) { - crng_init_cnt += len; + crng_init_cnt += min_t(size_t, len, CRNG_INIT_CNT_THRESH - crng_init_cnt); if (crng_init_cnt >= CRNG_INIT_CNT_THRESH) { ++base_crng.generation; crng_init = 1; @@ -474,8 +468,6 @@ static size_t crng_pre_init_inject(const void *input, size_t len, bool account) if (crng_init == 1) pr_notice("fast init done\n"); - - return len; } static void _get_random_bytes(void *buf, size_t nbytes) @@ -531,7 +523,6 @@ EXPORT_SYMBOL(get_random_bytes); static ssize_t get_random_bytes_user(void __user *buf, size_t nbytes) { - bool large_request = nbytes > 256; ssize_t ret = 0; size_t len; u32 chacha_state[CHACHA_STATE_WORDS]; @@ -540,22 +531,23 @@ static ssize_t get_random_bytes_user(void __user *buf, size_t nbytes) if (!nbytes) return 0; - len = min_t(size_t, 32, nbytes); - crng_make_state(chacha_state, output, len); - - if (copy_to_user(buf, output, len)) - return -EFAULT; - nbytes -= len; - buf += len; - ret += len; - - while (nbytes) { - if (large_request && need_resched()) { - if (signal_pending(current)) - break; - schedule(); - } + /* + * Immediately overwrite the ChaCha key at index 4 with random + * bytes, in case userspace causes copy_to_user() below to sleep + * forever, so that we still retain forward secrecy in that case. + */ + crng_make_state(chacha_state, (u8 *)&chacha_state[4], CHACHA_KEY_SIZE); + /* + * However, if we're doing a read of len <= 32, we don't need to + * use chacha_state after, so we can simply return those bytes to + * the user directly. + */ + if (nbytes <= CHACHA_KEY_SIZE) { + ret = copy_to_user(buf, &chacha_state[4], nbytes) ? -EFAULT : nbytes; + goto out_zero_chacha; + } + do { chacha20_block(chacha_state, output); if (unlikely(chacha_state[12] == 0)) ++chacha_state[13]; @@ -569,10 +561,18 @@ static ssize_t get_random_bytes_user(void __user *buf, size_t nbytes) nbytes -= len; buf += len; ret += len; - } - memzero_explicit(chacha_state, sizeof(chacha_state)); + BUILD_BUG_ON(PAGE_SIZE % CHACHA_BLOCK_SIZE != 0); + if (!(ret % PAGE_SIZE) && nbytes) { + if (signal_pending(current)) + break; + cond_resched(); + } + } while (nbytes); + memzero_explicit(output, sizeof(output)); +out_zero_chacha: + memzero_explicit(chacha_state, sizeof(chacha_state)); return ret; } @@ -1141,12 +1141,9 @@ void add_hwgenerator_randomness(const void *buffer, size_t count, size_t entropy) { if (unlikely(crng_init == 0 && entropy < POOL_MIN_BITS)) { - size_t ret = crng_pre_init_inject(buffer, count, true); - mix_pool_bytes(buffer, ret); - count -= ret; - buffer += ret; - if (!count || crng_init == 0) - return; + crng_pre_init_inject(buffer, count, true); + mix_pool_bytes(buffer, count); + return; } /* @@ -1545,6 +1542,13 @@ static ssize_t urandom_read(struct file *file, char __user *buf, size_t nbytes, { static int maxwarn = 10; + /* + * Opportunistically attempt to initialize the RNG on platforms that + * have fast cycle counters, but don't (for now) require it to succeed. + */ + if (!crng_ready()) + try_to_generate_entropy(); + if (!crng_ready() && maxwarn > 0) { maxwarn--; if (__ratelimit(&urandom_warning)) diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c index 8a7267d116b7..3f2182d66829 100644 --- a/drivers/cxl/pci.c +++ b/drivers/cxl/pci.c @@ -436,7 +436,6 @@ static int wait_for_media_ready(struct cxl_dev_state *cxlds) for (i = mbox_ready_timeout; i; i--) { u32 temp; - int rc; rc = pci_read_config_dword( pdev, d + CXL_DVSEC_RANGE_SIZE_LOW(0), &temp); diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile index 511805dbeb75..4c9eb53ba3f8 100644 --- a/drivers/dma-buf/Makefile +++ b/drivers/dma-buf/Makefile @@ -12,6 +12,7 @@ dmabuf_selftests-y := \ selftest.o \ st-dma-fence.o \ st-dma-fence-chain.o \ + st-dma-fence-unwrap.o \ st-dma-resv.o obj-$(CONFIG_DMABUF_SELFTESTS) += dmabuf_selftests.o diff --git a/drivers/dma-buf/dma-fence-array.c b/drivers/dma-buf/dma-fence-array.c index cb1bacb5a42b..5c8a7084577b 100644 --- a/drivers/dma-buf/dma-fence-array.c +++ b/drivers/dma-buf/dma-fence-array.c @@ -159,6 +159,8 @@ struct dma_fence_array *dma_fence_array_create(int num_fences, struct dma_fence_array *array; size_t size = sizeof(*array); + WARN_ON(!num_fences || !fences); + /* Allocate the callback structures behind the array. */ size += num_fences * sizeof(struct dma_fence_array_cb); array = kzalloc(size, GFP_KERNEL); @@ -219,3 +221,33 @@ bool dma_fence_match_context(struct dma_fence *fence, u64 context) return true; } EXPORT_SYMBOL(dma_fence_match_context); + +struct dma_fence *dma_fence_array_first(struct dma_fence *head) +{ + struct dma_fence_array *array; + + if (!head) + return NULL; + + array = to_dma_fence_array(head); + if (!array) + return head; + + if (!array->num_fences) + return NULL; + + return array->fences[0]; +} +EXPORT_SYMBOL(dma_fence_array_first); + +struct dma_fence *dma_fence_array_next(struct dma_fence *head, + unsigned int index) +{ + struct dma_fence_array *array = to_dma_fence_array(head); + + if (!array || index >= array->num_fences) + return NULL; + + return array->fences[index]; +} +EXPORT_SYMBOL(dma_fence_array_next); diff --git a/drivers/dma-buf/selftests.h b/drivers/dma-buf/selftests.h index 97d73aaa31da..851965867d9c 100644 --- a/drivers/dma-buf/selftests.h +++ b/drivers/dma-buf/selftests.h @@ -12,4 +12,5 @@ selftest(sanitycheck, __sanitycheck__) /* keep first (igt selfcheck) */ selftest(dma_fence, dma_fence) selftest(dma_fence_chain, dma_fence_chain) +selftest(dma_fence_unwrap, dma_fence_unwrap) selftest(dma_resv, dma_resv) diff --git a/drivers/dma-buf/st-dma-fence-unwrap.c b/drivers/dma-buf/st-dma-fence-unwrap.c new file mode 100644 index 000000000000..039f016b57be --- /dev/null +++ b/drivers/dma-buf/st-dma-fence-unwrap.c @@ -0,0 +1,261 @@ +// SPDX-License-Identifier: MIT + +/* + * Copyright (C) 2022 Advanced Micro Devices, Inc. + */ + +#include <linux/dma-fence-unwrap.h> +#if 0 +#include <linux/kernel.h> +#include <linux/kthread.h> +#include <linux/mm.h> +#include <linux/sched/signal.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/random.h> +#endif + +#include "selftest.h" + +#define CHAIN_SZ (4 << 10) + +static inline struct mock_fence { + struct dma_fence base; + spinlock_t lock; +} *to_mock_fence(struct dma_fence *f) { + return container_of(f, struct mock_fence, base); +} + +static const char *mock_name(struct dma_fence *f) +{ + return "mock"; +} + +static const struct dma_fence_ops mock_ops = { + .get_driver_name = mock_name, + .get_timeline_name = mock_name, +}; + +static struct dma_fence *mock_fence(void) +{ + struct mock_fence *f; + + f = kmalloc(sizeof(*f), GFP_KERNEL); + if (!f) + return NULL; + + spin_lock_init(&f->lock); + dma_fence_init(&f->base, &mock_ops, &f->lock, 0, 0); + + return &f->base; +} + +static struct dma_fence *mock_array(unsigned int num_fences, ...) +{ + struct dma_fence_array *array; + struct dma_fence **fences; + va_list valist; + int i; + + fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL); + if (!fences) + return NULL; + + va_start(valist, num_fences); + for (i = 0; i < num_fences; ++i) + fences[i] = va_arg(valist, typeof(*fences)); + va_end(valist); + + array = dma_fence_array_create(num_fences, fences, + dma_fence_context_alloc(1), + 1, false); + if (!array) + goto cleanup; + return &array->base; + +cleanup: + for (i = 0; i < num_fences; ++i) + dma_fence_put(fences[i]); + kfree(fences); + return NULL; +} + +static struct dma_fence *mock_chain(struct dma_fence *prev, + struct dma_fence *fence) +{ + struct dma_fence_chain *f; + + f = dma_fence_chain_alloc(); + if (!f) { + dma_fence_put(prev); + dma_fence_put(fence); + return NULL; + } + + dma_fence_chain_init(f, prev, fence, 1); + return &f->base; +} + +static int sanitycheck(void *arg) +{ + struct dma_fence *f, *chain, *array; + int err = 0; + + f = mock_fence(); + if (!f) + return -ENOMEM; + + array = mock_array(1, f); + if (!array) + return -ENOMEM; + + chain = mock_chain(NULL, array); + if (!chain) + return -ENOMEM; + + dma_fence_signal(f); + dma_fence_put(chain); + return err; +} + +static int unwrap_array(void *arg) +{ + struct dma_fence *fence, *f1, *f2, *array; + struct dma_fence_unwrap iter; + int err = 0; + + f1 = mock_fence(); + if (!f1) + return -ENOMEM; + + f2 = mock_fence(); + if (!f2) { + dma_fence_put(f1); + return -ENOMEM; + } + + array = mock_array(2, f1, f2); + if (!array) + return -ENOMEM; + + dma_fence_unwrap_for_each(fence, &iter, array) { + if (fence == f1) { + f1 = NULL; + } else if (fence == f2) { + f2 = NULL; + } else { + pr_err("Unexpected fence!\n"); + err = -EINVAL; + } + } + + if (f1 || f2) { + pr_err("Not all fences seen!\n"); + err = -EINVAL; + } + + dma_fence_signal(f1); + dma_fence_signal(f2); + dma_fence_put(array); + return 0; +} + +static int unwrap_chain(void *arg) +{ + struct dma_fence *fence, *f1, *f2, *chain; + struct dma_fence_unwrap iter; + int err = 0; + + f1 = mock_fence(); + if (!f1) + return -ENOMEM; + + f2 = mock_fence(); + if (!f2) { + dma_fence_put(f1); + return -ENOMEM; + } + + chain = mock_chain(f1, f2); + if (!chain) + return -ENOMEM; + + dma_fence_unwrap_for_each(fence, &iter, chain) { + if (fence == f1) { + f1 = NULL; + } else if (fence == f2) { + f2 = NULL; + } else { + pr_err("Unexpected fence!\n"); + err = -EINVAL; + } + } + + if (f1 || f2) { + pr_err("Not all fences seen!\n"); + err = -EINVAL; + } + + dma_fence_signal(f1); + dma_fence_signal(f2); + dma_fence_put(chain); + return 0; +} + +static int unwrap_chain_array(void *arg) +{ + struct dma_fence *fence, *f1, *f2, *array, *chain; + struct dma_fence_unwrap iter; + int err = 0; + + f1 = mock_fence(); + if (!f1) + return -ENOMEM; + + f2 = mock_fence(); + if (!f2) { + dma_fence_put(f1); + return -ENOMEM; + } + + array = mock_array(2, f1, f2); + if (!array) + return -ENOMEM; + + chain = mock_chain(NULL, array); + if (!chain) + return -ENOMEM; + + dma_fence_unwrap_for_each(fence, &iter, chain) { + if (fence == f1) { + f1 = NULL; + } else if (fence == f2) { + f2 = NULL; + } else { + pr_err("Unexpected fence!\n"); + err = -EINVAL; + } + } + + if (f1 || f2) { + pr_err("Not all fences seen!\n"); + err = -EINVAL; + } + + dma_fence_signal(f1); + dma_fence_signal(f2); + dma_fence_put(chain); + return 0; +} + +int dma_fence_unwrap(void) +{ + static const struct subtest tests[] = { + SUBTEST(sanitycheck), + SUBTEST(unwrap_array), + SUBTEST(unwrap_chain), + SUBTEST(unwrap_chain_array), + }; + + return subtests(tests, NULL); +} diff --git a/drivers/dma-buf/sync_file.c b/drivers/dma-buf/sync_file.c index 394e6e1e9686..514d213261df 100644 --- a/drivers/dma-buf/sync_file.c +++ b/drivers/dma-buf/sync_file.c @@ -5,6 +5,7 @@ * Copyright (C) 2012 Google, Inc. */ +#include <linux/dma-fence-unwrap.h> #include <linux/export.h> #include <linux/file.h> #include <linux/fs.h> @@ -172,20 +173,6 @@ static int sync_file_set_fence(struct sync_file *sync_file, return 0; } -static struct dma_fence **get_fences(struct sync_file *sync_file, - int *num_fences) -{ - if (dma_fence_is_array(sync_file->fence)) { - struct dma_fence_array *array = to_dma_fence_array(sync_file->fence); - - *num_fences = array->num_fences; - return array->fences; - } - - *num_fences = 1; - return &sync_file->fence; -} - static void add_fence(struct dma_fence **fences, int *i, struct dma_fence *fence) { @@ -210,86 +197,97 @@ static void add_fence(struct dma_fence **fences, static struct sync_file *sync_file_merge(const char *name, struct sync_file *a, struct sync_file *b) { + struct dma_fence *a_fence, *b_fence, **fences; + struct dma_fence_unwrap a_iter, b_iter; + unsigned int index, num_fences; struct sync_file *sync_file; - struct dma_fence **fences = NULL, **nfences, **a_fences, **b_fences; - int i = 0, i_a, i_b, num_fences, a_num_fences, b_num_fences; sync_file = sync_file_alloc(); if (!sync_file) return NULL; - a_fences = get_fences(a, &a_num_fences); - b_fences = get_fences(b, &b_num_fences); - if (a_num_fences > INT_MAX - b_num_fences) - goto err; + num_fences = 0; + dma_fence_unwrap_for_each(a_fence, &a_iter, a->fence) + ++num_fences; + dma_fence_unwrap_for_each(b_fence, &b_iter, b->fence) + ++num_fences; - num_fences = a_num_fences + b_num_fences; + if (num_fences > INT_MAX) + goto err_free_sync_file; fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL); if (!fences) - goto err; + goto err_free_sync_file; /* - * Assume sync_file a and b are both ordered and have no - * duplicates with the same context. + * We can't guarantee that fences in both a and b are ordered, but it is + * still quite likely. * - * If a sync_file can only be created with sync_file_merge - * and sync_file_create, this is a reasonable assumption. + * So attempt to order the fences as we pass over them and merge fences + * with the same context. */ - for (i_a = i_b = 0; i_a < a_num_fences && i_b < b_num_fences; ) { - struct dma_fence *pt_a = a_fences[i_a]; - struct dma_fence *pt_b = b_fences[i_b]; - if (pt_a->context < pt_b->context) { - add_fence(fences, &i, pt_a); + index = 0; + for (a_fence = dma_fence_unwrap_first(a->fence, &a_iter), + b_fence = dma_fence_unwrap_first(b->fence, &b_iter); + a_fence || b_fence; ) { + + if (!b_fence) { + add_fence(fences, &index, a_fence); + a_fence = dma_fence_unwrap_next(&a_iter); + + } else if (!a_fence) { + add_fence(fences, &index, b_fence); + b_fence = dma_fence_unwrap_next(&b_iter); + + } else if (a_fence->context < b_fence->context) { + add_fence(fences, &index, a_fence); + a_fence = dma_fence_unwrap_next(&a_iter); - i_a++; - } else if (pt_a->context > pt_b->context) { - add_fence(fences, &i, pt_b); + } else if (b_fence->context < a_fence->context) { + add_fence(fences, &index, b_fence); + b_fence = dma_fence_unwrap_next(&b_iter); + + } else if (__dma_fence_is_later(a_fence->seqno, b_fence->seqno, + a_fence->ops)) { + add_fence(fences, &index, a_fence); + a_fence = dma_fence_unwrap_next(&a_iter); + b_fence = dma_fence_unwrap_next(&b_iter); - i_b++; } else { - if (__dma_fence_is_later(pt_a->seqno, pt_b->seqno, - pt_a->ops)) - add_fence(fences, &i, pt_a); - else - add_fence(fences, &i, pt_b); - - i_a++; - i_b++; + add_fence(fences, &index, b_fence); + a_fence = dma_fence_unwrap_next(&a_iter); + b_fence = dma_fence_unwrap_next(&b_iter); } } - for (; i_a < a_num_fences; i_a++) - add_fence(fences, &i, a_fences[i_a]); - - for (; i_b < b_num_fences; i_b++) - add_fence(fences, &i, b_fences[i_b]); - - if (i == 0) - fences[i++] = dma_fence_get(a_fences[0]); + if (index == 0) + fences[index++] = dma_fence_get_stub(); - if (num_fences > i) { - nfences = krealloc_array(fences, i, sizeof(*fences), GFP_KERNEL); - if (!nfences) - goto err; + if (num_fences > index) { + struct dma_fence **tmp; - fences = nfences; + /* Keep going even when reducing the size failed */ + tmp = krealloc_array(fences, index, sizeof(*fences), + GFP_KERNEL); + if (tmp) + fences = tmp; } - if (sync_file_set_fence(sync_file, fences, i) < 0) - goto err; + if (sync_file_set_fence(sync_file, fences, index) < 0) + goto err_put_fences; strlcpy(sync_file->user_name, name, sizeof(sync_file->user_name)); return sync_file; -err: - while (i) - dma_fence_put(fences[--i]); +err_put_fences: + while (index) + dma_fence_put(fences[--index]); kfree(fences); + +err_free_sync_file: fput(sync_file->file); return NULL; - } static int sync_file_release(struct inode *inode, struct file *file) @@ -398,11 +396,13 @@ static int sync_fill_fence_info(struct dma_fence *fence, static long sync_file_ioctl_fence_info(struct sync_file *sync_file, unsigned long arg) { - struct sync_file_info info; struct sync_fence_info *fence_info = NULL; - struct dma_fence **fences; + struct dma_fence_unwrap iter; + struct sync_file_info info; + unsigned int num_fences; + struct dma_fence *fence; + int ret; __u32 size; - int num_fences, ret, i; if (copy_from_user(&info, (void __user *)arg, sizeof(info))) return -EFAULT; @@ -410,7 +410,9 @@ static long sync_file_ioctl_fence_info(struct sync_file *sync_file, if (info.flags || info.pad) return -EINVAL; - fences = get_fences(sync_file, &num_fences); + num_fences = 0; + dma_fence_unwrap_for_each(fence, &iter, sync_file->fence) + ++num_fences; /* * Passing num_fences = 0 means that userspace doesn't want to @@ -433,8 +435,11 @@ static long sync_file_ioctl_fence_info(struct sync_file *sync_file, if (!fence_info) return -ENOMEM; - for (i = 0; i < num_fences; i++) { - int status = sync_fill_fence_info(fences[i], &fence_info[i]); + num_fences = 0; + dma_fence_unwrap_for_each(fence, &iter, sync_file->fence) { + int status; + + status = sync_fill_fence_info(fence, &fence_info[num_fences++]); info.status = info.status <= 0 ? info.status : status; } diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index e59884cc12a7..085348e08986 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1404,6 +1404,16 @@ static int gpiochip_to_irq(struct gpio_chip *gc, unsigned int offset) { struct irq_domain *domain = gc->irq.domain; +#ifdef CONFIG_GPIOLIB_IRQCHIP + /* + * Avoid race condition with other code, which tries to lookup + * an IRQ before the irqchip has been properly registered, + * i.e. while gpiochip is still being brought up. + */ + if (!gc->irq.initialized) + return -EPROBE_DEFER; +#endif + if (!gpiochip_irqchip_irq_valid(gc, offset)) return -ENXIO; @@ -1593,6 +1603,15 @@ static int gpiochip_add_irqchip(struct gpio_chip *gc, acpi_gpiochip_request_interrupts(gc); + /* + * Using barrier() here to prevent compiler from reordering + * gc->irq.initialized before initialization of above + * GPIO chip irq members. + */ + barrier(); + + gc->irq.initialized = true; + return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/ObjectID.h b/drivers/gpu/drm/amd/amdgpu/ObjectID.h index 5b393622f592..a0f0a17e224f 100644 --- a/drivers/gpu/drm/amd/amdgpu/ObjectID.h +++ b/drivers/gpu/drm/amd/amdgpu/ObjectID.h @@ -119,6 +119,7 @@ #define CONNECTOR_OBJECT_ID_eDP 0x14 #define CONNECTOR_OBJECT_ID_MXM 0x15 #define CONNECTOR_OBJECT_ID_LVDS_eDP 0x16 +#define CONNECTOR_OBJECT_ID_USBC 0x17 /* deleted */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 3987ecb24ef4..49f734137f15 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -5733,7 +5733,7 @@ void amdgpu_device_flush_hdp(struct amdgpu_device *adev, struct amdgpu_ring *ring) { #ifdef CONFIG_X86_64 - if (adev->flags & AMD_IS_APU) + if ((adev->flags & AMD_IS_APU) && !amdgpu_passthrough(adev)) return; #endif if (adev->gmc.xgmi.connected_to_cpu) @@ -5749,7 +5749,7 @@ void amdgpu_device_invalidate_hdp(struct amdgpu_device *adev, struct amdgpu_ring *ring) { #ifdef CONFIG_X86_64 - if (adev->flags & AMD_IS_APU) + if ((adev->flags & AMD_IS_APU) && !amdgpu_passthrough(adev)) return; #endif if (adev->gmc.xgmi.connected_to_cpu) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index bb1c025d9001..b03663f42cc9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -680,7 +680,7 @@ MODULE_PARM_DESC(sched_policy, * Maximum number of processes that HWS can schedule concurrently. The maximum is the * number of VMIDs assigned to the HWS, which is also the default. */ -int hws_max_conc_proc = 8; +int hws_max_conc_proc = -1; module_param(hws_max_conc_proc, int, 0444); MODULE_PARM_DESC(hws_max_conc_proc, "Max # processes HWS can execute concurrently when sched_policy=0 (0 = no concurrency, #VMIDs for KFD = Maximum(default))"); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c index 8fe939976224..28a736c507bb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c @@ -266,7 +266,7 @@ static int amdgpu_gfx_kiq_acquire(struct amdgpu_device *adev, * adev->gfx.mec.num_pipe_per_mec * adev->gfx.mec.num_queue_per_pipe; - while (queue_bit-- >= 0) { + while (--queue_bit >= 0) { if (test_bit(queue_bit, adev->gfx.mec.queue_bitmap)) continue; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c index ca2cfb65f976..a66a0881a934 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c @@ -561,9 +561,15 @@ void amdgpu_gmc_noretry_set(struct amdgpu_device *adev) switch (adev->ip_versions[GC_HWIP][0]) { case IP_VERSION(9, 0, 1): + case IP_VERSION(9, 3, 0): case IP_VERSION(9, 4, 0): case IP_VERSION(9, 4, 1): case IP_VERSION(9, 4, 2): + case IP_VERSION(10, 3, 3): + case IP_VERSION(10, 3, 4): + case IP_VERSION(10, 3, 5): + case IP_VERSION(10, 3, 6): + case IP_VERSION(10, 3, 7): /* * noretry = 0 will cause kfd page fault tests fail * for some ASICs, so set default to 1 for these ASICs. diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index ef93abec13b9..e92ecabfa7bd 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -1283,6 +1283,7 @@ void amdgpu_bo_get_memory(struct amdgpu_bo *bo, uint64_t *vram_mem, */ void amdgpu_bo_release_notify(struct ttm_buffer_object *bo) { + struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev); struct dma_fence *fence = NULL; struct amdgpu_bo *abo; int r; @@ -1302,7 +1303,8 @@ void amdgpu_bo_release_notify(struct ttm_buffer_object *bo) amdgpu_amdkfd_remove_fence_on_pt_pd_bos(abo); if (bo->resource->mem_type != TTM_PL_VRAM || - !(abo->flags & AMDGPU_GEM_CREATE_VRAM_WIPE_ON_RELEASE)) + !(abo->flags & AMDGPU_GEM_CREATE_VRAM_WIPE_ON_RELEASE) || + adev->in_suspend || adev->shutdown) return; if (WARN_ON_ONCE(!dma_resv_trylock(bo->base.resv))) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h index 5320bb0883d8..317d80209e95 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h @@ -300,8 +300,8 @@ void amdgpu_ring_generic_pad_ib(struct amdgpu_ring *ring, struct amdgpu_ib *ib); void amdgpu_ring_commit(struct amdgpu_ring *ring); void amdgpu_ring_undo(struct amdgpu_ring *ring); int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring, - unsigned int ring_size, struct amdgpu_irq_src *irq_src, - unsigned int irq_type, unsigned int prio, + unsigned int max_dw, struct amdgpu_irq_src *irq_src, + unsigned int irq_type, unsigned int hw_prio, atomic_t *sched_score); void amdgpu_ring_fini(struct amdgpu_ring *ring); void amdgpu_ring_emit_reg_write_reg_wait_helper(struct amdgpu_ring *ring, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h index e2fde88aaf5e..f06fb7f882e2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h @@ -159,6 +159,7 @@ #define AMDGPU_VCN_MULTI_QUEUE_FLAG (1 << 8) #define AMDGPU_VCN_SW_RING_FLAG (1 << 9) #define AMDGPU_VCN_FW_LOGGING_FLAG (1 << 10) +#define AMDGPU_VCN_SMU_VERSION_INFO_FLAG (1 << 11) #define AMDGPU_VCN_IB_FLAG_DECODE_BUFFER 0x00000001 #define AMDGPU_VCN_CMD_FLAG_MSG_BUFFER 0x00000001 @@ -279,6 +280,11 @@ struct amdgpu_fw_shared_fw_logging { uint32_t size; }; +struct amdgpu_fw_shared_smu_interface_info { + uint8_t smu_interface_type; + uint8_t padding[3]; +}; + struct amdgpu_fw_shared { uint32_t present_flag_0; uint8_t pad[44]; @@ -287,6 +293,7 @@ struct amdgpu_fw_shared { struct amdgpu_fw_shared_multi_queue multi_queue; struct amdgpu_fw_shared_sw_ring sw_ring; struct amdgpu_fw_shared_fw_logging fw_log; + struct amdgpu_fw_shared_smu_interface_info smu_interface_info; }; struct amdgpu_vcn_fwlog { diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c index f4c6accd3226..9426e252d8aa 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c @@ -3293,7 +3293,7 @@ static const struct soc15_reg_golden golden_settings_gc_10_3_3[] = SOC15_REG_GOLDEN_VALUE(GC, 0, mmDB_DEBUG3, 0xffffffff, 0x00000280), SOC15_REG_GOLDEN_VALUE(GC, 0, mmDB_DEBUG4, 0xffffffff, 0x00800000), SOC15_REG_GOLDEN_VALUE(GC, 0, mmGB_ADDR_CONFIG, 0x0c1807ff, 0x00000242), - SOC15_REG_GOLDEN_VALUE(GC, 0, mmGCR_GENERAL_CNTL, 0x1ff1ffff, 0x00000500), + SOC15_REG_GOLDEN_VALUE(GC, 0, mmGCR_GENERAL_CNTL_Vangogh, 0x1ff1ffff, 0x00000500), SOC15_REG_GOLDEN_VALUE(GC, 0, mmGL1_PIPE_STEER, 0x000000ff, 0x000000e4), SOC15_REG_GOLDEN_VALUE(GC, 0, mmGL2_PIPE_STEER_0, 0x77777777, 0x32103210), SOC15_REG_GOLDEN_VALUE(GC, 0, mmGL2_PIPE_STEER_1, 0x77777777, 0x32103210), @@ -3429,7 +3429,7 @@ static const struct soc15_reg_golden golden_settings_gc_10_3_6[] = SOC15_REG_GOLDEN_VALUE(GC, 0, mmDB_DEBUG3, 0xffffffff, 0x00000280), SOC15_REG_GOLDEN_VALUE(GC, 0, mmDB_DEBUG4, 0xffffffff, 0x00800000), SOC15_REG_GOLDEN_VALUE(GC, 0, mmGB_ADDR_CONFIG, 0x0c1807ff, 0x00000042), - SOC15_REG_GOLDEN_VALUE(GC, 0, mmGCR_GENERAL_CNTL, 0x1ff1ffff, 0x00000500), + SOC15_REG_GOLDEN_VALUE(GC, 0, mmGCR_GENERAL_CNTL_Vangogh, 0x1ff1ffff, 0x00000500), SOC15_REG_GOLDEN_VALUE(GC, 0, mmGL1_PIPE_STEER, 0x000000ff, 0x00000044), SOC15_REG_GOLDEN_VALUE(GC, 0, mmGL2_PIPE_STEER_0, 0x77777777, 0x32103210), SOC15_REG_GOLDEN_VALUE(GC, 0, mmGL2_PIPE_STEER_1, 0x77777777, 0x32103210), @@ -3454,7 +3454,7 @@ static const struct soc15_reg_golden golden_settings_gc_10_3_7[] = { SOC15_REG_GOLDEN_VALUE(GC, 0, mmDB_DEBUG3, 0xffffffff, 0x00000280), SOC15_REG_GOLDEN_VALUE(GC, 0, mmDB_DEBUG4, 0xffffffff, 0x00800000), SOC15_REG_GOLDEN_VALUE(GC, 0, mmGB_ADDR_CONFIG, 0x0c1807ff, 0x00000041), - SOC15_REG_GOLDEN_VALUE(GC, 0, mmGCR_GENERAL_CNTL, 0x1ff1ffff, 0x00000500), + SOC15_REG_GOLDEN_VALUE(GC, 0, mmGCR_GENERAL_CNTL_Vangogh, 0x1ff1ffff, 0x00000500), SOC15_REG_GOLDEN_VALUE(GC, 0, mmGL1_PIPE_STEER, 0x000000ff, 0x000000e4), SOC15_REG_GOLDEN_VALUE(GC, 0, mmGL2_PIPE_STEER_0, 0x77777777, 0x32103210), SOC15_REG_GOLDEN_VALUE(GC, 0, mmGL2_PIPE_STEER_1, 0x77777777, 0x32103210), @@ -7689,6 +7689,7 @@ static uint64_t gfx_v10_0_get_gpu_clock_counter(struct amdgpu_device *adev) switch (adev->ip_versions[GC_HWIP][0]) { case IP_VERSION(10, 3, 1): case IP_VERSION(10, 3, 3): + case IP_VERSION(10, 3, 7): preempt_disable(); clock_hi = RREG32_SOC15_NO_KIQ(SMUIO, 0, mmGOLDEN_TSC_COUNT_UPPER_Vangogh); clock_lo = RREG32_SOC15_NO_KIQ(SMUIO, 0, mmGOLDEN_TSC_COUNT_LOWER_Vangogh); diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c index 3c1d440824a7..5228421b0f72 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c @@ -814,7 +814,7 @@ static int gmc_v10_0_mc_init(struct amdgpu_device *adev) adev->gmc.aper_size = pci_resource_len(adev->pdev, 0); #ifdef CONFIG_X86_64 - if (adev->flags & AMD_IS_APU) { + if ((adev->flags & AMD_IS_APU) && !amdgpu_passthrough(adev)) { adev->gmc.aper_base = adev->gfxhub.funcs->get_mc_fb_offset(adev); adev->gmc.aper_size = adev->gmc.real_vram_size; } diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c index 344d819b4c1b..979da6f510e8 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c @@ -381,8 +381,9 @@ static int gmc_v7_0_mc_init(struct amdgpu_device *adev) adev->gmc.aper_size = pci_resource_len(adev->pdev, 0); #ifdef CONFIG_X86_64 - if (adev->flags & AMD_IS_APU && - adev->gmc.real_vram_size > adev->gmc.aper_size) { + if ((adev->flags & AMD_IS_APU) && + adev->gmc.real_vram_size > adev->gmc.aper_size && + !amdgpu_passthrough(adev)) { adev->gmc.aper_base = ((u64)RREG32(mmMC_VM_FB_OFFSET)) << 22; adev->gmc.aper_size = adev->gmc.real_vram_size; } diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c index ca9841d5669f..1932a3e4af7e 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c @@ -581,7 +581,7 @@ static int gmc_v8_0_mc_init(struct amdgpu_device *adev) adev->gmc.aper_size = pci_resource_len(adev->pdev, 0); #ifdef CONFIG_X86_64 - if (adev->flags & AMD_IS_APU) { + if ((adev->flags & AMD_IS_APU) && !amdgpu_passthrough(adev)) { adev->gmc.aper_base = ((u64)RREG32(mmMC_VM_FB_OFFSET)) << 22; adev->gmc.aper_size = adev->gmc.real_vram_size; } diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c index 431742eb7811..6009fbfdcc19 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c @@ -1456,7 +1456,7 @@ static int gmc_v9_0_mc_init(struct amdgpu_device *adev) */ /* check whether both host-gpu and gpu-gpu xgmi links exist */ - if ((adev->flags & AMD_IS_APU) || + if (((adev->flags & AMD_IS_APU) && !amdgpu_passthrough(adev)) || (adev->gmc.xgmi.supported && adev->gmc.xgmi.connected_to_cpu)) { adev->gmc.aper_base = @@ -1721,7 +1721,7 @@ static int gmc_v9_0_sw_fini(void *handle) amdgpu_gem_force_release(adev); amdgpu_vm_manager_fini(adev); amdgpu_gart_table_vram_free(adev); - amdgpu_bo_unref(&adev->gmc.pdb0_bo); + amdgpu_bo_free_kernel(&adev->gmc.pdb0_bo, NULL, &adev->gmc.ptr_pdb0); amdgpu_bo_fini(adev); return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c index dff54190b96c..f0fbcda76f5e 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c @@ -24,6 +24,7 @@ #include <linux/firmware.h> #include "amdgpu.h" +#include "amdgpu_cs.h" #include "amdgpu_vcn.h" #include "amdgpu_pm.h" #include "soc15.h" @@ -1900,6 +1901,75 @@ static const struct amd_ip_funcs vcn_v1_0_ip_funcs = { .set_powergating_state = vcn_v1_0_set_powergating_state, }; +/* + * It is a hardware issue that VCN can't handle a GTT TMZ buffer on + * CHIP_RAVEN series ASIC. Move such a GTT TMZ buffer to VRAM domain + * before command submission as a workaround. + */ +static int vcn_v1_0_validate_bo(struct amdgpu_cs_parser *parser, + struct amdgpu_job *job, + uint64_t addr) +{ + struct ttm_operation_ctx ctx = { false, false }; + struct amdgpu_fpriv *fpriv = parser->filp->driver_priv; + struct amdgpu_vm *vm = &fpriv->vm; + struct amdgpu_bo_va_mapping *mapping; + struct amdgpu_bo *bo; + int r; + + addr &= AMDGPU_GMC_HOLE_MASK; + if (addr & 0x7) { + DRM_ERROR("VCN messages must be 8 byte aligned!\n"); + return -EINVAL; + } + + mapping = amdgpu_vm_bo_lookup_mapping(vm, addr/AMDGPU_GPU_PAGE_SIZE); + if (!mapping || !mapping->bo_va || !mapping->bo_va->base.bo) + return -EINVAL; + + bo = mapping->bo_va->base.bo; + if (!(bo->flags & AMDGPU_GEM_CREATE_ENCRYPTED)) + return 0; + + amdgpu_bo_placement_from_domain(bo, AMDGPU_GEM_DOMAIN_VRAM); + r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); + if (r) { + DRM_ERROR("Failed to validate the VCN message BO (%d)!\n", r); + return r; + } + + return r; +} + +static int vcn_v1_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p, + struct amdgpu_job *job, + struct amdgpu_ib *ib) +{ + uint32_t msg_lo = 0, msg_hi = 0; + int i, r; + + if (!(ib->flags & AMDGPU_IB_FLAGS_SECURE)) + return 0; + + for (i = 0; i < ib->length_dw; i += 2) { + uint32_t reg = amdgpu_ib_get_value(ib, i); + uint32_t val = amdgpu_ib_get_value(ib, i + 1); + + if (reg == PACKET0(p->adev->vcn.internal.data0, 0)) { + msg_lo = val; + } else if (reg == PACKET0(p->adev->vcn.internal.data1, 0)) { + msg_hi = val; + } else if (reg == PACKET0(p->adev->vcn.internal.cmd, 0)) { + r = vcn_v1_0_validate_bo(p, job, + ((u64)msg_hi) << 32 | msg_lo); + if (r) + return r; + } + } + + return 0; +} + static const struct amdgpu_ring_funcs vcn_v1_0_dec_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_DEC, .align_mask = 0xf, @@ -1910,6 +1980,7 @@ static const struct amdgpu_ring_funcs vcn_v1_0_dec_ring_vm_funcs = { .get_rptr = vcn_v1_0_dec_ring_get_rptr, .get_wptr = vcn_v1_0_dec_ring_get_wptr, .set_wptr = vcn_v1_0_dec_ring_set_wptr, + .patch_cs_in_place = vcn_v1_0_ring_patch_cs_in_place, .emit_frame_size = 6 + 6 + /* hdp invalidate / flush */ SOC15_FLUSH_GPU_TLB_NUM_WREG * 6 + diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c index c87263ed20ec..cb5f0a12333f 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c @@ -219,6 +219,11 @@ static int vcn_v3_0_sw_init(void *handle) cpu_to_le32(AMDGPU_VCN_MULTI_QUEUE_FLAG) | cpu_to_le32(AMDGPU_VCN_FW_SHARED_FLAG_0_RB); fw_shared->sw_ring.is_enabled = cpu_to_le32(DEC_SW_RING_ENABLED); + fw_shared->present_flag_0 |= AMDGPU_VCN_SMU_VERSION_INFO_FLAG; + if (adev->ip_versions[UVD_HWIP][0] == IP_VERSION(3, 1, 2)) + fw_shared->smu_interface_info.smu_interface_type = 2; + else if (adev->ip_versions[UVD_HWIP][0] == IP_VERSION(3, 1, 1)) + fw_shared->smu_interface_info.smu_interface_type = 1; if (amdgpu_vcnfw_log) amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]); @@ -575,8 +580,8 @@ static void vcn_v3_0_mc_resume_dpg_mode(struct amdgpu_device *adev, int inst_idx AMDGPU_GPU_PAGE_ALIGN(sizeof(struct amdgpu_fw_shared)), 0, indirect); /* VCN global tiling registers */ - WREG32_SOC15_DPG_MODE(0, SOC15_DPG_MODE_OFFSET( - UVD, 0, mmUVD_GFX10_ADDR_CONFIG), adev->gfx.config.gb_addr_config, 0, indirect); + WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET( + UVD, inst_idx, mmUVD_GFX10_ADDR_CONFIG), adev->gfx.config.gb_addr_config, 0, indirect); } static void vcn_v3_0_disable_static_power_gating(struct amdgpu_device *adev, int inst) @@ -1480,8 +1485,11 @@ static int vcn_v3_0_start_sriov(struct amdgpu_device *adev) static int vcn_v3_0_stop_dpg_mode(struct amdgpu_device *adev, int inst_idx) { + struct dpg_pause_state state = {.fw_based = VCN_DPG_STATE__UNPAUSE}; uint32_t tmp; + vcn_v3_0_pause_dpg_mode(adev, inst_idx, &state); + /* Wait for power status to be 1 */ SOC15_WAIT_ON_RREG(VCN, inst_idx, mmUVD_POWER_STATUS, 1, UVD_POWER_STATUS__UVD_POWER_STATUS_MASK); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index 339e12c94cff..62aa6c9d5123 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -483,15 +483,10 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd, } /* Verify module parameters regarding mapped process number*/ - if ((hws_max_conc_proc < 0) - || (hws_max_conc_proc > kfd->vm_info.vmid_num_kfd)) { - dev_err(kfd_device, - "hws_max_conc_proc %d must be between 0 and %d, use %d instead\n", - hws_max_conc_proc, kfd->vm_info.vmid_num_kfd, - kfd->vm_info.vmid_num_kfd); + if (hws_max_conc_proc >= 0) + kfd->max_proc_per_quantum = min((u32)hws_max_conc_proc, kfd->vm_info.vmid_num_kfd); + else kfd->max_proc_per_quantum = kfd->vm_info.vmid_num_kfd; - } else - kfd->max_proc_per_quantum = hws_max_conc_proc; /* calculate max size of mqds needed for queues */ size = max_num_of_queues_per_device * @@ -536,7 +531,8 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd, goto kfd_doorbell_error; } - kfd->hive_id = kfd->adev->gmc.xgmi.hive_id; + if (amdgpu_use_xgmi_p2p) + kfd->hive_id = kfd->adev->gmc.xgmi.hive_id; kfd->noretry = kfd->adev->gmc.noretry; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_events.c index deecccebe5b6..64f4a51cc880 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_events.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_events.c @@ -749,6 +749,8 @@ static struct kfd_event_waiter *alloc_event_waiters(uint32_t num_events) event_waiters = kmalloc_array(num_events, sizeof(struct kfd_event_waiter), GFP_KERNEL); + if (!event_waiters) + return NULL; for (i = 0; (event_waiters) && (i < num_events) ; i++) { init_wait(&event_waiters[i].wait); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c index e4beebb1c80a..f2e1d506ba21 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c @@ -247,15 +247,6 @@ int kfd_smi_event_open(struct kfd_dev *dev, uint32_t *fd) return ret; } - ret = anon_inode_getfd(kfd_smi_name, &kfd_smi_ev_fops, (void *)client, - O_RDWR); - if (ret < 0) { - kfifo_free(&client->fifo); - kfree(client); - return ret; - } - *fd = ret; - init_waitqueue_head(&client->wait_queue); spin_lock_init(&client->lock); client->events = 0; @@ -265,5 +256,20 @@ int kfd_smi_event_open(struct kfd_dev *dev, uint32_t *fd) list_add_rcu(&client->list, &dev->smi_clients); spin_unlock(&dev->smi_lock); + ret = anon_inode_getfd(kfd_smi_name, &kfd_smi_ev_fops, (void *)client, + O_RDWR); + if (ret < 0) { + spin_lock(&dev->smi_lock); + list_del_rcu(&client->list); + spin_unlock(&dev->smi_lock); + + synchronize_rcu(); + + kfifo_free(&client->fifo); + kfree(client); + return ret; + } + *fd = ret; + return 0; } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 9e24b1e616af..73423b805b54 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -2714,7 +2714,8 @@ static int dm_resume(void *handle) * this is the case when traversing through already created * MST connectors, should be skipped */ - if (aconnector->mst_port) + if (aconnector->dc_link && + aconnector->dc_link->type == dc_connection_mst_branch) continue; mutex_lock(&aconnector->hpd_lock); @@ -3972,7 +3973,7 @@ static u32 convert_brightness_to_user(const struct amdgpu_dm_backlight_caps *cap max - min); } -static int amdgpu_dm_backlight_set_level(struct amdgpu_display_manager *dm, +static void amdgpu_dm_backlight_set_level(struct amdgpu_display_manager *dm, int bl_idx, u32 user_brightness) { @@ -4003,7 +4004,8 @@ static int amdgpu_dm_backlight_set_level(struct amdgpu_display_manager *dm, DRM_DEBUG("DM: Failed to update backlight on eDP[%d]\n", bl_idx); } - return rc ? 0 : 1; + if (rc) + dm->actual_brightness[bl_idx] = user_brightness; } static int amdgpu_dm_backlight_update_status(struct backlight_device *bd) @@ -9948,7 +9950,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) /* restore the backlight level */ for (i = 0; i < dm->num_of_edps; i++) { if (dm->backlight_dev[i] && - (amdgpu_dm_backlight_get_level(dm, i) != dm->brightness[i])) + (dm->actual_brightness[i] != dm->brightness[i])) amdgpu_dm_backlight_set_level(dm, i, dm->brightness[i]); } #endif diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h index 6a908d736d6a..7e44b0429448 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -540,6 +540,12 @@ struct amdgpu_display_manager { * cached backlight values. */ u32 brightness[AMDGPU_DM_MAX_NUM_EDP]; + /** + * @actual_brightness: + * + * last successfully applied backlight values. + */ + u32 actual_brightness[AMDGPU_DM_MAX_NUM_EDP]; }; enum dsc_clock_force_state { diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c index edda572dc570..8be4c1970628 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c @@ -436,57 +436,84 @@ static void dcn315_clk_mgr_helper_populate_bw_params( struct integrated_info *bios_info, const DpmClocks_315_t *clock_table) { - int i, j; + int i; struct clk_bw_params *bw_params = clk_mgr->base.bw_params; - uint32_t max_dispclk = 0, max_dppclk = 0; - - j = -1; - - ASSERT(NUM_DF_PSTATE_LEVELS <= MAX_NUM_DPM_LVL); - - /* Find lowest DPM, FCLK is filled in reverse order*/ - - for (i = NUM_DF_PSTATE_LEVELS - 1; i >= 0; i--) { - if (clock_table->DfPstateTable[i].FClk != 0) { - j = i; - break; + uint32_t max_dispclk, max_dppclk, max_pstate, max_socclk, max_fclk = 0, min_pstate = 0; + struct clk_limit_table_entry def_max = bw_params->clk_table.entries[bw_params->clk_table.num_entries - 1]; + + max_dispclk = find_max_clk_value(clock_table->DispClocks, clock_table->NumDispClkLevelsEnabled); + max_dppclk = find_max_clk_value(clock_table->DppClocks, clock_table->NumDispClkLevelsEnabled); + max_socclk = find_max_clk_value(clock_table->SocClocks, clock_table->NumSocClkLevelsEnabled); + + /* Find highest fclk pstate */ + for (i = 0; i < clock_table->NumDfPstatesEnabled; i++) { + if (clock_table->DfPstateTable[i].FClk > max_fclk) { + max_fclk = clock_table->DfPstateTable[i].FClk; + max_pstate = i; } } - if (j == -1) { - /* clock table is all 0s, just use our own hardcode */ - ASSERT(0); - return; - } - - bw_params->clk_table.num_entries = j + 1; - - /* dispclk and dppclk can be max at any voltage, same number of levels for both */ - if (clock_table->NumDispClkLevelsEnabled <= NUM_DISPCLK_DPM_LEVELS && - clock_table->NumDispClkLevelsEnabled <= NUM_DPPCLK_DPM_LEVELS) { - max_dispclk = find_max_clk_value(clock_table->DispClocks, clock_table->NumDispClkLevelsEnabled); - max_dppclk = find_max_clk_value(clock_table->DppClocks, clock_table->NumDispClkLevelsEnabled); - } else { - ASSERT(0); - } + /* For 315 we want to base clock table on dcfclk, need at least one entry regardless of pmfw table */ + for (i = 0; i < clock_table->NumDcfClkLevelsEnabled; i++) { + int j; + uint32_t min_fclk = clock_table->DfPstateTable[0].FClk; - for (i = 0; i < bw_params->clk_table.num_entries; i++, j--) { - int temp; + for (j = 1; j < clock_table->NumDfPstatesEnabled; j++) { + if (clock_table->DfPstateTable[j].Voltage <= clock_table->SocVoltage[i] + && clock_table->DfPstateTable[j].FClk < min_fclk) { + min_fclk = clock_table->DfPstateTable[j].FClk; + min_pstate = j; + } + } - bw_params->clk_table.entries[i].fclk_mhz = clock_table->DfPstateTable[j].FClk; - bw_params->clk_table.entries[i].memclk_mhz = clock_table->DfPstateTable[j].MemClk; - bw_params->clk_table.entries[i].voltage = clock_table->DfPstateTable[j].Voltage; + bw_params->clk_table.entries[i].fclk_mhz = min_fclk; + bw_params->clk_table.entries[i].memclk_mhz = clock_table->DfPstateTable[min_pstate].MemClk; + bw_params->clk_table.entries[i].voltage = clock_table->DfPstateTable[min_pstate].Voltage; + bw_params->clk_table.entries[i].dcfclk_mhz = clock_table->DcfClocks[i]; + bw_params->clk_table.entries[i].socclk_mhz = clock_table->SocClocks[i]; + bw_params->clk_table.entries[i].dispclk_mhz = max_dispclk; + bw_params->clk_table.entries[i].dppclk_mhz = max_dppclk; bw_params->clk_table.entries[i].wck_ratio = 1; - temp = find_clk_for_voltage(clock_table, clock_table->DcfClocks, clock_table->DfPstateTable[j].Voltage); - if (temp) - bw_params->clk_table.entries[i].dcfclk_mhz = temp; - temp = find_clk_for_voltage(clock_table, clock_table->SocClocks, clock_table->DfPstateTable[j].Voltage); - if (temp) - bw_params->clk_table.entries[i].socclk_mhz = temp; + }; + + /* Make sure to include at least one entry and highest pstate */ + if (max_pstate != min_pstate) { + bw_params->clk_table.entries[i].fclk_mhz = max_fclk; + bw_params->clk_table.entries[i].memclk_mhz = clock_table->DfPstateTable[max_pstate].MemClk; + bw_params->clk_table.entries[i].voltage = clock_table->DfPstateTable[max_pstate].Voltage; + bw_params->clk_table.entries[i].dcfclk_mhz = find_clk_for_voltage( + clock_table, clock_table->DcfClocks, clock_table->DfPstateTable[max_pstate].Voltage); + bw_params->clk_table.entries[i].socclk_mhz = find_clk_for_voltage( + clock_table, clock_table->SocClocks, clock_table->DfPstateTable[max_pstate].Voltage); bw_params->clk_table.entries[i].dispclk_mhz = max_dispclk; bw_params->clk_table.entries[i].dppclk_mhz = max_dppclk; + bw_params->clk_table.entries[i].wck_ratio = 1; + i++; } + bw_params->clk_table.num_entries = i; + + /* Include highest socclk */ + if (bw_params->clk_table.entries[i-1].socclk_mhz < max_socclk) + bw_params->clk_table.entries[i-1].socclk_mhz = max_socclk; + /* Set any 0 clocks to max default setting. Not an issue for + * power since we aren't doing switching in such case anyway + */ + for (i = 0; i < bw_params->clk_table.num_entries; i++) { + if (!bw_params->clk_table.entries[i].fclk_mhz) { + bw_params->clk_table.entries[i].fclk_mhz = def_max.fclk_mhz; + bw_params->clk_table.entries[i].memclk_mhz = def_max.memclk_mhz; + bw_params->clk_table.entries[i].voltage = def_max.voltage; + } + if (!bw_params->clk_table.entries[i].dcfclk_mhz) + bw_params->clk_table.entries[i].dcfclk_mhz = def_max.dcfclk_mhz; + if (!bw_params->clk_table.entries[i].socclk_mhz) + bw_params->clk_table.entries[i].socclk_mhz = def_max.socclk_mhz; + if (!bw_params->clk_table.entries[i].dispclk_mhz) + bw_params->clk_table.entries[i].dispclk_mhz = def_max.dispclk_mhz; + if (!bw_params->clk_table.entries[i].dppclk_mhz) + bw_params->clk_table.entries[i].dppclk_mhz = def_max.dppclk_mhz; + } bw_params->vram_type = bios_info->memory_type; bw_params->num_channels = bios_info->ma_channel_number; diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_smu.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_smu.c index 880ffea2afc6..2600313fea57 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_smu.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_smu.c @@ -80,8 +80,8 @@ static const struct IP_BASE NBIO_BASE = { { { { 0x00000000, 0x00000014, 0x00000D #define VBIOSSMC_MSG_SetDppclkFreq 0x06 ///< Set DPP clock frequency in MHZ #define VBIOSSMC_MSG_SetHardMinDcfclkByFreq 0x07 ///< Set DCF clock frequency hard min in MHZ #define VBIOSSMC_MSG_SetMinDeepSleepDcfclk 0x08 ///< Set DCF clock minimum frequency in deep sleep in MHZ -#define VBIOSSMC_MSG_SetPhyclkVoltageByFreq 0x09 ///< Set display phy clock frequency in MHZ in case VMIN does not support phy frequency -#define VBIOSSMC_MSG_GetFclkFrequency 0x0A ///< Get FCLK frequency, return frequemcy in MHZ +#define VBIOSSMC_MSG_GetDtbclkFreq 0x09 ///< Get display dtb clock frequency in MHZ in case VMIN does not support phy frequency +#define VBIOSSMC_MSG_SetDtbClk 0x0A ///< Set dtb clock frequency, return frequemcy in MHZ #define VBIOSSMC_MSG_SetDisplayCount 0x0B ///< Inform PMFW of number of display connected #define VBIOSSMC_MSG_EnableTmdp48MHzRefclkPwrDown 0x0C ///< To ask PMFW turn off TMDP 48MHz refclk during display off to save power #define VBIOSSMC_MSG_UpdatePmeRestore 0x0D ///< To ask PMFW to write into Azalia for PME wake up event @@ -324,15 +324,26 @@ int dcn315_smu_get_dpref_clk(struct clk_mgr_internal *clk_mgr) return (dprefclk_get_mhz * 1000); } -int dcn315_smu_get_smu_fclk(struct clk_mgr_internal *clk_mgr) +int dcn315_smu_get_dtbclk(struct clk_mgr_internal *clk_mgr) { int fclk_get_mhz = -1; if (clk_mgr->smu_present) { fclk_get_mhz = dcn315_smu_send_msg_with_param( clk_mgr, - VBIOSSMC_MSG_GetFclkFrequency, + VBIOSSMC_MSG_GetDtbclkFreq, 0); } return (fclk_get_mhz * 1000); } + +void dcn315_smu_set_dtbclk(struct clk_mgr_internal *clk_mgr, bool enable) +{ + if (!clk_mgr->smu_present) + return; + + dcn315_smu_send_msg_with_param( + clk_mgr, + VBIOSSMC_MSG_SetDtbClk, + enable); +} diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_smu.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_smu.h index 66fa42f8dd18..5aa3275ac7d8 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_smu.h +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_smu.h @@ -37,6 +37,7 @@ #define NUM_SOC_VOLTAGE_LEVELS 4 #define NUM_DF_PSTATE_LEVELS 4 + typedef struct { uint16_t MinClock; // This is either DCFCLK or SOCCLK (in MHz) uint16_t MaxClock; // This is either DCFCLK or SOCCLK (in MHz) @@ -124,5 +125,6 @@ void dcn315_smu_transfer_wm_table_dram_2_smu(struct clk_mgr_internal *clk_mgr); void dcn315_smu_request_voltage_via_phyclk(struct clk_mgr_internal *clk_mgr, int requested_phyclk_khz); void dcn315_smu_enable_pme_wa(struct clk_mgr_internal *clk_mgr); int dcn315_smu_get_dpref_clk(struct clk_mgr_internal *clk_mgr); -int dcn315_smu_get_smu_fclk(struct clk_mgr_internal *clk_mgr); +int dcn315_smu_get_dtbclk(struct clk_mgr_internal *clk_mgr); +void dcn315_smu_set_dtbclk(struct clk_mgr_internal *clk_mgr, bool enable); #endif /* DAL_DC_315_SMU_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index f6e19efea756..c436db416708 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -2389,6 +2389,8 @@ static enum surface_update_type check_update_surfaces_for_stream( if (stream_update->mst_bw_update) su_flags->bits.mst_bw = 1; + if (stream_update->crtc_timing_adjust && dc_extended_blank_supported(dc)) + su_flags->bits.crtc_timing_adjust = 1; if (su_flags->raw != 0) overall_type = UPDATE_TYPE_FULL; @@ -2650,6 +2652,9 @@ static void copy_stream_update_to_stream(struct dc *dc, if (update->vrr_infopacket) stream->vrr_infopacket = *update->vrr_infopacket; + if (update->crtc_timing_adjust) + stream->adjust = *update->crtc_timing_adjust; + if (update->dpms_off) stream->dpms_off = *update->dpms_off; @@ -4051,3 +4056,17 @@ void dc_notify_vsync_int_state(struct dc *dc, struct dc_stream_state *stream, bo if (pipe->stream_res.abm && pipe->stream_res.abm->funcs->set_abm_pause) pipe->stream_res.abm->funcs->set_abm_pause(pipe->stream_res.abm, !enable, i, pipe->stream_res.tg->inst); } +/* + * dc_extended_blank_supported: Decide whether extended blank is supported + * + * Extended blank is a freesync optimization feature to be enabled in the future. + * During the extra vblank period gained from freesync, we have the ability to enter z9/z10. + * + * @param [in] dc: Current DC state + * @return: Indicate whether extended blank is supported (true or false) + */ +bool dc_extended_blank_supported(struct dc *dc) +{ + return dc->debug.extended_blank_optimization && !dc->debug.disable_z10 + && dc->caps.zstate_support && dc->caps.is_apu; +} diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index cb87dd643180..bbaa5abdf888 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -983,8 +983,7 @@ static bool should_verify_link_capability_destructively(struct dc_link *link, destrictive = false; } } - } else if (dc_is_hdmi_signal(link->local_sink->sink_signal)) - destrictive = true; + } return destrictive; } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c index 351081f574cb..22dabe596dfc 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c @@ -5216,6 +5216,62 @@ static void retrieve_cable_id(struct dc_link *link) &link->dpcd_caps.cable_id, &usbc_cable_id); } +/* DPRX may take some time to respond to AUX messages after HPD asserted. + * If AUX read unsuccessful, try to wake unresponsive DPRX by toggling DPCD SET_POWER (0x600). + */ +static enum dc_status wa_try_to_wake_dprx(struct dc_link *link, uint64_t timeout_ms) +{ + enum dc_status status = DC_ERROR_UNEXPECTED; + uint8_t dpcd_data = 0; + uint64_t start_ts = 0; + uint64_t current_ts = 0; + uint64_t time_taken_ms = 0; + enum dc_connection_type type = dc_connection_none; + + status = core_link_read_dpcd( + link, + DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV, + &dpcd_data, + sizeof(dpcd_data)); + + if (status != DC_OK) { + DC_LOG_WARNING("%s: Read DPCD LTTPR_CAP failed - try to toggle DPCD SET_POWER for %lld ms.", + __func__, + timeout_ms); + start_ts = dm_get_timestamp(link->ctx); + + do { + if (!dc_link_detect_sink(link, &type) || type == dc_connection_none) + break; + + dpcd_data = DP_SET_POWER_D3; + status = core_link_write_dpcd( + link, + DP_SET_POWER, + &dpcd_data, + sizeof(dpcd_data)); + + dpcd_data = DP_SET_POWER_D0; + status = core_link_write_dpcd( + link, + DP_SET_POWER, + &dpcd_data, + sizeof(dpcd_data)); + + current_ts = dm_get_timestamp(link->ctx); + time_taken_ms = div_u64(dm_get_elapse_time_in_ns(link->ctx, current_ts, start_ts), 1000000); + } while (status != DC_OK && time_taken_ms < timeout_ms); + + DC_LOG_WARNING("%s: DPCD SET_POWER %s after %lld ms%s", + __func__, + (status == DC_OK) ? "succeeded" : "failed", + time_taken_ms, + (type == dc_connection_none) ? ". Unplugged." : "."); + } + + return status; +} + static bool retrieve_link_cap(struct dc_link *link) { /* DP_ADAPTER_CAP - DP_DPCD_REV + 1 == 16 and also DP_DSC_BITS_PER_PIXEL_INC - DP_DSC_SUPPORT + 1 == 16, @@ -5251,6 +5307,15 @@ static bool retrieve_link_cap(struct dc_link *link) dc_link_aux_try_to_configure_timeout(link->ddc, LINK_AUX_DEFAULT_LTTPR_TIMEOUT_PERIOD); + /* Try to ensure AUX channel active before proceeding. */ + if (link->dc->debug.aux_wake_wa.bits.enable_wa) { + uint64_t timeout_ms = link->dc->debug.aux_wake_wa.bits.timeout_ms; + + if (link->dc->debug.aux_wake_wa.bits.use_default_timeout) + timeout_ms = LINK_AUX_WAKE_TIMEOUT_MS; + status = wa_try_to_wake_dprx(link, timeout_ms); + } + is_lttpr_present = dp_retrieve_lttpr_cap(link); /* Read DP tunneling information. */ status = dpcd_get_tunneling_device_data(link); diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index 7af153434e9e..d251c3f3a714 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -1685,8 +1685,8 @@ bool dc_is_stream_unchanged( if (old_stream->ignore_msa_timing_param != stream->ignore_msa_timing_param) return false; - // Only Have Audio left to check whether it is same or not. This is a corner case for Tiled sinks - if (old_stream->audio_info.mode_count != stream->audio_info.mode_count) + /*compare audio info*/ + if (memcmp(&old_stream->audio_info, &stream->audio_info, sizeof(stream->audio_info)) != 0) return false; return true; diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 4ffab7bb1098..77ef9d1f9ea8 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -188,6 +188,7 @@ struct dc_caps { bool psp_setup_panel_mode; bool extended_aux_timeout_support; bool dmcub_support; + bool zstate_support; uint32_t num_of_internal_disp; enum dp_protocol_version max_dp_protocol_version; unsigned int mall_size_per_mem_channel; @@ -525,6 +526,22 @@ union dpia_debug_options { uint32_t raw; }; +/* AUX wake work around options + * 0: enable/disable work around + * 1: use default timeout LINK_AUX_WAKE_TIMEOUT_MS + * 15-2: reserved + * 31-16: timeout in ms + */ +union aux_wake_wa_options { + struct { + uint32_t enable_wa : 1; + uint32_t use_default_timeout : 1; + uint32_t rsvd: 14; + uint32_t timeout_ms : 16; + } bits; + uint32_t raw; +}; + struct dc_debug_data { uint32_t ltFailCount; uint32_t i2cErrorCount; @@ -703,13 +720,15 @@ struct dc_debug_options { bool enable_driver_sequence_debug; enum det_size crb_alloc_policy; int crb_alloc_policy_min_disp_count; -#if defined(CONFIG_DRM_AMD_DC_DCN) bool disable_z10; +#if defined(CONFIG_DRM_AMD_DC_DCN) bool enable_z9_disable_interface; bool enable_sw_cntl_psr; union dpia_debug_options dpia_debug; #endif bool apply_vendor_specific_lttpr_wa; + bool extended_blank_optimization; + union aux_wake_wa_options aux_wake_wa; bool ignore_dpref_ss; uint8_t psr_power_use_phy_fsm; }; @@ -1369,6 +1388,8 @@ struct dc_sink_init_data { bool converter_disable_audio; }; +bool dc_extended_blank_supported(struct dc *dc); + struct dc_sink *dc_sink_create(const struct dc_sink_init_data *init_params); /* Newer interfaces */ diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index 99a750f561f8..c4168c11257c 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -131,6 +131,7 @@ union stream_update_flags { uint32_t wb_update:1; uint32_t dsc_changed : 1; uint32_t mst_bw : 1; + uint32_t crtc_timing_adjust : 1; } bits; uint32_t raw; @@ -289,6 +290,7 @@ struct dc_stream_update { struct dc_3dlut *lut3d_func; struct test_pattern *pending_test_pattern; + struct dc_crtc_timing_adjust *crtc_timing_adjust; }; bool dc_is_stream_unchanged( diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index c3e141c19a77..781334b395ba 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -1497,16 +1497,12 @@ void dcn10_init_hw(struct dc *dc) link->link_status.link_active = true; } - /* Power gate DSCs */ - if (!is_optimized_init_done) { - for (i = 0; i < res_pool->res_cap->num_dsc; i++) - if (hws->funcs.dsc_pg_control != NULL) - hws->funcs.dsc_pg_control(hws, res_pool->dscs[i]->inst, false); - } - /* we want to turn off all dp displays before doing detection */ dc_link_blank_all_dp_displays(dc); + if (hws->funcs.enable_power_gating_plane) + hws->funcs.enable_power_gating_plane(dc->hwseq, true); + /* If taking control over from VBIOS, we may want to optimize our first * mode set, so we need to skip powering down pipes until we know which * pipes we want to use. @@ -1559,8 +1555,6 @@ void dcn10_init_hw(struct dc *dc) REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); } - if (hws->funcs.enable_power_gating_plane) - hws->funcs.enable_power_gating_plane(dc->hwseq, true); if (dc->clk_mgr->funcs->notify_wm_ranges) dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr); @@ -2056,7 +2050,7 @@ static int dcn10_align_pixel_clocks(struct dc *dc, int group_size, { struct dc_context *dc_ctx = dc->ctx; int i, master = -1, embedded = -1; - struct dc_crtc_timing hw_crtc_timing[MAX_PIPES] = {0}; + struct dc_crtc_timing *hw_crtc_timing; uint64_t phase[MAX_PIPES]; uint64_t modulo[MAX_PIPES]; unsigned int pclk; @@ -2067,6 +2061,10 @@ static int dcn10_align_pixel_clocks(struct dc *dc, int group_size, uint32_t dp_ref_clk_100hz = dc->res_pool->dp_clock_source->ctx->dc->clk_mgr->dprefclk_khz*10; + hw_crtc_timing = kcalloc(MAX_PIPES, sizeof(*hw_crtc_timing), GFP_KERNEL); + if (!hw_crtc_timing) + return master; + if (dc->config.vblank_alignment_dto_params && dc->res_pool->dp_clock_source->funcs->override_dp_pix_clk) { embedded_h_total = @@ -2130,6 +2128,8 @@ static int dcn10_align_pixel_clocks(struct dc *dc, int group_size, } } + + kfree(hw_crtc_timing); return master; } diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c index ab910deed481..4290eaf11a04 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c @@ -1857,6 +1857,7 @@ void dcn20_optimize_bandwidth( struct dc_state *context) { struct hubbub *hubbub = dc->res_pool->hubbub; + int i; /* program dchubbub watermarks */ hubbub->funcs->program_watermarks(hubbub, @@ -1873,6 +1874,17 @@ void dcn20_optimize_bandwidth( dc->clk_mgr, context, true); + if (dc_extended_blank_supported(dc) && context->bw_ctx.bw.dcn.clk.zstate_support == DCN_ZSTATE_SUPPORT_ALLOW) { + for (i = 0; i < dc->res_pool->pipe_count; ++i) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + if (pipe_ctx->stream && pipe_ctx->plane_res.hubp->funcs->program_extended_blank + && pipe_ctx->stream->adjust.v_total_min == pipe_ctx->stream->adjust.v_total_max + && pipe_ctx->stream->adjust.v_total_max > pipe_ctx->stream->timing.v_total) + pipe_ctx->plane_res.hubp->funcs->program_extended_blank(pipe_ctx->plane_res.hubp, + pipe_ctx->dlg_regs.optimized_min_dst_y_next_start); + } + } /* increase compbuf size */ if (hubbub->funcs->program_compbuf_size) hubbub->funcs->program_compbuf_size(hubbub, context->bw_ctx.bw.dcn.compbuf_size_kb, true); diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c index d473708d5399..7802d603f796 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c @@ -1976,7 +1976,6 @@ int dcn20_validate_apply_pipe_split_flags( /*If need split for odm but 4 way split already*/ if (split[i] == 2 && ((pipe->prev_odm_pipe && !pipe->prev_odm_pipe->prev_odm_pipe) || !pipe->next_odm_pipe)) { - ASSERT(0); /* NOT expected yet */ merge[i] = true; /* 4 -> 2 ODM */ } else if (split[i] == 0 && pipe->prev_odm_pipe) { ASSERT(0); /* NOT expected yet */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c index 612732656772..3fe4bfbb98a0 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c @@ -644,7 +644,7 @@ static const struct dc_debug_options debug_defaults_drv = { .clock_trace = true, .disable_pplib_clock_request = true, .min_disp_clk_khz = 100000, - .pipe_split_policy = MPC_SPLIT_DYNAMIC, + .pipe_split_policy = MPC_SPLIT_AVOID_MULT_DISP, .force_single_disp_pipe_split = false, .disable_dcc = DCC_ENABLE, .vsr_support = true, diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c index ed0a0e5fd805..f61ec8763844 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c @@ -547,6 +547,9 @@ void dcn30_init_hw(struct dc *dc) /* we want to turn off all dp displays before doing detection */ dc_link_blank_all_dp_displays(dc); + if (hws->funcs.enable_power_gating_plane) + hws->funcs.enable_power_gating_plane(dc->hwseq, true); + /* If taking control over from VBIOS, we may want to optimize our first * mode set, so we need to skip powering down pipes until we know which * pipes we want to use. @@ -624,8 +627,6 @@ void dcn30_init_hw(struct dc *dc) REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); } - if (hws->funcs.enable_power_gating_plane) - hws->funcs.enable_power_gating_plane(dc->hwseq, true); if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks) dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub); diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c index 3e6d6ebd199e..51c5f3685470 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c @@ -1042,5 +1042,7 @@ void hubbub31_construct(struct dcn20_hubbub *hubbub31, hubbub31->detile_buf_size = det_size_kb * 1024; hubbub31->pixel_chunk_size = pixel_chunk_size_kb * 1024; hubbub31->crb_size_segs = config_return_buffer_size_kb / DCN31_CRB_SEGMENT_SIZE_KB; + + hubbub31->debug_test_index_pstate = 0x6; } diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubp.c index 53b792b997b7..8ae6117953ca 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubp.c @@ -54,6 +54,13 @@ void hubp31_soft_reset(struct hubp *hubp, bool reset) REG_UPDATE(DCHUBP_CNTL, HUBP_SOFT_RESET, reset); } +void hubp31_program_extended_blank(struct hubp *hubp, unsigned int min_dst_y_next_start_optimized) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + + REG_SET(BLANK_OFFSET_1, 0, MIN_DST_Y_NEXT_START, min_dst_y_next_start_optimized); +} + static struct hubp_funcs dcn31_hubp_funcs = { .hubp_enable_tripleBuffer = hubp2_enable_triplebuffer, .hubp_is_triplebuffer_enabled = hubp2_is_triplebuffer_enabled, @@ -80,6 +87,7 @@ static struct hubp_funcs dcn31_hubp_funcs = { .set_unbounded_requesting = hubp31_set_unbounded_requesting, .hubp_soft_reset = hubp31_soft_reset, .hubp_in_blank = hubp1_in_blank, + .program_extended_blank = hubp31_program_extended_blank, }; bool hubp31_construct( diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c index 4be228680909..631d8ac63aa4 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c @@ -199,6 +199,9 @@ void dcn31_init_hw(struct dc *dc) /* we want to turn off all dp displays before doing detection */ dc_link_blank_all_dp_displays(dc); + if (hws->funcs.enable_power_gating_plane) + hws->funcs.enable_power_gating_plane(dc->hwseq, true); + /* If taking control over from VBIOS, we may want to optimize our first * mode set, so we need to skip powering down pipes until we know which * pipes we want to use. @@ -248,8 +251,6 @@ void dcn31_init_hw(struct dc *dc) REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); } - if (hws->funcs.enable_power_gating_plane) - hws->funcs.enable_power_gating_plane(dc->hwseq, true); if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks) dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub); @@ -338,20 +339,20 @@ void dcn31_enable_power_gating_plane( bool enable) { bool force_on = true; /* disable power gating */ + uint32_t org_ip_request_cntl = 0; if (enable && !hws->ctx->dc->debug.disable_hubp_power_gate) force_on = false; + REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); + if (org_ip_request_cntl == 0) + REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); /* DCHUBP0/1/2/3/4/5 */ REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); - REG_WAIT(DOMAIN0_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, force_on, 1, 1000); REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); - REG_WAIT(DOMAIN2_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, force_on, 1, 1000); /* DPP0/1/2/3/4/5 */ REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); - REG_WAIT(DOMAIN1_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, force_on, 1, 1000); REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); - REG_WAIT(DOMAIN3_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, force_on, 1, 1000); force_on = true; /* disable power gating */ if (enable && !hws->ctx->dc->debug.disable_dsc_power_gate) @@ -359,11 +360,11 @@ void dcn31_enable_power_gating_plane( /* DCS0/1/2/3/4/5 */ REG_UPDATE(DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); - REG_WAIT(DOMAIN16_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, force_on, 1, 1000); REG_UPDATE(DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); - REG_WAIT(DOMAIN17_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, force_on, 1, 1000); REG_UPDATE(DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on); - REG_WAIT(DOMAIN18_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, force_on, 1, 1000); + + if (org_ip_request_cntl == 0) + REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); } void dcn31_update_info_frame(struct pipe_ctx *pipe_ctx) diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.c index 8afe2130d7c5..e05527a3a8ba 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.c @@ -124,7 +124,6 @@ static bool optc31_enable_crtc(struct timing_generator *optc) static bool optc31_disable_crtc(struct timing_generator *optc) { struct optc *optc1 = DCN10TG_FROM_TG(optc); - /* disable otg request until end of the first line * in the vertical blank region */ @@ -138,6 +137,7 @@ static bool optc31_disable_crtc(struct timing_generator *optc) REG_WAIT(OTG_CLOCK_CONTROL, OTG_BUSY, 0, 1, 100000); + optc1_clear_optc_underflow(optc); return true; } @@ -158,6 +158,9 @@ static bool optc31_immediate_disable_crtc(struct timing_generator *optc) OTG_BUSY, 0, 1, 100000); + /* clear the false state */ + optc1_clear_optc_underflow(optc); + return true; } diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c index 89b7b6b7254a..63934ecf6be8 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c @@ -2032,7 +2032,9 @@ bool dcn31_validate_bandwidth(struct dc *dc, BW_VAL_TRACE_COUNT(); + DC_FP_START(); out = dcn30_internal_validate_bw(dc, context, pipes, &pipe_cnt, &vlevel, fast_validate); + DC_FP_END(); // Disable fast_validate to set min dcfclk in alculate_wm_and_dlg if (pipe_cnt == 0) @@ -2232,6 +2234,7 @@ static bool dcn31_resource_construct( dc->caps.extended_aux_timeout_support = true; dc->caps.dmcub_support = true; dc->caps.is_apu = true; + dc->caps.zstate_support = true; /* Color pipeline capabilities */ dc->caps.color.dpp.dcn_arch = 1; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c index 2f6122153bdb..f93af45aeab4 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c @@ -722,8 +722,10 @@ static enum dcn_zstate_support_state decide_zstate_support(struct dc *dc, struc { int plane_count; int i; + unsigned int optimized_min_dst_y_next_start_us; plane_count = 0; + optimized_min_dst_y_next_start_us = 0; for (i = 0; i < dc->res_pool->pipe_count; i++) { if (context->res_ctx.pipe_ctx[i].plane_state) plane_count++; @@ -744,11 +746,22 @@ static enum dcn_zstate_support_state decide_zstate_support(struct dc *dc, struc struct dc_link *link = context->streams[0]->sink->link; struct dc_stream_status *stream_status = &context->stream_status[0]; + if (dc_extended_blank_supported(dc)) { + for (i = 0; i < dc->res_pool->pipe_count; i++) { + if (context->res_ctx.pipe_ctx[i].stream == context->streams[0] + && context->res_ctx.pipe_ctx[i].stream->adjust.v_total_min == context->res_ctx.pipe_ctx[i].stream->adjust.v_total_max + && context->res_ctx.pipe_ctx[i].stream->adjust.v_total_min > context->res_ctx.pipe_ctx[i].stream->timing.v_total) { + optimized_min_dst_y_next_start_us = + context->res_ctx.pipe_ctx[i].dlg_regs.optimized_min_dst_y_next_start_us; + break; + } + } + } /* zstate only supported on PWRSEQ0 and when there's <2 planes*/ if (link->link_index != 0 || stream_status->plane_count > 1) return DCN_ZSTATE_SUPPORT_DISALLOW; - if (context->bw_ctx.dml.vba.StutterPeriod > 5000.0) + if (context->bw_ctx.dml.vba.StutterPeriod > 5000.0 || optimized_min_dst_y_next_start_us > 5000) return DCN_ZSTATE_SUPPORT_ALLOW; else if (link->psr_settings.psr_version == DC_PSR_VERSION_1 && !dc->debug.disable_psr) return DCN_ZSTATE_SUPPORT_ALLOW_Z10_ONLY; @@ -786,8 +799,6 @@ void dcn20_calculate_dlg_params( != dm_dram_clock_change_unsupported; context->bw_ctx.bw.dcn.clk.dppclk_khz = 0; - context->bw_ctx.bw.dcn.clk.zstate_support = decide_zstate_support(dc, context); - context->bw_ctx.bw.dcn.clk.dtbclk_en = is_dtbclk_required(dc, context); if (context->bw_ctx.bw.dcn.clk.dispclk_khz < dc->debug.min_disp_clk_khz) @@ -843,6 +854,7 @@ void dcn20_calculate_dlg_params( &pipes[pipe_idx].pipe); pipe_idx++; } + context->bw_ctx.bw.dcn.clk.zstate_support = decide_zstate_support(dc, context); } static void swizzle_to_dml_params( diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_rq_dlg_calc_31.c b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_rq_dlg_calc_31.c index e0fecf127bd5..53d760e169e6 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_rq_dlg_calc_31.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_rq_dlg_calc_31.c @@ -1055,6 +1055,7 @@ static void dml_rq_dlg_get_dlg_params( float vba__refcyc_per_req_delivery_pre_l = get_refcyc_per_req_delivery_pre_l_in_us(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz; // From VBA float vba__refcyc_per_req_delivery_l = get_refcyc_per_req_delivery_l_in_us(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz; // From VBA + int blank_lines; memset(disp_dlg_regs, 0, sizeof(*disp_dlg_regs)); memset(disp_ttu_regs, 0, sizeof(*disp_ttu_regs)); @@ -1080,6 +1081,18 @@ static void dml_rq_dlg_get_dlg_params( dlg_vblank_start = interlaced ? (vblank_start / 2) : vblank_start; disp_dlg_regs->min_dst_y_next_start = (unsigned int) (((double) dlg_vblank_start) * dml_pow(2, 2)); + blank_lines = (dst->vblank_end + dst->vtotal_min - dst->vblank_start - dst->vstartup_start - 1); + if (blank_lines < 0) + blank_lines = 0; + if (blank_lines != 0) { + disp_dlg_regs->optimized_min_dst_y_next_start_us = + ((unsigned int) blank_lines * dst->hactive) / (unsigned int) dst->pixel_rate_mhz; + disp_dlg_regs->optimized_min_dst_y_next_start = + (unsigned int)(((double) (dlg_vblank_start + blank_lines)) * dml_pow(2, 2)); + } else { + // use unoptimized value + disp_dlg_regs->optimized_min_dst_y_next_start = disp_dlg_regs->min_dst_y_next_start; + } ASSERT(disp_dlg_regs->min_dst_y_next_start < (unsigned int)dml_pow(2, 18)); dml_print("DML_DLG: %s: min_ttu_vblank (us) = %3.2f\n", __func__, min_ttu_vblank); diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h index 59f0a61c33cf..2df660cd8801 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h @@ -446,6 +446,8 @@ struct _vcs_dpi_display_dlg_regs_st { unsigned int refcyc_h_blank_end; unsigned int dlg_vblank_end; unsigned int min_dst_y_next_start; + unsigned int optimized_min_dst_y_next_start; + unsigned int optimized_min_dst_y_next_start_us; unsigned int refcyc_per_htotal; unsigned int refcyc_x_after_scaler; unsigned int dst_y_after_scaler; diff --git a/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c b/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c index efc2339f1fa0..4385d19bc489 100644 --- a/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c +++ b/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c @@ -864,11 +864,11 @@ static bool setup_dsc_config( min_slices_h = inc_num_slices(dsc_common_caps.slice_caps, min_slices_h); } + is_dsc_possible = (min_slices_h <= max_slices_h); + if (pic_width % min_slices_h != 0) min_slices_h = 0; // DSC TODO: Maybe try increasing the number of slices first? - is_dsc_possible = (min_slices_h <= max_slices_h); - if (min_slices_h == 0 && max_slices_h == 0) is_dsc_possible = false; diff --git a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h index ab9939db8cea..44f167d2584f 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h @@ -33,6 +33,7 @@ #define MAX_MTP_SLOT_COUNT 64 #define DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE 0x50 #define TRAINING_AUX_RD_INTERVAL 100 //us +#define LINK_AUX_WAKE_TIMEOUT_MS 1500 // Timeout when trying to wake unresponsive DPRX. struct dc_link; struct dc_stream_state; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h index e45b7993c5c5..ad69d78c4ac3 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h @@ -195,6 +195,9 @@ struct hubp_funcs { void (*hubp_set_flip_int)(struct hubp *hubp); + void (*program_extended_blank)(struct hubp *hubp, + unsigned int min_dst_y_next_start_optimized); + void (*hubp_wait_pipe_read_start)(struct hubp *hubp); }; diff --git a/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c b/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c index b691aa45e84f..79bc207415bc 100644 --- a/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c +++ b/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c @@ -100,7 +100,8 @@ enum vsc_packet_revision { //PB7 = MD0 #define MASK_VTEM_MD0__VRR_EN 0x01 #define MASK_VTEM_MD0__M_CONST 0x02 -#define MASK_VTEM_MD0__RESERVED2 0x0C +#define MASK_VTEM_MD0__QMS_EN 0x04 +#define MASK_VTEM_MD0__RESERVED2 0x08 #define MASK_VTEM_MD0__FVA_FACTOR_M1 0xF0 //MD1 @@ -109,7 +110,7 @@ enum vsc_packet_revision { //MD2 #define MASK_VTEM_MD2__BASE_REFRESH_RATE_98 0x03 #define MASK_VTEM_MD2__RB 0x04 -#define MASK_VTEM_MD2__RESERVED3 0xF8 +#define MASK_VTEM_MD2__NEXT_TFR 0xF8 //MD3 #define MASK_VTEM_MD3__BASE_REFRESH_RATE_07 0xFF diff --git a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c index 89fbee568be4..5504d81c77b7 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c @@ -173,6 +173,17 @@ bool amdgpu_dpm_is_baco_supported(struct amdgpu_device *adev) if (!pp_funcs || !pp_funcs->get_asic_baco_capability) return false; + /* Don't use baco for reset in S3. + * This is a workaround for some platforms + * where entering BACO during suspend + * seems to cause reboots or hangs. + * This might be related to the fact that BACO controls + * power to the whole GPU including devices like audio and USB. + * Powering down/up everything may adversely affect these other + * devices. Needs more investigation. + */ + if (adev->in_s3) + return false; mutex_lock(&adev->pm.mutex); @@ -500,6 +511,9 @@ int amdgpu_dpm_send_hbm_bad_pages_num(struct amdgpu_device *adev, uint32_t size) struct smu_context *smu = adev->powerplay.pp_handle; int ret = 0; + if (!is_support_sw_smu(adev)) + return -EOPNOTSUPP; + mutex_lock(&adev->pm.mutex); ret = smu_send_hbm_bad_pages_num(smu, size); mutex_unlock(&adev->pm.mutex); @@ -512,6 +526,9 @@ int amdgpu_dpm_send_hbm_bad_channel_flag(struct amdgpu_device *adev, uint32_t si struct smu_context *smu = adev->powerplay.pp_handle; int ret = 0; + if (!is_support_sw_smu(adev)) + return -EOPNOTSUPP; + mutex_lock(&adev->pm.mutex); ret = smu_send_hbm_bad_channel_flag(smu, size); mutex_unlock(&adev->pm.mutex); diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c index 9ddd8491ff00..ede71de2343d 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.c @@ -773,13 +773,13 @@ static int smu10_dpm_force_dpm_level(struct pp_hwmgr *hwmgr, smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetHardMinFclkByFreq, hwmgr->display_config->num_display > 3 ? - data->clock_vol_info.vdd_dep_on_fclk->entries[0].clk : + (data->clock_vol_info.vdd_dep_on_fclk->entries[0].clk / 100) : min_mclk, NULL); smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetHardMinSocclkByFreq, - data->clock_vol_info.vdd_dep_on_socclk->entries[0].clk, + data->clock_vol_info.vdd_dep_on_socclk->entries[0].clk / 100, NULL); smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetHardMinVcn, @@ -792,11 +792,11 @@ static int smu10_dpm_force_dpm_level(struct pp_hwmgr *hwmgr, NULL); smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetSoftMaxFclkByFreq, - data->clock_vol_info.vdd_dep_on_fclk->entries[index_fclk].clk, + data->clock_vol_info.vdd_dep_on_fclk->entries[index_fclk].clk / 100, NULL); smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetSoftMaxSocclkByFreq, - data->clock_vol_info.vdd_dep_on_socclk->entries[index_socclk].clk, + data->clock_vol_info.vdd_dep_on_socclk->entries[index_socclk].clk / 100, NULL); smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetSoftMaxVcn, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c index 7bfac029e513..b81711c4ff33 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c @@ -991,7 +991,7 @@ static int smu_v13_0_5_set_performance_level(struct smu_context *smu, return -EINVAL; } - if (sclk_min && sclk_max) { + if (sclk_min && sclk_max && smu_v13_0_5_clk_dpm_is_enabled(smu, SMU_SCLK)) { ret = smu_v13_0_5_set_soft_freq_limited_range(smu, SMU_SCLK, sclk_min, diff --git a/drivers/gpu/drm/dp/drm_dp.c b/drivers/gpu/drm/dp/drm_dp.c index b76260ea11ce..2a1f5ff6633c 100644 --- a/drivers/gpu/drm/dp/drm_dp.c +++ b/drivers/gpu/drm/dp/drm_dp.c @@ -2413,9 +2413,36 @@ int drm_dp_dsc_sink_supported_input_bpcs(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_S } EXPORT_SYMBOL(drm_dp_dsc_sink_supported_input_bpcs); +static int drm_dp_read_lttpr_regs(struct drm_dp_aux *aux, + const u8 dpcd[DP_RECEIVER_CAP_SIZE], int address, + u8 *buf, int buf_size) +{ + /* + * At least the DELL P2715Q monitor with a DPCD_REV < 0x14 returns + * corrupted values when reading from the 0xF0000- range with a block + * size bigger than 1. + */ + int block_size = dpcd[DP_DPCD_REV] < 0x14 ? 1 : buf_size; + int offset; + int ret; + + for (offset = 0; offset < buf_size; offset += block_size) { + ret = drm_dp_dpcd_read(aux, + address + offset, + &buf[offset], block_size); + if (ret < 0) + return ret; + + WARN_ON(ret != block_size); + } + + return 0; +} + /** * drm_dp_read_lttpr_common_caps - read the LTTPR common capabilities * @aux: DisplayPort AUX channel + * @dpcd: DisplayPort configuration data * @caps: buffer to return the capability info in * * Read capabilities common to all LTTPRs. @@ -2423,25 +2450,19 @@ EXPORT_SYMBOL(drm_dp_dsc_sink_supported_input_bpcs); * Returns 0 on success or a negative error code on failure. */ int drm_dp_read_lttpr_common_caps(struct drm_dp_aux *aux, + const u8 dpcd[DP_RECEIVER_CAP_SIZE], u8 caps[DP_LTTPR_COMMON_CAP_SIZE]) { - int ret; - - ret = drm_dp_dpcd_read(aux, - DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV, - caps, DP_LTTPR_COMMON_CAP_SIZE); - if (ret < 0) - return ret; - - WARN_ON(ret != DP_LTTPR_COMMON_CAP_SIZE); - - return 0; + return drm_dp_read_lttpr_regs(aux, dpcd, + DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV, + caps, DP_LTTPR_COMMON_CAP_SIZE); } EXPORT_SYMBOL(drm_dp_read_lttpr_common_caps); /** * drm_dp_read_lttpr_phy_caps - read the capabilities for a given LTTPR PHY * @aux: DisplayPort AUX channel + * @dpcd: DisplayPort configuration data * @dp_phy: LTTPR PHY to read the capabilities for * @caps: buffer to return the capability info in * @@ -2450,20 +2471,13 @@ EXPORT_SYMBOL(drm_dp_read_lttpr_common_caps); * Returns 0 on success or a negative error code on failure. */ int drm_dp_read_lttpr_phy_caps(struct drm_dp_aux *aux, + const u8 dpcd[DP_RECEIVER_CAP_SIZE], enum drm_dp_phy dp_phy, u8 caps[DP_LTTPR_PHY_CAP_SIZE]) { - int ret; - - ret = drm_dp_dpcd_read(aux, - DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER(dp_phy), - caps, DP_LTTPR_PHY_CAP_SIZE); - if (ret < 0) - return ret; - - WARN_ON(ret != DP_LTTPR_PHY_CAP_SIZE); - - return 0; + return drm_dp_read_lttpr_regs(aux, dpcd, + DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER(dp_phy), + caps, DP_LTTPR_PHY_CAP_SIZE); } EXPORT_SYMBOL(drm_dp_read_lttpr_phy_caps); diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c index 026e4e29a0f3..f4df344509a8 100644 --- a/drivers/gpu/drm/drm_of.c +++ b/drivers/gpu/drm/drm_of.c @@ -214,6 +214,29 @@ int drm_of_encoder_active_endpoint(struct device_node *node, } EXPORT_SYMBOL_GPL(drm_of_encoder_active_endpoint); +static int find_panel_or_bridge(struct device_node *node, + struct drm_panel **panel, + struct drm_bridge **bridge) +{ + if (panel) { + *panel = of_drm_find_panel(node); + if (!IS_ERR(*panel)) + return 0; + + /* Clear the panel pointer in case of error. */ + *panel = NULL; + } + + /* No panel found yet, check for a bridge next. */ + if (bridge) { + *bridge = of_drm_find_bridge(node); + if (*bridge) + return 0; + } + + return -EPROBE_DEFER; +} + /** * drm_of_find_panel_or_bridge - return connected panel or bridge device * @np: device tree node containing encoder output ports @@ -236,66 +259,44 @@ int drm_of_find_panel_or_bridge(const struct device_node *np, struct drm_panel **panel, struct drm_bridge **bridge) { - int ret = -EPROBE_DEFER; - struct device_node *remote; + struct device_node *node; + int ret; if (!panel && !bridge) return -EINVAL; + if (panel) *panel = NULL; - - /** - * Devices can also be child nodes when we also control that device - * through the upstream device (ie, MIPI-DCS for a MIPI-DSI device). - * - * Lookup for a child node of the given parent that isn't either port - * or ports. - */ - for_each_available_child_of_node(np, remote) { - if (of_node_name_eq(remote, "port") || - of_node_name_eq(remote, "ports")) - continue; - - goto of_find_panel_or_bridge; + if (bridge) + *bridge = NULL; + + /* Check for a graph on the device node first. */ + if (of_graph_is_present(np)) { + node = of_graph_get_remote_node(np, port, endpoint); + if (node) { + ret = find_panel_or_bridge(node, panel, bridge); + of_node_put(node); + + if (!ret) + return 0; + } } - /* - * of_graph_get_remote_node() produces a noisy error message if port - * node isn't found and the absence of the port is a legit case here, - * so at first we silently check whether graph presents in the - * device-tree node. - */ - if (!of_graph_is_present(np)) - return -ENODEV; - - remote = of_graph_get_remote_node(np, port, endpoint); - -of_find_panel_or_bridge: - if (!remote) - return -ENODEV; + /* Otherwise check for any child node other than port/ports. */ + for_each_available_child_of_node(np, node) { + if (of_node_name_eq(node, "port") || + of_node_name_eq(node, "ports")) + continue; - if (panel) { - *panel = of_drm_find_panel(remote); - if (!IS_ERR(*panel)) - ret = 0; - else - *panel = NULL; - } - - /* No panel found yet, check for a bridge next. */ - if (bridge) { - if (ret) { - *bridge = of_drm_find_bridge(remote); - if (*bridge) - ret = 0; - } else { - *bridge = NULL; - } + ret = find_panel_or_bridge(node, panel, bridge); + of_node_put(node); + /* Stop at the first found occurrence. */ + if (!ret) + return 0; } - of_node_put(remote); - return ret; + return -EPROBE_DEFER; } EXPORT_SYMBOL_GPL(drm_of_find_panel_or_bridge); diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 7df74a71d454..815589f8658c 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -213,6 +213,7 @@ i915-y += \ display/intel_cursor.o \ display/intel_display.o \ display/intel_display_power.o \ + display/intel_display_power_well.o \ display/intel_dmc.o \ display/intel_dpio_phy.o \ display/intel_dpll.o \ diff --git a/drivers/gpu/drm/i915/display/g4x_dp.c b/drivers/gpu/drm/i915/display/g4x_dp.c index f67bbaaad8e0..16bb21ad898b 100644 --- a/drivers/gpu/drm/i915/display/g4x_dp.c +++ b/drivers/gpu/drm/i915/display/g4x_dp.c @@ -5,6 +5,8 @@ * DisplayPort support for G4x,ILK,SNB,IVB,VLV,CHV (HSW+ handled by the DDI code). */ +#include <linux/string_helpers.h> + #include "g4x_dp.h" #include "intel_audio.h" #include "intel_backlight.h" @@ -22,58 +24,37 @@ #include "intel_pps.h" #include "vlv_sideband.h" -struct dp_link_dpll { - int clock; - struct dpll dpll; +static const struct dpll g4x_dpll[] = { + { .dot = 162000, .p1 = 2, .p2 = 10, .n = 2, .m1 = 23, .m2 = 8, }, + { .dot = 270000, .p1 = 1, .p2 = 10, .n = 1, .m1 = 14, .m2 = 2, }, }; -static const struct dp_link_dpll g4x_dpll[] = { - { 162000, - { .p1 = 2, .p2 = 10, .n = 2, .m1 = 23, .m2 = 8 } }, - { 270000, - { .p1 = 1, .p2 = 10, .n = 1, .m1 = 14, .m2 = 2 } } +static const struct dpll pch_dpll[] = { + { .dot = 162000, .p1 = 2, .p2 = 10, .n = 1, .m1 = 12, .m2 = 9, }, + { .dot = 270000, .p1 = 1, .p2 = 10, .n = 2, .m1 = 14, .m2 = 8, }, }; -static const struct dp_link_dpll pch_dpll[] = { - { 162000, - { .p1 = 2, .p2 = 10, .n = 1, .m1 = 12, .m2 = 9 } }, - { 270000, - { .p1 = 1, .p2 = 10, .n = 2, .m1 = 14, .m2 = 8 } } +static const struct dpll vlv_dpll[] = { + { .dot = 162000, .p1 = 3, .p2 = 2, .n = 5, .m1 = 3, .m2 = 81, }, + { .dot = 270000, .p1 = 2, .p2 = 2, .n = 1, .m1 = 2, .m2 = 27, }, }; -static const struct dp_link_dpll vlv_dpll[] = { - { 162000, - { .p1 = 3, .p2 = 2, .n = 5, .m1 = 3, .m2 = 81 } }, - { 270000, - { .p1 = 2, .p2 = 2, .n = 1, .m1 = 2, .m2 = 27 } } -}; - -/* - * CHV supports eDP 1.4 that have more link rates. - * Below only provides the fixed rate but exclude variable rate. - */ -static const struct dp_link_dpll chv_dpll[] = { - /* - * CHV requires to program fractional division for m2. - * m2 is stored in fixed point format using formula below - * (m2_int << 22) | m2_fraction - */ - { 162000, /* m2_int = 32, m2_fraction = 1677722 */ - { .p1 = 4, .p2 = 2, .n = 1, .m1 = 2, .m2 = 0x819999a } }, - { 270000, /* m2_int = 27, m2_fraction = 0 */ - { .p1 = 4, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x6c00000 } }, +static const struct dpll chv_dpll[] = { + /* m2 is .22 binary fixed point */ + { .dot = 162000, .p1 = 4, .p2 = 2, .n = 1, .m1 = 2, .m2 = 0x819999a /* 32.4 */ }, + { .dot = 270000, .p1 = 4, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x6c00000 /* 27.0 */ }, }; const struct dpll *vlv_get_dpll(struct drm_i915_private *i915) { - return IS_CHERRYVIEW(i915) ? &chv_dpll[0].dpll : &vlv_dpll[0].dpll; + return IS_CHERRYVIEW(i915) ? &chv_dpll[0] : &vlv_dpll[0]; } void g4x_dp_set_clock(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - const struct dp_link_dpll *divisor = NULL; + const struct dpll *divisor = NULL; int i, count = 0; if (IS_G4X(dev_priv)) { @@ -92,8 +73,8 @@ void g4x_dp_set_clock(struct intel_encoder *encoder, if (divisor && count) { for (i = 0; i < count; i++) { - if (pipe_config->port_clock == divisor[i].clock) { - pipe_config->dpll = divisor[i].dpll; + if (pipe_config->port_clock == divisor[i].dot) { + pipe_config->dpll = divisor[i]; pipe_config->clock_set = true; break; } @@ -192,7 +173,7 @@ static void assert_dp_port(struct intel_dp *intel_dp, bool state) I915_STATE_WARN(cur_state != state, "[ENCODER:%d:%s] state assertion failure (expected %s, current %s)\n", dig_port->base.base.base.id, dig_port->base.base.name, - onoff(state), onoff(cur_state)); + str_on_off(state), str_on_off(cur_state)); } #define assert_dp_port_disabled(d) assert_dp_port((d), false) @@ -202,7 +183,7 @@ static void assert_edp_pll(struct drm_i915_private *dev_priv, bool state) I915_STATE_WARN(cur_state != state, "eDP PLL state assertion failure (expected %s, current %s)\n", - onoff(state), onoff(cur_state)); + str_on_off(state), str_on_off(cur_state)); } #define assert_edp_pll_enabled(d) assert_edp_pll((d), true) #define assert_edp_pll_disabled(d) assert_edp_pll((d), false) @@ -514,9 +495,7 @@ static void intel_disable_dp(struct intel_atomic_state *state, intel_dp->link_trained = false; - if (old_crtc_state->has_audio) - intel_audio_codec_disable(encoder, - old_crtc_state, old_conn_state); + intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); /* * Make sure the panel is off before trying to change the mode. @@ -677,9 +656,7 @@ static void intel_enable_dp(struct intel_atomic_state *state, { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc); u32 dp_reg = intel_de_read(dev_priv, intel_dp->output_reg); - enum pipe pipe = crtc->pipe; intel_wakeref_t wakeref; if (drm_WARN_ON(&dev_priv->drm, dp_reg & DP_PORT_EN)) @@ -713,11 +690,7 @@ static void intel_enable_dp(struct intel_atomic_state *state, intel_dp_start_link_train(intel_dp, pipe_config); intel_dp_stop_link_train(intel_dp, pipe_config); - if (pipe_config->has_audio) { - drm_dbg(&dev_priv->drm, "Enabling DP audio on pipe %c\n", - pipe_name(pipe)); - intel_audio_codec_enable(encoder, pipe_config, conn_state); - } + intel_audio_codec_enable(encoder, pipe_config, conn_state); } static void g4x_enable_dp(struct intel_atomic_state *state, diff --git a/drivers/gpu/drm/i915/display/g4x_hdmi.c b/drivers/gpu/drm/i915/display/g4x_hdmi.c index 06e00b1eaa7c..8bfef08b7c43 100644 --- a/drivers/gpu/drm/i915/display/g4x_hdmi.c +++ b/drivers/gpu/drm/i915/display/g4x_hdmi.c @@ -143,19 +143,6 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder, &pipe_config->infoframes.hdmi); } -static void intel_enable_hdmi_audio(struct intel_encoder *encoder, - const struct intel_crtc_state *pipe_config, - const struct drm_connector_state *conn_state) -{ - struct drm_i915_private *i915 = to_i915(encoder->base.dev); - struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc); - - drm_WARN_ON(&i915->drm, !pipe_config->has_hdmi_sink); - drm_dbg_kms(&i915->drm, "Enabling HDMI audio on pipe %c\n", - pipe_name(crtc->pipe)); - intel_audio_codec_enable(encoder, pipe_config, conn_state); -} - static void g4x_enable_hdmi(struct intel_atomic_state *state, struct intel_encoder *encoder, const struct intel_crtc_state *pipe_config, @@ -175,8 +162,9 @@ static void g4x_enable_hdmi(struct intel_atomic_state *state, intel_de_write(dev_priv, intel_hdmi->hdmi_reg, temp); intel_de_posting_read(dev_priv, intel_hdmi->hdmi_reg); - if (pipe_config->has_audio) - intel_enable_hdmi_audio(encoder, pipe_config, conn_state); + drm_WARN_ON(&dev_priv->drm, pipe_config->has_audio && + !pipe_config->has_hdmi_sink); + intel_audio_codec_enable(encoder, pipe_config, conn_state); } static void ibx_enable_hdmi(struct intel_atomic_state *state, @@ -227,8 +215,9 @@ static void ibx_enable_hdmi(struct intel_atomic_state *state, intel_de_posting_read(dev_priv, intel_hdmi->hdmi_reg); } - if (pipe_config->has_audio) - intel_enable_hdmi_audio(encoder, pipe_config, conn_state); + drm_WARN_ON(&dev_priv->drm, pipe_config->has_audio && + !pipe_config->has_hdmi_sink); + intel_audio_codec_enable(encoder, pipe_config, conn_state); } static void cpt_enable_hdmi(struct intel_atomic_state *state, @@ -281,8 +270,9 @@ static void cpt_enable_hdmi(struct intel_atomic_state *state, intel_de_read(dev_priv, TRANS_CHICKEN1(pipe)) & ~TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE); } - if (pipe_config->has_audio) - intel_enable_hdmi_audio(encoder, pipe_config, conn_state); + drm_WARN_ON(&dev_priv->drm, pipe_config->has_audio && + !pipe_config->has_hdmi_sink); + intel_audio_codec_enable(encoder, pipe_config, conn_state); } static void vlv_enable_hdmi(struct intel_atomic_state *state, @@ -356,9 +346,7 @@ static void g4x_disable_hdmi(struct intel_atomic_state *state, const struct intel_crtc_state *old_crtc_state, const struct drm_connector_state *old_conn_state) { - if (old_crtc_state->has_audio) - intel_audio_codec_disable(encoder, - old_crtc_state, old_conn_state); + intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); intel_disable_hdmi(state, encoder, old_crtc_state, old_conn_state); } @@ -368,9 +356,7 @@ static void pch_disable_hdmi(struct intel_atomic_state *state, const struct intel_crtc_state *old_crtc_state, const struct drm_connector_state *old_conn_state) { - if (old_crtc_state->has_audio) - intel_audio_codec_disable(encoder, - old_crtc_state, old_conn_state); + intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); } static void pch_post_disable_hdmi(struct intel_atomic_state *state, diff --git a/drivers/gpu/drm/i915/display/i9xx_plane.c b/drivers/gpu/drm/i915/display/i9xx_plane.c index a87b65cd41fd..7fe1a4e57654 100644 --- a/drivers/gpu/drm/i915/display/i9xx_plane.c +++ b/drivers/gpu/drm/i915/display/i9xx_plane.c @@ -418,9 +418,6 @@ static void i9xx_plane_update_noarm(struct intel_plane *plane, { struct drm_i915_private *dev_priv = to_i915(plane->base.dev); enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; - unsigned long irqflags; - - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); intel_de_write_fw(dev_priv, DSPSTRIDE(i9xx_plane), plane_state->view.color_plane[0].mapping_stride); @@ -441,8 +438,6 @@ static void i9xx_plane_update_noarm(struct intel_plane *plane, intel_de_write_fw(dev_priv, DSPSIZE(i9xx_plane), DISP_HEIGHT(crtc_h - 1) | DISP_WIDTH(crtc_w - 1)); } - - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } static void i9xx_plane_update_arm(struct intel_plane *plane, @@ -454,7 +449,6 @@ static void i9xx_plane_update_arm(struct intel_plane *plane, int x = plane_state->view.color_plane[0].x; int y = plane_state->view.color_plane[0].y; u32 dspcntr, dspaddr_offset, linear_offset; - unsigned long irqflags; dspcntr = plane_state->ctl | i9xx_plane_ctl_crtc(crtc_state); @@ -465,8 +459,6 @@ static void i9xx_plane_update_arm(struct intel_plane *plane, else dspaddr_offset = linear_offset; - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); - if (IS_CHERRYVIEW(dev_priv) && i9xx_plane == PLANE_B) { int crtc_x = plane_state->uapi.dst.x1; int crtc_y = plane_state->uapi.dst.y1; @@ -496,14 +488,13 @@ static void i9xx_plane_update_arm(struct intel_plane *plane, * the control register just before the surface register. */ intel_de_write_fw(dev_priv, DSPCNTR(i9xx_plane), dspcntr); + if (DISPLAY_VER(dev_priv) >= 4) intel_de_write_fw(dev_priv, DSPSURF(i9xx_plane), intel_plane_ggtt_offset(plane_state) + dspaddr_offset); else intel_de_write_fw(dev_priv, DSPADDR(i9xx_plane), intel_plane_ggtt_offset(plane_state) + dspaddr_offset); - - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } static void i830_plane_update_arm(struct intel_plane *plane, @@ -525,7 +516,6 @@ static void i9xx_plane_disable_arm(struct intel_plane *plane, { struct drm_i915_private *dev_priv = to_i915(plane->base.dev); enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; - unsigned long irqflags; u32 dspcntr; /* @@ -540,15 +530,12 @@ static void i9xx_plane_disable_arm(struct intel_plane *plane, */ dspcntr = i9xx_plane_ctl_crtc(crtc_state); - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); - intel_de_write_fw(dev_priv, DSPCNTR(i9xx_plane), dspcntr); + if (DISPLAY_VER(dev_priv) >= 4) intel_de_write_fw(dev_priv, DSPSURF(i9xx_plane), 0); else intel_de_write_fw(dev_priv, DSPADDR(i9xx_plane), 0); - - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } static void @@ -561,16 +548,14 @@ g4x_primary_async_flip(struct intel_plane *plane, u32 dspcntr = plane_state->ctl | i9xx_plane_ctl_crtc(crtc_state); u32 dspaddr_offset = plane_state->view.color_plane[0].offset; enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; - unsigned long irqflags; if (async_flip) dspcntr |= DISP_ASYNC_FLIP; - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); intel_de_write_fw(dev_priv, DSPCNTR(i9xx_plane), dspcntr); + intel_de_write_fw(dev_priv, DSPSURF(i9xx_plane), intel_plane_ggtt_offset(plane_state) + dspaddr_offset); - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } static void @@ -582,12 +567,9 @@ vlv_primary_async_flip(struct intel_plane *plane, struct drm_i915_private *dev_priv = to_i915(plane->base.dev); u32 dspaddr_offset = plane_state->view.color_plane[0].offset; enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; - unsigned long irqflags; - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); intel_de_write_fw(dev_priv, DSPADDR_VLV(i9xx_plane), intel_plane_ggtt_offset(plane_state) + dspaddr_offset); - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } static void diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c index 13b07c6fd6be..084cc51d1c41 100644 --- a/drivers/gpu/drm/i915/display/icl_dsi.c +++ b/drivers/gpu/drm/i915/display/icl_dsi.c @@ -1967,6 +1967,8 @@ static void icl_dphy_param_init(struct intel_dsi *intel_dsi) static void icl_dsi_add_properties(struct intel_connector *connector) { + const struct drm_display_mode *fixed_mode = + intel_panel_preferred_fixed_mode(connector); u32 allowed_scalers; allowed_scalers = BIT(DRM_MODE_SCALE_ASPECT) | @@ -1979,9 +1981,9 @@ static void icl_dsi_add_properties(struct intel_connector *connector) connector->base.state->scaling_mode = DRM_MODE_SCALE_ASPECT; drm_connector_set_panel_orientation_with_quirk(&connector->base, - intel_dsi_get_panel_orientation(connector), - connector->panel.fixed_mode->hdisplay, - connector->panel.fixed_mode->vdisplay); + intel_dsi_get_panel_orientation(connector), + fixed_mode->hdisplay, + fixed_mode->vdisplay); } void icl_dsi_init(struct drm_i915_private *dev_priv) @@ -1991,7 +1993,6 @@ void icl_dsi_init(struct drm_i915_private *dev_priv) struct intel_encoder *encoder; struct intel_connector *intel_connector; struct drm_connector *connector; - struct drm_display_mode *fixed_mode; enum port port; if (!intel_bios_is_dsi_present(dev_priv, &port)) @@ -2048,15 +2049,16 @@ void icl_dsi_init(struct drm_i915_private *dev_priv) intel_connector_attach_encoder(intel_connector, encoder); mutex_lock(&dev->mode_config.mutex); - fixed_mode = intel_panel_vbt_fixed_mode(intel_connector); + intel_panel_add_vbt_lfp_fixed_mode(intel_connector); mutex_unlock(&dev->mode_config.mutex); - if (!fixed_mode) { + if (!intel_panel_preferred_fixed_mode(intel_connector)) { drm_err(&dev_priv->drm, "DSI fixed mode info missing\n"); goto err; } - intel_panel_init(&intel_connector->panel, fixed_mode, NULL); + intel_panel_init(intel_connector); + intel_backlight_setup(intel_connector, INVALID_PIPE); if (dev_priv->vbt.dsi.config->dual_link) diff --git a/drivers/gpu/drm/i915/display/intel_atomic_plane.c b/drivers/gpu/drm/i915/display/intel_atomic_plane.c index 03e86e836a17..efe8591619e3 100644 --- a/drivers/gpu/drm/i915/display/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/display/intel_atomic_plane.c @@ -181,29 +181,67 @@ unsigned int intel_plane_pixel_rate(const struct intel_crtc_state *crtc_state, } unsigned int intel_plane_data_rate(const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state) + const struct intel_plane_state *plane_state, + int color_plane) { const struct drm_framebuffer *fb = plane_state->hw.fb; - unsigned int cpp; - unsigned int pixel_rate; if (!plane_state->uapi.visible) return 0; - pixel_rate = intel_plane_pixel_rate(crtc_state, plane_state); + return intel_plane_pixel_rate(crtc_state, plane_state) * + fb->format->cpp[color_plane]; +} + +static bool +use_min_ddb(const struct intel_crtc_state *crtc_state, + struct intel_plane *plane) +{ + struct drm_i915_private *i915 = to_i915(plane->base.dev); + + return DISPLAY_VER(i915) >= 13 && + crtc_state->uapi.async_flip && + plane->async_flip; +} + +static unsigned int +intel_plane_relative_data_rate(const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state, + int color_plane) +{ + struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); + const struct drm_framebuffer *fb = plane_state->hw.fb; + int width, height; - cpp = fb->format->cpp[0]; + if (plane->id == PLANE_CURSOR) + return 0; + + if (!plane_state->uapi.visible) + return 0; /* - * Based on HSD#:1408715493 - * NV12 cpp == 4, P010 cpp == 8 - * - * FIXME what is the logic behind this? + * We calculate extra ddb based on ratio plane rate/total data rate + * in case, in some cases we should not allocate extra ddb for the plane, + * so do not count its data rate, if this is the case. */ - if (fb->format->is_yuv && fb->format->num_planes > 1) - cpp *= 4; + if (use_min_ddb(crtc_state, plane)) + return 0; + + /* + * Src coordinates are already rotated by 270 degrees for + * the 90/270 degree plane rotation cases (to match the + * GTT mapping), hence no need to account for rotation here. + */ + width = drm_rect_width(&plane_state->uapi.src) >> 16; + height = drm_rect_height(&plane_state->uapi.src) >> 16; + + /* UV plane does 1/2 pixel sub-sampling */ + if (color_plane == 1) { + width /= 2; + height /= 2; + } - return pixel_rate * cpp; + return width * height * fb->format->cpp[color_plane]; } int intel_plane_calc_min_cdclk(struct intel_atomic_state *state, @@ -326,6 +364,9 @@ void intel_plane_set_invisible(struct intel_crtc_state *crtc_state, crtc_state->nv12_planes &= ~BIT(plane->id); crtc_state->c8_planes &= ~BIT(plane->id); crtc_state->data_rate[plane->id] = 0; + crtc_state->data_rate_y[plane->id] = 0; + crtc_state->rel_data_rate[plane->id] = 0; + crtc_state->rel_data_rate_y[plane->id] = 0; crtc_state->min_cdclk[plane->id] = 0; plane_state->uapi.visible = false; @@ -551,8 +592,27 @@ int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_ if (new_plane_state->uapi.visible || old_plane_state->uapi.visible) new_crtc_state->update_planes |= BIT(plane->id); - new_crtc_state->data_rate[plane->id] = - intel_plane_data_rate(new_crtc_state, new_plane_state); + if (new_plane_state->uapi.visible && + intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier)) { + new_crtc_state->data_rate_y[plane->id] = + intel_plane_data_rate(new_crtc_state, new_plane_state, 0); + new_crtc_state->data_rate[plane->id] = + intel_plane_data_rate(new_crtc_state, new_plane_state, 1); + + new_crtc_state->rel_data_rate_y[plane->id] = + intel_plane_relative_data_rate(new_crtc_state, + new_plane_state, 0); + new_crtc_state->rel_data_rate[plane->id] = + intel_plane_relative_data_rate(new_crtc_state, + new_plane_state, 1); + } else if (new_plane_state->uapi.visible) { + new_crtc_state->data_rate[plane->id] = + intel_plane_data_rate(new_crtc_state, new_plane_state, 0); + + new_crtc_state->rel_data_rate[plane->id] = + intel_plane_relative_data_rate(new_crtc_state, + new_plane_state, 0); + } return intel_plane_atomic_calc_changes(old_crtc_state, new_crtc_state, old_plane_state, new_plane_state); @@ -616,8 +676,8 @@ int intel_plane_atomic_check(struct intel_atomic_state *state, static struct intel_plane * skl_next_plane_to_commit(struct intel_atomic_state *state, struct intel_crtc *crtc, - struct skl_ddb_entry entries_y[I915_MAX_PLANES], - struct skl_ddb_entry entries_uv[I915_MAX_PLANES], + struct skl_ddb_entry ddb[I915_MAX_PLANES], + struct skl_ddb_entry ddb_y[I915_MAX_PLANES], unsigned int *update_mask) { struct intel_crtc_state *crtc_state = @@ -636,17 +696,15 @@ skl_next_plane_to_commit(struct intel_atomic_state *state, !(*update_mask & BIT(plane_id))) continue; - if (skl_ddb_allocation_overlaps(&crtc_state->wm.skl.plane_ddb_y[plane_id], - entries_y, - I915_MAX_PLANES, plane_id) || - skl_ddb_allocation_overlaps(&crtc_state->wm.skl.plane_ddb_uv[plane_id], - entries_uv, - I915_MAX_PLANES, plane_id)) + if (skl_ddb_allocation_overlaps(&crtc_state->wm.skl.plane_ddb[plane_id], + ddb, I915_MAX_PLANES, plane_id) || + skl_ddb_allocation_overlaps(&crtc_state->wm.skl.plane_ddb_y[plane_id], + ddb_y, I915_MAX_PLANES, plane_id)) continue; *update_mask &= ~BIT(plane_id); - entries_y[plane_id] = crtc_state->wm.skl.plane_ddb_y[plane_id]; - entries_uv[plane_id] = crtc_state->wm.skl.plane_ddb_uv[plane_id]; + ddb[plane_id] = crtc_state->wm.skl.plane_ddb[plane_id]; + ddb_y[plane_id] = crtc_state->wm.skl.plane_ddb_y[plane_id]; return plane; } @@ -728,19 +786,17 @@ static void skl_crtc_planes_update_arm(struct intel_atomic_state *state, intel_atomic_get_old_crtc_state(state, crtc); struct intel_crtc_state *new_crtc_state = intel_atomic_get_new_crtc_state(state, crtc); - struct skl_ddb_entry entries_y[I915_MAX_PLANES]; - struct skl_ddb_entry entries_uv[I915_MAX_PLANES]; + struct skl_ddb_entry ddb[I915_MAX_PLANES]; + struct skl_ddb_entry ddb_y[I915_MAX_PLANES]; u32 update_mask = new_crtc_state->update_planes; struct intel_plane *plane; - memcpy(entries_y, old_crtc_state->wm.skl.plane_ddb_y, + memcpy(ddb, old_crtc_state->wm.skl.plane_ddb, + sizeof(old_crtc_state->wm.skl.plane_ddb)); + memcpy(ddb_y, old_crtc_state->wm.skl.plane_ddb_y, sizeof(old_crtc_state->wm.skl.plane_ddb_y)); - memcpy(entries_uv, old_crtc_state->wm.skl.plane_ddb_uv, - sizeof(old_crtc_state->wm.skl.plane_ddb_uv)); - while ((plane = skl_next_plane_to_commit(state, crtc, - entries_y, entries_uv, - &update_mask))) { + while ((plane = skl_next_plane_to_commit(state, crtc, ddb, ddb_y, &update_mask))) { struct intel_plane_state *new_plane_state = intel_atomic_get_new_plane_state(state, plane); @@ -802,8 +858,8 @@ int intel_atomic_plane_check_clipping(struct intel_plane_state *plane_state, struct drm_framebuffer *fb = plane_state->hw.fb; struct drm_rect *src = &plane_state->uapi.src; struct drm_rect *dst = &plane_state->uapi.dst; + const struct drm_rect *clip = &crtc_state->pipe_src; unsigned int rotation = plane_state->hw.rotation; - struct drm_rect clip = {}; int hscale, vscale; if (!fb) { @@ -823,31 +879,25 @@ int intel_atomic_plane_check_clipping(struct intel_plane_state *plane_state, return -ERANGE; } - if (crtc_state->hw.enable) { - clip.x2 = crtc_state->pipe_src_w; - clip.y2 = crtc_state->pipe_src_h; - } - - /* right side of the image is on the slave crtc, adjust dst to match */ - if (intel_crtc_is_bigjoiner_slave(crtc_state)) - drm_rect_translate(dst, -crtc_state->pipe_src_w, 0); - /* * FIXME: This might need further adjustment for seamless scaling * with phase information, for the 2p2 and 2p1 scenarios. */ - plane_state->uapi.visible = drm_rect_clip_scaled(src, dst, &clip); + plane_state->uapi.visible = drm_rect_clip_scaled(src, dst, clip); drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16, rotation); if (!can_position && plane_state->uapi.visible && - !drm_rect_equals(dst, &clip)) { + !drm_rect_equals(dst, clip)) { drm_dbg_kms(&i915->drm, "Plane must cover entire CRTC\n"); drm_rect_debug_print("dst: ", dst, false); - drm_rect_debug_print("clip: ", &clip, false); + drm_rect_debug_print("clip: ", clip, false); return -EINVAL; } + /* final plane coordinates will be relative to the plane's pipe */ + drm_rect_translate(dst, -clip->x1, -clip->y1); + return 0; } diff --git a/drivers/gpu/drm/i915/display/intel_atomic_plane.h b/drivers/gpu/drm/i915/display/intel_atomic_plane.h index f4763a53541e..74b6d3b169a7 100644 --- a/drivers/gpu/drm/i915/display/intel_atomic_plane.h +++ b/drivers/gpu/drm/i915/display/intel_atomic_plane.h @@ -25,7 +25,8 @@ unsigned int intel_plane_pixel_rate(const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state); unsigned int intel_plane_data_rate(const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state); + const struct intel_plane_state *plane_state, + int color_plane); void intel_plane_copy_uapi_to_hw_state(struct intel_plane_state *plane_state, const struct intel_plane_state *from_plane_state, struct intel_crtc *crtc); diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c index 3bdca0fe2cee..1c87bf66b092 100644 --- a/drivers/gpu/drm/i915/display/intel_audio.c +++ b/drivers/gpu/drm/i915/display/intel_audio.c @@ -337,8 +337,6 @@ static void g4x_audio_codec_disable(struct intel_encoder *encoder, struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); u32 eldv, tmp; - drm_dbg_kms(&dev_priv->drm, "Disable audio codec\n"); - tmp = intel_de_read(dev_priv, G4X_AUD_VID_DID); if (tmp == INTEL_AUDIO_DEVBLC || tmp == INTEL_AUDIO_DEVCL) eldv = G4X_ELDV_DEVCL_DEVBLC; @@ -362,9 +360,6 @@ static void g4x_audio_codec_enable(struct intel_encoder *encoder, u32 tmp; int len, i; - drm_dbg_kms(&dev_priv->drm, "Enable audio codec, %u bytes ELD\n", - drm_eld_size(eld)); - tmp = intel_de_read(dev_priv, G4X_AUD_VID_DID); if (tmp == INTEL_AUDIO_DEVBLC || tmp == INTEL_AUDIO_DEVCL) eldv = G4X_ELDV_DEVCL_DEVBLC; @@ -383,7 +378,6 @@ static void g4x_audio_codec_enable(struct intel_encoder *encoder, intel_de_write(dev_priv, G4X_AUD_CNTL_ST, tmp); len = min(drm_eld_size(eld) / 4, len); - drm_dbg(&dev_priv->drm, "ELD size %d\n", len); for (i = 0; i < len; i++) intel_de_write(dev_priv, G4X_HDMIW_HDMIEDID, *((const u32 *)eld + i)); @@ -501,9 +495,6 @@ static void hsw_audio_codec_disable(struct intel_encoder *encoder, enum transcoder cpu_transcoder = old_crtc_state->cpu_transcoder; u32 tmp; - drm_dbg_kms(&dev_priv->drm, "Disable audio codec on transcoder %s\n", - transcoder_name(cpu_transcoder)); - mutex_lock(&dev_priv->audio.mutex); /* Disable timestamps */ @@ -647,10 +638,6 @@ static void hsw_audio_codec_enable(struct intel_encoder *encoder, u32 tmp; int len, i; - drm_dbg_kms(&dev_priv->drm, - "Enable audio codec on transcoder %s, %u bytes ELD\n", - transcoder_name(cpu_transcoder), drm_eld_size(eld)); - mutex_lock(&dev_priv->audio.mutex); /* Enable Audio WA for 4k DSC usecases */ @@ -703,11 +690,6 @@ static void ilk_audio_codec_disable(struct intel_encoder *encoder, u32 tmp, eldv; i915_reg_t aud_config, aud_cntrl_st2; - drm_dbg_kms(&dev_priv->drm, - "Disable audio codec on [ENCODER:%d:%s], pipe %c\n", - encoder->base.base.id, encoder->base.name, - pipe_name(pipe)); - if (drm_WARN_ON(&dev_priv->drm, port == PORT_A)) return; @@ -754,11 +736,6 @@ static void ilk_audio_codec_enable(struct intel_encoder *encoder, int len, i; i915_reg_t hdmiw_hdmiedid, aud_config, aud_cntl_st, aud_cntrl_st2; - drm_dbg_kms(&dev_priv->drm, - "Enable audio codec on [ENCODER:%d:%s], pipe %c, %u bytes ELD\n", - encoder->base.base.id, encoder->base.name, - pipe_name(pipe), drm_eld_size(eld)); - if (drm_WARN_ON(&dev_priv->drm, port == PORT_A)) return; @@ -844,18 +821,20 @@ void intel_audio_codec_enable(struct intel_encoder *encoder, enum port port = encoder->port; enum pipe pipe = crtc->pipe; + if (!crtc_state->has_audio) + return; + + drm_dbg_kms(&dev_priv->drm, "[CONNECTOR:%d:%s][ENCODER:%d:%s] Enable audio codec on pipe %c, %u bytes ELD\n", + connector->base.id, connector->name, + encoder->base.base.id, encoder->base.name, + pipe, drm_eld_size(connector->eld)); + /* FIXME precompute the ELD in .compute_config() */ if (!connector->eld[0]) drm_dbg_kms(&dev_priv->drm, "Bogus ELD on [CONNECTOR:%d:%s]\n", connector->base.id, connector->name); - drm_dbg(&dev_priv->drm, "ELD on [CONNECTOR:%d:%s], [ENCODER:%d:%s]\n", - connector->base.id, - connector->name, - encoder->base.base.id, - encoder->base.name); - connector->eld[6] = drm_av_sync_delay(connector, adjusted_mode) / 2; if (dev_priv->audio.funcs) @@ -900,9 +879,17 @@ void intel_audio_codec_disable(struct intel_encoder *encoder, struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct i915_audio_component *acomp = dev_priv->audio.component; struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc); + struct drm_connector *connector = old_conn_state->connector; enum port port = encoder->port; enum pipe pipe = crtc->pipe; + if (!old_crtc_state->has_audio) + return; + + drm_dbg_kms(&dev_priv->drm, "[CONNECTOR:%d:%s][ENCODER:%d:%s] Disable audio codec on pipe %c\n", + connector->base.id, connector->name, + encoder->base.base.id, encoder->base.name, pipe); + if (dev_priv->audio.funcs) dev_priv->audio.funcs->audio_codec_disable(encoder, old_crtc_state, diff --git a/drivers/gpu/drm/i915/display/intel_backlight.c b/drivers/gpu/drm/i915/display/intel_backlight.c index 98f7ea44042f..c8e1fc53a881 100644 --- a/drivers/gpu/drm/i915/display/intel_backlight.c +++ b/drivers/gpu/drm/i915/display/intel_backlight.c @@ -5,6 +5,7 @@ #include <linux/kernel.h> #include <linux/pwm.h> +#include <linux/string_helpers.h> #include "intel_backlight.h" #include "intel_connector.h" @@ -1633,7 +1634,7 @@ int intel_backlight_setup(struct intel_connector *connector, enum pipe pipe) drm_dbg_kms(&dev_priv->drm, "Connector %s backlight initialized, %s, brightness %u/%u\n", connector->base.name, - enableddisabled(panel->backlight.enabled), + str_enabled_disabled(panel->backlight.enabled), panel->backlight.level, panel->backlight.max); return 0; diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c index 40b5e7ed12c2..bc195769dd07 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.c +++ b/drivers/gpu/drm/i915/display/intel_bios.c @@ -88,7 +88,7 @@ static u32 get_blocksize(const void *block_data) } static const void * -find_section(const void *_bdb, enum bdb_block_id section_id) +find_raw_section(const void *_bdb, enum bdb_block_id section_id) { const struct bdb_header *bdb = _bdb; const u8 *base = _bdb; @@ -118,6 +118,250 @@ find_section(const void *_bdb, enum bdb_block_id section_id) return NULL; } +/* + * Offset from the start of BDB to the start of the + * block data (just past the block header). + */ +static u32 block_offset(const void *bdb, enum bdb_block_id section_id) +{ + const void *block; + + block = find_raw_section(bdb, section_id); + if (!block) + return 0; + + return block - bdb; +} + +/* size of the block excluding the header */ +static u32 block_size(const void *bdb, enum bdb_block_id section_id) +{ + const void *block; + + block = find_raw_section(bdb, section_id); + if (!block) + return 0; + + return get_blocksize(block); +} + +struct bdb_block_entry { + struct list_head node; + enum bdb_block_id section_id; + u8 data[]; +}; + +static const void * +find_section(struct drm_i915_private *i915, + enum bdb_block_id section_id) +{ + struct bdb_block_entry *entry; + + list_for_each_entry(entry, &i915->vbt.bdb_blocks, node) { + if (entry->section_id == section_id) + return entry->data + 3; + } + + return NULL; +} + +static const struct { + enum bdb_block_id section_id; + size_t min_size; +} bdb_blocks[] = { + { .section_id = BDB_GENERAL_FEATURES, + .min_size = sizeof(struct bdb_general_features), }, + { .section_id = BDB_GENERAL_DEFINITIONS, + .min_size = sizeof(struct bdb_general_definitions), }, + { .section_id = BDB_PSR, + .min_size = sizeof(struct bdb_psr), }, + { .section_id = BDB_DRIVER_FEATURES, + .min_size = sizeof(struct bdb_driver_features), }, + { .section_id = BDB_SDVO_LVDS_OPTIONS, + .min_size = sizeof(struct bdb_sdvo_lvds_options), }, + { .section_id = BDB_SDVO_PANEL_DTDS, + .min_size = sizeof(struct bdb_sdvo_panel_dtds), }, + { .section_id = BDB_EDP, + .min_size = sizeof(struct bdb_edp), }, + { .section_id = BDB_LVDS_OPTIONS, + .min_size = sizeof(struct bdb_lvds_options), }, + { .section_id = BDB_LVDS_LFP_DATA_PTRS, + .min_size = sizeof(struct bdb_lvds_lfp_data_ptrs), }, + { .section_id = BDB_LVDS_LFP_DATA, + .min_size = sizeof(struct bdb_lvds_lfp_data), }, + { .section_id = BDB_LVDS_BACKLIGHT, + .min_size = sizeof(struct bdb_lfp_backlight_data), }, + { .section_id = BDB_LFP_POWER, + .min_size = sizeof(struct bdb_lfp_power), }, + { .section_id = BDB_MIPI_CONFIG, + .min_size = sizeof(struct bdb_mipi_config), }, + { .section_id = BDB_MIPI_SEQUENCE, + .min_size = sizeof(struct bdb_mipi_sequence) }, + { .section_id = BDB_COMPRESSION_PARAMETERS, + .min_size = sizeof(struct bdb_compression_parameters), }, + { .section_id = BDB_GENERIC_DTD, + .min_size = sizeof(struct bdb_generic_dtd), }, +}; + +static bool validate_lfp_data_ptrs(const void *bdb, + const struct bdb_lvds_lfp_data_ptrs *ptrs) +{ + int fp_timing_size, dvo_timing_size, panel_pnp_id_size, panel_name_size; + int data_block_size, lfp_data_size; + int i; + + data_block_size = block_size(bdb, BDB_LVDS_LFP_DATA); + if (data_block_size == 0) + return false; + + /* always 3 indicating the presence of fp_timing+dvo_timing+panel_pnp_id */ + if (ptrs->lvds_entries != 3) + return false; + + fp_timing_size = ptrs->ptr[0].fp_timing.table_size; + dvo_timing_size = ptrs->ptr[0].dvo_timing.table_size; + panel_pnp_id_size = ptrs->ptr[0].panel_pnp_id.table_size; + panel_name_size = ptrs->panel_name.table_size; + + /* fp_timing has variable size */ + if (fp_timing_size < 32 || + dvo_timing_size != sizeof(struct lvds_dvo_timing) || + panel_pnp_id_size != sizeof(struct lvds_pnp_id)) + return false; + + /* panel_name is not present in old VBTs */ + if (panel_name_size != 0 && + panel_name_size != sizeof(struct lvds_lfp_panel_name)) + return false; + + lfp_data_size = ptrs->ptr[1].fp_timing.offset - ptrs->ptr[0].fp_timing.offset; + if (16 * lfp_data_size > data_block_size) + return false; + + /* + * Except for vlv/chv machines all real VBTs seem to have 6 + * unaccounted bytes in the fp_timing table. And it doesn't + * appear to be a really intentional hole as the fp_timing + * 0xffff terminator is always within those 6 missing bytes. + */ + if (fp_timing_size + dvo_timing_size + panel_pnp_id_size != lfp_data_size && + fp_timing_size + 6 + dvo_timing_size + panel_pnp_id_size != lfp_data_size) + return false; + + if (ptrs->ptr[0].fp_timing.offset + fp_timing_size > ptrs->ptr[0].dvo_timing.offset || + ptrs->ptr[0].dvo_timing.offset + dvo_timing_size != ptrs->ptr[0].panel_pnp_id.offset || + ptrs->ptr[0].panel_pnp_id.offset + panel_pnp_id_size != lfp_data_size) + return false; + + /* make sure the table entries have uniform size */ + for (i = 1; i < 16; i++) { + if (ptrs->ptr[i].fp_timing.table_size != fp_timing_size || + ptrs->ptr[i].dvo_timing.table_size != dvo_timing_size || + ptrs->ptr[i].panel_pnp_id.table_size != panel_pnp_id_size) + return false; + + if (ptrs->ptr[i].fp_timing.offset - ptrs->ptr[i-1].fp_timing.offset != lfp_data_size || + ptrs->ptr[i].dvo_timing.offset - ptrs->ptr[i-1].dvo_timing.offset != lfp_data_size || + ptrs->ptr[i].panel_pnp_id.offset - ptrs->ptr[i-1].panel_pnp_id.offset != lfp_data_size) + return false; + } + + /* make sure the tables fit inside the data block */ + for (i = 0; i < 16; i++) { + if (ptrs->ptr[i].fp_timing.offset + fp_timing_size > data_block_size || + ptrs->ptr[i].dvo_timing.offset + dvo_timing_size > data_block_size || + ptrs->ptr[i].panel_pnp_id.offset + panel_pnp_id_size > data_block_size) + return false; + } + + if (ptrs->panel_name.offset + 16 * panel_name_size > data_block_size) + return false; + + return true; +} + +/* make the data table offsets relative to the data block */ +static bool fixup_lfp_data_ptrs(const void *bdb, void *ptrs_block) +{ + struct bdb_lvds_lfp_data_ptrs *ptrs = ptrs_block; + u32 offset; + int i; + + offset = block_offset(bdb, BDB_LVDS_LFP_DATA); + + for (i = 0; i < 16; i++) { + if (ptrs->ptr[i].fp_timing.offset < offset || + ptrs->ptr[i].dvo_timing.offset < offset || + ptrs->ptr[i].panel_pnp_id.offset < offset) + return false; + + ptrs->ptr[i].fp_timing.offset -= offset; + ptrs->ptr[i].dvo_timing.offset -= offset; + ptrs->ptr[i].panel_pnp_id.offset -= offset; + } + + if (ptrs->panel_name.table_size) { + if (ptrs->panel_name.offset < offset) + return false; + + ptrs->panel_name.offset -= offset; + } + + return validate_lfp_data_ptrs(bdb, ptrs); +} + +static void +init_bdb_block(struct drm_i915_private *i915, + const void *bdb, enum bdb_block_id section_id, + size_t min_size) +{ + struct bdb_block_entry *entry; + const void *block; + size_t block_size; + + block = find_raw_section(bdb, section_id); + if (!block) + return; + + drm_WARN(&i915->drm, min_size == 0, + "Block %d min_size is zero\n", section_id); + + block_size = get_blocksize(block); + + entry = kzalloc(struct_size(entry, data, max(min_size, block_size) + 3), + GFP_KERNEL); + if (!entry) + return; + + entry->section_id = section_id; + memcpy(entry->data, block - 3, block_size + 3); + + drm_dbg_kms(&i915->drm, "Found BDB block %d (size %zu, min size %zu)\n", + section_id, block_size, min_size); + + if (section_id == BDB_LVDS_LFP_DATA_PTRS && + !fixup_lfp_data_ptrs(bdb, entry->data + 3)) { + drm_err(&i915->drm, "VBT has malformed LFP data table pointers\n"); + kfree(entry); + return; + } + + list_add_tail(&entry->node, &i915->vbt.bdb_blocks); +} + +static void init_bdb_blocks(struct drm_i915_private *i915, + const void *bdb) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(bdb_blocks); i++) { + enum bdb_block_id section_id = bdb_blocks[i].section_id; + size_t min_size = bdb_blocks[i].min_size; + + init_bdb_block(i915, bdb, section_id, min_size); + } +} + static void fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode, const struct lvds_dvo_timing *dvo_timing) @@ -169,60 +413,31 @@ fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode, } static const struct lvds_dvo_timing * -get_lvds_dvo_timing(const struct bdb_lvds_lfp_data *lvds_lfp_data, - const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs, +get_lvds_dvo_timing(const struct bdb_lvds_lfp_data *data, + const struct bdb_lvds_lfp_data_ptrs *ptrs, int index) { - /* - * the size of fp_timing varies on the different platform. - * So calculate the DVO timing relative offset in LVDS data - * entry to get the DVO timing entry - */ - - int lfp_data_size = - lvds_lfp_data_ptrs->ptr[1].dvo_timing_offset - - lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset; - int dvo_timing_offset = - lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset - - lvds_lfp_data_ptrs->ptr[0].fp_timing_offset; - char *entry = (char *)lvds_lfp_data->data + lfp_data_size * index; - - return (struct lvds_dvo_timing *)(entry + dvo_timing_offset); + return (const void *)data + ptrs->ptr[index].dvo_timing.offset; } -/* get lvds_fp_timing entry - * this function may return NULL if the corresponding entry is invalid - */ static const struct lvds_fp_timing * -get_lvds_fp_timing(const struct bdb_header *bdb, - const struct bdb_lvds_lfp_data *data, +get_lvds_fp_timing(const struct bdb_lvds_lfp_data *data, const struct bdb_lvds_lfp_data_ptrs *ptrs, int index) { - size_t data_ofs = (const u8 *)data - (const u8 *)bdb; - u16 data_size = ((const u16 *)data)[-1]; /* stored in header */ - size_t ofs; - - if (index >= ARRAY_SIZE(ptrs->ptr)) - return NULL; - ofs = ptrs->ptr[index].fp_timing_offset; - if (ofs < data_ofs || - ofs + sizeof(struct lvds_fp_timing) > data_ofs + data_size) - return NULL; - return (const struct lvds_fp_timing *)((const u8 *)bdb + ofs); + return (const void *)data + ptrs->ptr[index].fp_timing.offset; } /* Parse general panel options */ static void -parse_panel_options(struct drm_i915_private *i915, - const struct bdb_header *bdb) +parse_panel_options(struct drm_i915_private *i915) { const struct bdb_lvds_options *lvds_options; int panel_type; int drrs_mode; int ret; - lvds_options = find_section(bdb, BDB_LVDS_OPTIONS); + lvds_options = find_section(i915, BDB_LVDS_OPTIONS); if (!lvds_options) return; @@ -257,16 +472,16 @@ parse_panel_options(struct drm_i915_private *i915, */ switch (drrs_mode) { case 0: - i915->vbt.drrs_type = STATIC_DRRS_SUPPORT; + i915->vbt.drrs_type = DRRS_TYPE_STATIC; drm_dbg_kms(&i915->drm, "DRRS supported mode is static\n"); break; case 2: - i915->vbt.drrs_type = SEAMLESS_DRRS_SUPPORT; + i915->vbt.drrs_type = DRRS_TYPE_SEAMLESS; drm_dbg_kms(&i915->drm, "DRRS supported mode is seamless\n"); break; default: - i915->vbt.drrs_type = DRRS_NOT_SUPPORTED; + i915->vbt.drrs_type = DRRS_TYPE_NONE; drm_dbg_kms(&i915->drm, "DRRS not supported (VBT input)\n"); break; @@ -275,8 +490,7 @@ parse_panel_options(struct drm_i915_private *i915, /* Try to find integrated panel timing data */ static void -parse_lfp_panel_dtd(struct drm_i915_private *i915, - const struct bdb_header *bdb) +parse_lfp_panel_dtd(struct drm_i915_private *i915) { const struct bdb_lvds_lfp_data *lvds_lfp_data; const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs; @@ -285,11 +499,11 @@ parse_lfp_panel_dtd(struct drm_i915_private *i915, struct drm_display_mode *panel_fixed_mode; int panel_type = i915->vbt.panel_type; - lvds_lfp_data = find_section(bdb, BDB_LVDS_LFP_DATA); + lvds_lfp_data = find_section(i915, BDB_LVDS_LFP_DATA); if (!lvds_lfp_data) return; - lvds_lfp_data_ptrs = find_section(bdb, BDB_LVDS_LFP_DATA_PTRS); + lvds_lfp_data_ptrs = find_section(i915, BDB_LVDS_LFP_DATA_PTRS); if (!lvds_lfp_data_ptrs) return; @@ -306,34 +520,32 @@ parse_lfp_panel_dtd(struct drm_i915_private *i915, i915->vbt.lfp_lvds_vbt_mode = panel_fixed_mode; drm_dbg_kms(&i915->drm, - "Found panel mode in BIOS VBT legacy lfp table:\n"); - drm_mode_debug_printmodeline(panel_fixed_mode); + "Found panel mode in BIOS VBT legacy lfp table: " DRM_MODE_FMT "\n", + DRM_MODE_ARG(panel_fixed_mode)); - fp_timing = get_lvds_fp_timing(bdb, lvds_lfp_data, + fp_timing = get_lvds_fp_timing(lvds_lfp_data, lvds_lfp_data_ptrs, panel_type); - if (fp_timing) { - /* check the resolution, just to be sure */ - if (fp_timing->x_res == panel_fixed_mode->hdisplay && - fp_timing->y_res == panel_fixed_mode->vdisplay) { - i915->vbt.bios_lvds_val = fp_timing->lvds_reg_val; - drm_dbg_kms(&i915->drm, - "VBT initial LVDS value %x\n", - i915->vbt.bios_lvds_val); - } + + /* check the resolution, just to be sure */ + if (fp_timing->x_res == panel_fixed_mode->hdisplay && + fp_timing->y_res == panel_fixed_mode->vdisplay) { + i915->vbt.bios_lvds_val = fp_timing->lvds_reg_val; + drm_dbg_kms(&i915->drm, + "VBT initial LVDS value %x\n", + i915->vbt.bios_lvds_val); } } static void -parse_generic_dtd(struct drm_i915_private *i915, - const struct bdb_header *bdb) +parse_generic_dtd(struct drm_i915_private *i915) { const struct bdb_generic_dtd *generic_dtd; const struct generic_dtd_entry *dtd; struct drm_display_mode *panel_fixed_mode; int num_dtd; - generic_dtd = find_section(bdb, BDB_GENERIC_DTD); + generic_dtd = find_section(i915, BDB_GENERIC_DTD); if (!generic_dtd) return; @@ -397,15 +609,14 @@ parse_generic_dtd(struct drm_i915_private *i915, panel_fixed_mode->flags |= DRM_MODE_FLAG_NVSYNC; drm_dbg_kms(&i915->drm, - "Found panel mode in BIOS VBT generic dtd table:\n"); - drm_mode_debug_printmodeline(panel_fixed_mode); + "Found panel mode in BIOS VBT generic dtd table: " DRM_MODE_FMT "\n", + DRM_MODE_ARG(panel_fixed_mode)); i915->vbt.lfp_lvds_vbt_mode = panel_fixed_mode; } static void -parse_panel_dtd(struct drm_i915_private *i915, - const struct bdb_header *bdb) +parse_panel_dtd(struct drm_i915_private *i915) { /* * Older VBTs provided provided DTD information for internal displays @@ -415,22 +626,21 @@ parse_panel_dtd(struct drm_i915_private *i915, * try the new generic DTD block first on VBT >= 229, but still fall * back to trying the old LFP block if that fails. */ - if (bdb->version >= 229) - parse_generic_dtd(i915, bdb); + if (i915->vbt.version >= 229) + parse_generic_dtd(i915); if (!i915->vbt.lfp_lvds_vbt_mode) - parse_lfp_panel_dtd(i915, bdb); + parse_lfp_panel_dtd(i915); } static void -parse_lfp_backlight(struct drm_i915_private *i915, - const struct bdb_header *bdb) +parse_lfp_backlight(struct drm_i915_private *i915) { const struct bdb_lfp_backlight_data *backlight_data; const struct lfp_backlight_data_entry *entry; int panel_type = i915->vbt.panel_type; u16 level; - backlight_data = find_section(bdb, BDB_LVDS_BACKLIGHT); + backlight_data = find_section(i915, BDB_LVDS_BACKLIGHT); if (!backlight_data) return; @@ -452,12 +662,12 @@ parse_lfp_backlight(struct drm_i915_private *i915, } i915->vbt.backlight.type = INTEL_BACKLIGHT_DISPLAY_DDI; - if (bdb->version >= 191) { + if (i915->vbt.version >= 191) { size_t exp_size; - if (bdb->version >= 236) + if (i915->vbt.version >= 236) exp_size = sizeof(struct bdb_lfp_backlight_data); - else if (bdb->version >= 234) + else if (i915->vbt.version >= 234) exp_size = EXP_BDB_LFP_BL_DATA_SIZE_REV_234; else exp_size = EXP_BDB_LFP_BL_DATA_SIZE_REV_191; @@ -474,14 +684,14 @@ parse_lfp_backlight(struct drm_i915_private *i915, i915->vbt.backlight.pwm_freq_hz = entry->pwm_freq_hz; i915->vbt.backlight.active_low_pwm = entry->active_low_pwm; - if (bdb->version >= 234) { + if (i915->vbt.version >= 234) { u16 min_level; bool scale; level = backlight_data->brightness_level[panel_type].level; min_level = backlight_data->brightness_min_level[panel_type].level; - if (bdb->version >= 236) + if (i915->vbt.version >= 236) scale = backlight_data->brightness_precision_bits[panel_type] == 16; else scale = level > 255; @@ -514,8 +724,7 @@ parse_lfp_backlight(struct drm_i915_private *i915, /* Try to find sdvo panel data */ static void -parse_sdvo_panel_data(struct drm_i915_private *i915, - const struct bdb_header *bdb) +parse_sdvo_panel_data(struct drm_i915_private *i915) { const struct bdb_sdvo_panel_dtds *dtds; struct drm_display_mode *panel_fixed_mode; @@ -531,14 +740,14 @@ parse_sdvo_panel_data(struct drm_i915_private *i915, if (index == -1) { const struct bdb_sdvo_lvds_options *sdvo_lvds_options; - sdvo_lvds_options = find_section(bdb, BDB_SDVO_LVDS_OPTIONS); + sdvo_lvds_options = find_section(i915, BDB_SDVO_LVDS_OPTIONS); if (!sdvo_lvds_options) return; index = sdvo_lvds_options->panel_type; } - dtds = find_section(bdb, BDB_SDVO_PANEL_DTDS); + dtds = find_section(i915, BDB_SDVO_PANEL_DTDS); if (!dtds) return; @@ -551,8 +760,8 @@ parse_sdvo_panel_data(struct drm_i915_private *i915, i915->vbt.sdvo_lvds_vbt_mode = panel_fixed_mode; drm_dbg_kms(&i915->drm, - "Found SDVO panel mode in BIOS VBT tables:\n"); - drm_mode_debug_printmodeline(panel_fixed_mode); + "Found SDVO panel mode in BIOS VBT tables: " DRM_MODE_FMT "\n", + DRM_MODE_ARG(panel_fixed_mode)); } static int intel_bios_ssc_frequency(struct drm_i915_private *i915, @@ -570,18 +779,17 @@ static int intel_bios_ssc_frequency(struct drm_i915_private *i915, } static void -parse_general_features(struct drm_i915_private *i915, - const struct bdb_header *bdb) +parse_general_features(struct drm_i915_private *i915) { const struct bdb_general_features *general; - general = find_section(bdb, BDB_GENERAL_FEATURES); + general = find_section(i915, BDB_GENERAL_FEATURES); if (!general) return; i915->vbt.int_tv_support = general->int_tv_support; /* int_crt_support can't be trusted on earlier platforms */ - if (bdb->version >= 155 && + if (i915->vbt.version >= 155 && (HAS_DDI(i915) || IS_VALLEYVIEW(i915))) i915->vbt.int_crt_support = general->int_crt_support; i915->vbt.lvds_use_ssc = general->enable_ssc; @@ -589,7 +797,7 @@ parse_general_features(struct drm_i915_private *i915, intel_bios_ssc_frequency(i915, general->ssc_freq); i915->vbt.display_clock_mode = general->display_clock_mode; i915->vbt.fdi_rx_polarity_inverted = general->fdi_rx_polarity_inverted; - if (bdb->version >= 181) { + if (i915->vbt.version >= 181) { i915->vbt.orientation = general->rotate_180 ? DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP : DRM_MODE_PANEL_ORIENTATION_NORMAL; @@ -597,7 +805,7 @@ parse_general_features(struct drm_i915_private *i915, i915->vbt.orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN; } - if (bdb->version >= 249 && general->afc_startup_config) { + if (i915->vbt.version >= 249 && general->afc_startup_config) { i915->vbt.override_afc_startup = true; i915->vbt.override_afc_startup_val = general->afc_startup_config == 0x1 ? 0x0 : 0x7; } @@ -695,12 +903,11 @@ parse_sdvo_device_mapping(struct drm_i915_private *i915) } static void -parse_driver_features(struct drm_i915_private *i915, - const struct bdb_header *bdb) +parse_driver_features(struct drm_i915_private *i915) { const struct bdb_driver_features *driver; - driver = find_section(bdb, BDB_DRIVER_FEATURES); + driver = find_section(i915, BDB_DRIVER_FEATURES); if (!driver) return; @@ -724,13 +931,13 @@ parse_driver_features(struct drm_i915_private *i915, * in the wild with the bits correctly populated. Version * 108 (on i85x) does not have the bits correctly populated. */ - if (bdb->version >= 134 && + if (i915->vbt.version >= 134 && driver->lvds_config != BDB_DRIVER_FEATURE_INT_LVDS && driver->lvds_config != BDB_DRIVER_FEATURE_INT_SDVO_LVDS) i915->vbt.int_lvds_support = 0; } - if (bdb->version < 228) { + if (i915->vbt.version < 228) { drm_dbg_kms(&i915->drm, "DRRS State Enabled:%d\n", driver->drrs_enabled); /* @@ -740,23 +947,22 @@ parse_driver_features(struct drm_i915_private *i915, * driver->drrs_enabled=false */ if (!driver->drrs_enabled) - i915->vbt.drrs_type = DRRS_NOT_SUPPORTED; + i915->vbt.drrs_type = DRRS_TYPE_NONE; i915->vbt.psr.enable = driver->psr_enabled; } } static void -parse_power_conservation_features(struct drm_i915_private *i915, - const struct bdb_header *bdb) +parse_power_conservation_features(struct drm_i915_private *i915) { const struct bdb_lfp_power *power; u8 panel_type = i915->vbt.panel_type; - if (bdb->version < 228) + if (i915->vbt.version < 228) return; - power = find_section(bdb, BDB_LFP_POWER); + power = find_section(i915, BDB_LFP_POWER); if (!power) return; @@ -769,21 +975,21 @@ parse_power_conservation_features(struct drm_i915_private *i915, * power->drrs & BIT(panel_type)=false */ if (!(power->drrs & BIT(panel_type))) - i915->vbt.drrs_type = DRRS_NOT_SUPPORTED; + i915->vbt.drrs_type = DRRS_TYPE_NONE; - if (bdb->version >= 232) + if (i915->vbt.version >= 232) i915->vbt.edp.hobl = power->hobl & BIT(panel_type); } static void -parse_edp(struct drm_i915_private *i915, const struct bdb_header *bdb) +parse_edp(struct drm_i915_private *i915) { const struct bdb_edp *edp; const struct edp_power_seq *edp_pps; const struct edp_fast_link_params *edp_link_params; int panel_type = i915->vbt.panel_type; - edp = find_section(bdb, BDB_EDP); + edp = find_section(i915, BDB_EDP); if (!edp) return; @@ -876,7 +1082,7 @@ parse_edp(struct drm_i915_private *i915, const struct bdb_header *bdb) break; } - if (bdb->version >= 173) { + if (i915->vbt.version >= 173) { u8 vswing; /* Don't read from VBT if module parameter has valid value*/ @@ -888,16 +1094,19 @@ parse_edp(struct drm_i915_private *i915, const struct bdb_header *bdb) i915->vbt.edp.low_vswing = vswing == 0; } } + + i915->vbt.edp.drrs_msa_timing_delay = + (edp->sdrrs_msa_timing_delay >> (panel_type * 2)) & 3; } static void -parse_psr(struct drm_i915_private *i915, const struct bdb_header *bdb) +parse_psr(struct drm_i915_private *i915) { const struct bdb_psr *psr; const struct psr_table *psr_table; int panel_type = i915->vbt.panel_type; - psr = find_section(bdb, BDB_PSR); + psr = find_section(i915, BDB_PSR); if (!psr) { drm_dbg_kms(&i915->drm, "No PSR BDB found.\n"); return; @@ -916,7 +1125,7 @@ parse_psr(struct drm_i915_private *i915, const struct bdb_header *bdb) * New psr options 0=500us, 1=100us, 2=2500us, 3=0us * Old decimal value is wake up time in multiples of 100 us. */ - if (bdb->version >= 205 && + if (i915->vbt.version >= 205 && (DISPLAY_VER(i915) >= 9 && !IS_BROXTON(i915))) { switch (psr_table->tp1_wakeup_time) { case 0: @@ -962,7 +1171,7 @@ parse_psr(struct drm_i915_private *i915, const struct bdb_header *bdb) i915->vbt.psr.tp2_tp3_wakeup_time_us = psr_table->tp2_tp3_wakeup_time * 100; } - if (bdb->version >= 226) { + if (i915->vbt.version >= 226) { u32 wakeup_time = psr->psr2_tp2_tp3_wakeup_time; wakeup_time = (wakeup_time >> (2 * panel_type)) & 0x3; @@ -1031,8 +1240,7 @@ static void parse_dsi_backlight_ports(struct drm_i915_private *i915, } static void -parse_mipi_config(struct drm_i915_private *i915, - const struct bdb_header *bdb) +parse_mipi_config(struct drm_i915_private *i915) { const struct bdb_mipi_config *start; const struct mipi_config *config; @@ -1055,7 +1263,7 @@ parse_mipi_config(struct drm_i915_private *i915, /* Parse #52 for panel index used from panel_type already * parsed */ - start = find_section(bdb, BDB_MIPI_CONFIG); + start = find_section(i915, BDB_MIPI_CONFIG); if (!start) { drm_dbg_kms(&i915->drm, "No MIPI config BDB found"); return; @@ -1082,7 +1290,7 @@ parse_mipi_config(struct drm_i915_private *i915, return; } - parse_dsi_backlight_ports(i915, bdb->version, port); + parse_dsi_backlight_ports(i915, i915->vbt.version, port); /* FIXME is the 90 vs. 270 correct? */ switch (config->rotation) { @@ -1351,8 +1559,7 @@ static void fixup_mipi_sequences(struct drm_i915_private *i915) } static void -parse_mipi_sequence(struct drm_i915_private *i915, - const struct bdb_header *bdb) +parse_mipi_sequence(struct drm_i915_private *i915) { int panel_type = i915->vbt.panel_type; const struct bdb_mipi_sequence *sequence; @@ -1365,7 +1572,7 @@ parse_mipi_sequence(struct drm_i915_private *i915, if (i915->vbt.dsi.panel_id != MIPI_DSI_GENERIC_PANEL_ID) return; - sequence = find_section(bdb, BDB_MIPI_SEQUENCE); + sequence = find_section(i915, BDB_MIPI_SEQUENCE); if (!sequence) { drm_dbg_kms(&i915->drm, "No MIPI Sequence found, parsing complete\n"); @@ -1436,8 +1643,7 @@ err: } static void -parse_compression_parameters(struct drm_i915_private *i915, - const struct bdb_header *bdb) +parse_compression_parameters(struct drm_i915_private *i915) { const struct bdb_compression_parameters *params; struct intel_bios_encoder_data *devdata; @@ -1445,10 +1651,10 @@ parse_compression_parameters(struct drm_i915_private *i915, u16 block_size; int index; - if (bdb->version < 198) + if (i915->vbt.version < 198) return; - params = find_section(bdb, BDB_COMPRESSION_PARAMETERS); + params = find_section(i915, BDB_COMPRESSION_PARAMETERS); if (params) { /* Sanity checks */ if (params->entry_size != sizeof(params->data[0])) { @@ -1955,6 +2161,12 @@ static int _intel_bios_max_tmds_clock(const struct intel_bios_encoder_data *devd fallthrough; case HDMI_MAX_DATA_RATE_PLATFORM: return 0; + case HDMI_MAX_DATA_RATE_594: + return 594000; + case HDMI_MAX_DATA_RATE_340: + return 340000; + case HDMI_MAX_DATA_RATE_300: + return 300000; case HDMI_MAX_DATA_RATE_297: return 297000; case HDMI_MAX_DATA_RATE_165: @@ -2077,8 +2289,7 @@ static void parse_ddi_ports(struct drm_i915_private *i915) } static void -parse_general_definitions(struct drm_i915_private *i915, - const struct bdb_header *bdb) +parse_general_definitions(struct drm_i915_private *i915) { const struct bdb_general_definitions *defs; struct intel_bios_encoder_data *devdata; @@ -2088,7 +2299,7 @@ parse_general_definitions(struct drm_i915_private *i915, u16 block_size; int bus_pin; - defs = find_section(bdb, BDB_GENERAL_DEFINITIONS); + defs = find_section(i915, BDB_GENERAL_DEFINITIONS); if (!defs) { drm_dbg_kms(&i915->drm, "No general definition block is found, no devices defined.\n"); @@ -2108,31 +2319,31 @@ parse_general_definitions(struct drm_i915_private *i915, if (intel_gmbus_is_valid_pin(i915, bus_pin)) i915->vbt.crt_ddc_pin = bus_pin; - if (bdb->version < 106) { + if (i915->vbt.version < 106) { expected_size = 22; - } else if (bdb->version < 111) { + } else if (i915->vbt.version < 111) { expected_size = 27; - } else if (bdb->version < 195) { + } else if (i915->vbt.version < 195) { expected_size = LEGACY_CHILD_DEVICE_CONFIG_SIZE; - } else if (bdb->version == 195) { + } else if (i915->vbt.version == 195) { expected_size = 37; - } else if (bdb->version <= 215) { + } else if (i915->vbt.version <= 215) { expected_size = 38; - } else if (bdb->version <= 237) { + } else if (i915->vbt.version <= 237) { expected_size = 39; } else { expected_size = sizeof(*child); BUILD_BUG_ON(sizeof(*child) < 39); drm_dbg(&i915->drm, "Expected child device config size for VBT version %u not known; assuming %u\n", - bdb->version, expected_size); + i915->vbt.version, expected_size); } /* Flag an error for unexpected size, but continue anyway. */ if (defs->child_dev_size != expected_size) drm_err(&i915->drm, "Unexpected child device config size %u (expected %u for VBT version %u)\n", - defs->child_dev_size, expected_size, bdb->version); + defs->child_dev_size, expected_size, i915->vbt.version); /* The legacy sized child device config is the minimum we need. */ if (defs->child_dev_size < LEGACY_CHILD_DEVICE_CONFIG_SIZE) { @@ -2457,6 +2668,7 @@ void intel_bios_init(struct drm_i915_private *i915) const struct bdb_header *bdb; INIT_LIST_HEAD(&i915->vbt.display_devices); + INIT_LIST_HEAD(&i915->vbt.bdb_blocks); if (!HAS_DISPLAY(i915)) { drm_dbg_kms(&i915->drm, @@ -2488,24 +2700,26 @@ void intel_bios_init(struct drm_i915_private *i915) drm_dbg_kms(&i915->drm, "VBT signature \"%.*s\", BDB version %d\n", - (int)sizeof(vbt->signature), vbt->signature, bdb->version); + (int)sizeof(vbt->signature), vbt->signature, i915->vbt.version); + + init_bdb_blocks(i915, bdb); /* Grab useful general definitions */ - parse_general_features(i915, bdb); - parse_general_definitions(i915, bdb); - parse_panel_options(i915, bdb); - parse_panel_dtd(i915, bdb); - parse_lfp_backlight(i915, bdb); - parse_sdvo_panel_data(i915, bdb); - parse_driver_features(i915, bdb); - parse_power_conservation_features(i915, bdb); - parse_edp(i915, bdb); - parse_psr(i915, bdb); - parse_mipi_config(i915, bdb); - parse_mipi_sequence(i915, bdb); + parse_general_features(i915); + parse_general_definitions(i915); + parse_panel_options(i915); + parse_panel_dtd(i915); + parse_lfp_backlight(i915); + parse_sdvo_panel_data(i915); + parse_driver_features(i915); + parse_power_conservation_features(i915); + parse_edp(i915); + parse_psr(i915); + parse_mipi_config(i915); + parse_mipi_sequence(i915); /* Depends on child device list */ - parse_compression_parameters(i915, bdb); + parse_compression_parameters(i915); out: if (!vbt) { @@ -2527,14 +2741,20 @@ out: */ void intel_bios_driver_remove(struct drm_i915_private *i915) { - struct intel_bios_encoder_data *devdata, *n; + struct intel_bios_encoder_data *devdata, *nd; + struct bdb_block_entry *entry, *ne; - list_for_each_entry_safe(devdata, n, &i915->vbt.display_devices, node) { + list_for_each_entry_safe(devdata, nd, &i915->vbt.display_devices, node) { list_del(&devdata->node); kfree(devdata->dsc); kfree(devdata); } + list_for_each_entry_safe(entry, ne, &i915->vbt.bdb_blocks, node) { + list_del(&entry->node); + kfree(entry); + } + kfree(i915->vbt.sdvo_lvds_vbt_mode); i915->vbt.sdvo_lvds_vbt_mode = NULL; kfree(i915->vbt.lfp_lvds_vbt_mode); diff --git a/drivers/gpu/drm/i915/display/intel_bw.c b/drivers/gpu/drm/i915/display/intel_bw.c index adf58c58513b..37bd7b17f3d0 100644 --- a/drivers/gpu/drm/i915/display/intel_bw.c +++ b/drivers/gpu/drm/i915/display/intel_bw.c @@ -6,6 +6,7 @@ #include <drm/drm_atomic_state_helper.h> #include "i915_reg.h" +#include "i915_utils.h" #include "intel_atomic.h" #include "intel_bw.h" #include "intel_cdclk.h" @@ -124,8 +125,8 @@ int icl_pcode_restrict_qgv_points(struct drm_i915_private *dev_priv, /* bspec says to keep retrying for at least 1 ms */ ret = skl_pcode_request(dev_priv, ICL_PCODE_SAGV_DE_MEM_SS_CONFIG, points_mask, - ICL_PCODE_POINTS_RESTRICTED_MASK, - ICL_PCODE_POINTS_RESTRICTED, + ICL_PCODE_REP_QGV_MASK | ADLS_PCODE_REP_PSF_MASK, + ICL_PCODE_REP_QGV_SAFE | ADLS_PCODE_REP_PSF_SAFE, 1); if (ret < 0) { @@ -464,20 +465,25 @@ static int tgl_get_bw_info(struct drm_i915_private *dev_priv, const struct intel static void dg2_get_bw_info(struct drm_i915_private *i915) { - struct intel_bw_info *bi = &i915->max_bw[0]; + unsigned int deratedbw = IS_DG2_G11(i915) ? 38000 : 50000; + int num_groups = ARRAY_SIZE(i915->max_bw); + int i; /* * DG2 doesn't have SAGV or QGV points, just a constant max bandwidth - * that doesn't depend on the number of planes enabled. Create a - * single dummy QGV point to reflect that. DG2-G10 platforms have a - * constant 50 GB/s bandwidth, whereas DG2-G11 platforms have 38 GB/s. + * that doesn't depend on the number of planes enabled. So fill all the + * plane group with constant bw information for uniformity with other + * platforms. DG2-G10 platforms have a constant 50 GB/s bandwidth, + * whereas DG2-G11 platforms have 38 GB/s. */ - bi->num_planes = 1; - bi->num_qgv_points = 1; - if (IS_DG2_G11(i915)) - bi->deratedbw[0] = 38000; - else - bi->deratedbw[0] = 50000; + for (i = 0; i < num_groups; i++) { + struct intel_bw_info *bi = &i915->max_bw[i]; + + bi->num_planes = 1; + /* Need only one dummy QGV point per group */ + bi->num_qgv_points = 1; + bi->deratedbw[0] = deratedbw; + } i915->sagv_status = I915_SAGV_NOT_CONTROLLED; } @@ -578,6 +584,7 @@ static unsigned int intel_bw_crtc_num_active_planes(const struct intel_crtc_stat static unsigned int intel_bw_crtc_data_rate(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); unsigned int data_rate = 0; enum plane_id plane_id; @@ -590,11 +597,26 @@ static unsigned int intel_bw_crtc_data_rate(const struct intel_crtc_state *crtc_ continue; data_rate += crtc_state->data_rate[plane_id]; + + if (DISPLAY_VER(i915) < 11) + data_rate += crtc_state->data_rate_y[plane_id]; } return data_rate; } +/* "Maximum Pipe Read Bandwidth" */ +static int intel_bw_crtc_min_cdclk(const struct intel_crtc_state *crtc_state) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + + if (DISPLAY_VER(i915) < 12) + return 0; + + return DIV_ROUND_UP_ULL(mul_u32_u32(intel_bw_crtc_data_rate(crtc_state), 10), 512); +} + void intel_bw_crtc_update(struct intel_bw_state *bw_state, const struct intel_crtc_state *crtc_state) { @@ -633,8 +655,8 @@ static unsigned int intel_bw_data_rate(struct drm_i915_private *dev_priv, for_each_pipe(dev_priv, pipe) data_rate += bw_state->data_rate[pipe]; - if (DISPLAY_VER(dev_priv) >= 13 && intel_vtd_active(dev_priv)) - data_rate = data_rate * 105 / 100; + if (DISPLAY_VER(dev_priv) >= 13 && i915_vtd_active(dev_priv)) + data_rate = DIV_ROUND_UP(data_rate * 105, 100); return data_rate; } @@ -674,6 +696,53 @@ intel_atomic_get_bw_state(struct intel_atomic_state *state) return to_intel_bw_state(bw_state); } +static bool intel_bw_state_changed(struct drm_i915_private *i915, + const struct intel_bw_state *old_bw_state, + const struct intel_bw_state *new_bw_state) +{ + enum pipe pipe; + + for_each_pipe(i915, pipe) { + const struct intel_dbuf_bw *old_crtc_bw = + &old_bw_state->dbuf_bw[pipe]; + const struct intel_dbuf_bw *new_crtc_bw = + &new_bw_state->dbuf_bw[pipe]; + enum dbuf_slice slice; + + for_each_dbuf_slice(i915, slice) { + if (old_crtc_bw->max_bw[slice] != new_crtc_bw->max_bw[slice] || + old_crtc_bw->active_planes[slice] != new_crtc_bw->active_planes[slice]) + return true; + } + + if (old_bw_state->min_cdclk[pipe] != new_bw_state->min_cdclk[pipe]) + return true; + } + + return false; +} + +static void skl_plane_calc_dbuf_bw(struct intel_bw_state *bw_state, + struct intel_crtc *crtc, + enum plane_id plane_id, + const struct skl_ddb_entry *ddb, + unsigned int data_rate) +{ + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + struct intel_dbuf_bw *crtc_bw = &bw_state->dbuf_bw[crtc->pipe]; + unsigned int dbuf_mask = skl_ddb_dbuf_slice_mask(i915, ddb); + enum dbuf_slice slice; + + /* + * The arbiter can only really guarantee an + * equal share of the total bw to each plane. + */ + for_each_dbuf_slice_in_mask(i915, slice, dbuf_mask) { + crtc_bw->max_bw[slice] = max(crtc_bw->max_bw[slice], data_rate); + crtc_bw->active_planes[slice] |= BIT(plane_id); + } +} + static void skl_crtc_calc_dbuf_bw(struct intel_bw_state *bw_state, const struct intel_crtc_state *crtc_state) { @@ -682,136 +751,145 @@ static void skl_crtc_calc_dbuf_bw(struct intel_bw_state *bw_state, struct intel_dbuf_bw *crtc_bw = &bw_state->dbuf_bw[crtc->pipe]; enum plane_id plane_id; - memset(&crtc_bw->used_bw, 0, sizeof(crtc_bw->used_bw)); + memset(crtc_bw, 0, sizeof(*crtc_bw)); if (!crtc_state->hw.active) return; for_each_plane_id_on_crtc(crtc, plane_id) { - const struct skl_ddb_entry *ddb_y = - &crtc_state->wm.skl.plane_ddb_y[plane_id]; - const struct skl_ddb_entry *ddb_uv = - &crtc_state->wm.skl.plane_ddb_uv[plane_id]; - unsigned int data_rate = crtc_state->data_rate[plane_id]; - unsigned int dbuf_mask = 0; - enum dbuf_slice slice; - - dbuf_mask |= skl_ddb_dbuf_slice_mask(i915, ddb_y); - dbuf_mask |= skl_ddb_dbuf_slice_mask(i915, ddb_uv); - /* - * FIXME: To calculate that more properly we probably - * need to split per plane data_rate into data_rate_y - * and data_rate_uv for multiplanar formats in order not - * to get accounted those twice if they happen to reside - * on different slices. - * However for pre-icl this would work anyway because - * we have only single slice and for icl+ uv plane has - * non-zero data rate. - * So in worst case those calculation are a bit - * pessimistic, which shouldn't pose any significant - * problem anyway. + * We assume cursors are small enough + * to not cause bandwidth problems. */ - for_each_dbuf_slice_in_mask(i915, slice, dbuf_mask) - crtc_bw->used_bw[slice] += data_rate; - } -} - -int skl_bw_calc_min_cdclk(struct intel_atomic_state *state) -{ - struct drm_i915_private *dev_priv = to_i915(state->base.dev); - struct intel_bw_state *new_bw_state = NULL; - struct intel_bw_state *old_bw_state = NULL; - const struct intel_crtc_state *crtc_state; - struct intel_crtc *crtc; - int max_bw = 0; - enum pipe pipe; - int i; - - for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) { - new_bw_state = intel_atomic_get_bw_state(state); - if (IS_ERR(new_bw_state)) - return PTR_ERR(new_bw_state); + if (plane_id == PLANE_CURSOR) + continue; - old_bw_state = intel_atomic_get_old_bw_state(state); + skl_plane_calc_dbuf_bw(bw_state, crtc, plane_id, + &crtc_state->wm.skl.plane_ddb[plane_id], + crtc_state->data_rate[plane_id]); - skl_crtc_calc_dbuf_bw(new_bw_state, crtc_state); + if (DISPLAY_VER(i915) < 11) + skl_plane_calc_dbuf_bw(bw_state, crtc, plane_id, + &crtc_state->wm.skl.plane_ddb_y[plane_id], + crtc_state->data_rate[plane_id]); } +} - if (!old_bw_state) - return 0; +/* "Maximum Data Buffer Bandwidth" */ +static int +intel_bw_dbuf_min_cdclk(struct drm_i915_private *i915, + const struct intel_bw_state *bw_state) +{ + unsigned int total_max_bw = 0; + enum dbuf_slice slice; - for_each_pipe(dev_priv, pipe) { - struct intel_dbuf_bw *crtc_bw; - enum dbuf_slice slice; + for_each_dbuf_slice(i915, slice) { + int num_active_planes = 0; + unsigned int max_bw = 0; + enum pipe pipe; - crtc_bw = &new_bw_state->dbuf_bw[pipe]; + /* + * The arbiter can only really guarantee an + * equal share of the total bw to each plane. + */ + for_each_pipe(i915, pipe) { + const struct intel_dbuf_bw *crtc_bw = &bw_state->dbuf_bw[pipe]; - for_each_dbuf_slice(dev_priv, slice) { - /* - * Current experimental observations show that contrary - * to BSpec we get underruns once we exceed 64 * CDCLK - * for slices in total. - * As a temporary measure in order not to keep CDCLK - * bumped up all the time we calculate CDCLK according - * to this formula for overall bw consumed by slices. - */ - max_bw += crtc_bw->used_bw[slice]; + max_bw = max(crtc_bw->max_bw[slice], max_bw); + num_active_planes += hweight8(crtc_bw->active_planes[slice]); } + max_bw *= num_active_planes; + + total_max_bw = max(total_max_bw, max_bw); } - new_bw_state->min_cdclk = max_bw / 64; + return DIV_ROUND_UP(total_max_bw, 64); +} - if (new_bw_state->min_cdclk != old_bw_state->min_cdclk) { - int ret = intel_atomic_lock_global_state(&new_bw_state->base); +int intel_bw_min_cdclk(struct drm_i915_private *i915, + const struct intel_bw_state *bw_state) +{ + enum pipe pipe; + int min_cdclk; - if (ret) - return ret; - } + min_cdclk = intel_bw_dbuf_min_cdclk(i915, bw_state); - return 0; + for_each_pipe(i915, pipe) + min_cdclk = max(bw_state->min_cdclk[pipe], min_cdclk); + + return min_cdclk; } -int intel_bw_calc_min_cdclk(struct intel_atomic_state *state) +int intel_bw_calc_min_cdclk(struct intel_atomic_state *state, + bool *need_cdclk_calc) { struct drm_i915_private *dev_priv = to_i915(state->base.dev); struct intel_bw_state *new_bw_state = NULL; - struct intel_bw_state *old_bw_state = NULL; + const struct intel_bw_state *old_bw_state = NULL; + const struct intel_cdclk_state *cdclk_state; const struct intel_crtc_state *crtc_state; + int old_min_cdclk, new_min_cdclk; struct intel_crtc *crtc; - int min_cdclk = 0; - enum pipe pipe; int i; + if (DISPLAY_VER(dev_priv) < 9) + return 0; + for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) { new_bw_state = intel_atomic_get_bw_state(state); if (IS_ERR(new_bw_state)) return PTR_ERR(new_bw_state); old_bw_state = intel_atomic_get_old_bw_state(state); + + skl_crtc_calc_dbuf_bw(new_bw_state, crtc_state); + + new_bw_state->min_cdclk[crtc->pipe] = + intel_bw_crtc_min_cdclk(crtc_state); } if (!old_bw_state) return 0; - for_each_pipe(dev_priv, pipe) { - struct intel_cdclk_state *cdclk_state; + if (intel_bw_state_changed(dev_priv, old_bw_state, new_bw_state)) { + int ret = intel_atomic_lock_global_state(&new_bw_state->base); + if (ret) + return ret; + } - cdclk_state = intel_atomic_get_new_cdclk_state(state); - if (!cdclk_state) - return 0; + old_min_cdclk = intel_bw_min_cdclk(dev_priv, old_bw_state); + new_min_cdclk = intel_bw_min_cdclk(dev_priv, new_bw_state); - min_cdclk = max(cdclk_state->min_cdclk[pipe], min_cdclk); - } + /* + * No need to check against the cdclk state if + * the min cdclk doesn't increase. + * + * Ie. we only ever increase the cdclk due to bandwidth + * requirements. This can reduce back and forth + * display blinking due to constant cdclk changes. + */ + if (new_min_cdclk <= old_min_cdclk) + return 0; - new_bw_state->min_cdclk = min_cdclk; + cdclk_state = intel_atomic_get_cdclk_state(state); + if (IS_ERR(cdclk_state)) + return PTR_ERR(cdclk_state); - if (new_bw_state->min_cdclk != old_bw_state->min_cdclk) { - int ret = intel_atomic_lock_global_state(&new_bw_state->base); + /* + * No need to recalculate the cdclk state if + * the min cdclk doesn't increase. + * + * Ie. we only ever increase the cdclk due to bandwidth + * requirements. This can reduce back and forth + * display blinking due to constant cdclk changes. + */ + if (new_min_cdclk <= cdclk_state->bw_min_cdclk) + return 0; - if (ret) - return ret; - } + drm_dbg_kms(&dev_priv->drm, + "new bandwidth min cdclk (%d kHz) > old min cdclk (%d kHz)\n", + new_min_cdclk, cdclk_state->bw_min_cdclk); + *need_cdclk_calc = true; return 0; } @@ -820,7 +898,7 @@ static u16 icl_qgv_points_mask(struct drm_i915_private *i915) { unsigned int num_psf_gv_points = i915->max_bw[0].num_psf_gv_points; unsigned int num_qgv_points = i915->max_bw[0].num_qgv_points; - u16 mask = 0; + u16 qgv_points = 0, psf_points = 0; /* * We can _not_ use the whole ADLS_QGV_PT_MASK here, as PCode rejects @@ -828,12 +906,12 @@ static u16 icl_qgv_points_mask(struct drm_i915_private *i915) * So need to operate only with those returned from PCode. */ if (num_qgv_points > 0) - mask |= REG_GENMASK(num_qgv_points - 1, 0); + qgv_points = GENMASK(num_qgv_points - 1, 0); if (num_psf_gv_points > 0) - mask |= REG_GENMASK(num_psf_gv_points - 1, 0) << ADLS_PSF_PT_SHIFT; + psf_points = GENMASK(num_psf_gv_points - 1, 0); - return mask; + return ICL_PCODE_REQ_QGV_PT(qgv_points) | ADLS_PCODE_REQ_PSF_PT(psf_points); } static int intel_bw_check_data_rate(struct intel_atomic_state *state, bool *changed) @@ -890,7 +968,7 @@ int intel_bw_atomic_check(struct intel_atomic_state *state) unsigned int data_rate; unsigned int num_active_planes; int i, ret; - u32 allowed_points = 0; + u16 qgv_points = 0, psf_points = 0; unsigned int max_bw_point = 0, max_bw = 0; unsigned int num_qgv_points = dev_priv->max_bw[0].num_qgv_points; unsigned int num_psf_gv_points = dev_priv->max_bw[0].num_psf_gv_points; @@ -948,7 +1026,7 @@ int intel_bw_atomic_check(struct intel_atomic_state *state) max_bw = max_data_rate; } if (max_data_rate >= data_rate) - allowed_points |= REG_FIELD_PREP(ADLS_QGV_PT_MASK, BIT(i)); + qgv_points |= BIT(i); drm_dbg_kms(&dev_priv->drm, "QGV point %d: max bw %d required %d\n", i, max_data_rate, data_rate); @@ -958,7 +1036,7 @@ int intel_bw_atomic_check(struct intel_atomic_state *state) unsigned int max_data_rate = adl_psf_bw(dev_priv, i); if (max_data_rate >= data_rate) - allowed_points |= REG_FIELD_PREP(ADLS_PSF_PT_MASK, BIT(i)); + psf_points |= BIT(i); drm_dbg_kms(&dev_priv->drm, "PSF GV point %d: max bw %d" " required %d\n", @@ -970,20 +1048,18 @@ int intel_bw_atomic_check(struct intel_atomic_state *state) * left, so if we couldn't - simply reject the configuration for obvious * reasons. */ - if ((allowed_points & ADLS_QGV_PT_MASK) == 0) { + if (qgv_points == 0) { drm_dbg_kms(&dev_priv->drm, "No QGV points provide sufficient memory" " bandwidth %d for display configuration(%d active planes).\n", data_rate, num_active_planes); return -EINVAL; } - if (num_psf_gv_points > 0) { - if ((allowed_points & ADLS_PSF_PT_MASK) == 0) { - drm_dbg_kms(&dev_priv->drm, "No PSF GV points provide sufficient memory" - " bandwidth %d for display configuration(%d active planes).\n", - data_rate, num_active_planes); - return -EINVAL; - } + if (num_psf_gv_points > 0 && psf_points == 0) { + drm_dbg_kms(&dev_priv->drm, "No PSF GV points provide sufficient memory" + " bandwidth %d for display configuration(%d active planes).\n", + data_rate, num_active_planes); + return -EINVAL; } /* @@ -992,16 +1068,18 @@ int intel_bw_atomic_check(struct intel_atomic_state *state) * cause. */ if (!intel_can_enable_sagv(dev_priv, new_bw_state)) { - allowed_points &= ADLS_PSF_PT_MASK; - allowed_points |= BIT(max_bw_point); + qgv_points = BIT(max_bw_point); drm_dbg_kms(&dev_priv->drm, "No SAGV, using single QGV point %d\n", max_bw_point); } + /* * We store the ones which need to be masked as that is what PCode * actually accepts as a parameter. */ - new_bw_state->qgv_points_mask = ~allowed_points & + new_bw_state->qgv_points_mask = + ~(ICL_PCODE_REQ_QGV_PT(qgv_points) | + ADLS_PCODE_REQ_PSF_PT(psf_points)) & icl_qgv_points_mask(dev_priv); /* diff --git a/drivers/gpu/drm/i915/display/intel_bw.h b/drivers/gpu/drm/i915/display/intel_bw.h index 0ceaed1c9656..cb7ee3a24a58 100644 --- a/drivers/gpu/drm/i915/display/intel_bw.h +++ b/drivers/gpu/drm/i915/display/intel_bw.h @@ -17,7 +17,8 @@ struct intel_atomic_state; struct intel_crtc_state; struct intel_dbuf_bw { - int used_bw[I915_MAX_DBUF_SLICES]; + unsigned int max_bw[I915_MAX_DBUF_SLICES]; + u8 active_planes[I915_MAX_DBUF_SLICES]; }; struct intel_bw_state { @@ -40,10 +41,9 @@ struct intel_bw_state { */ u16 qgv_points_mask; + int min_cdclk[I915_MAX_PIPES]; unsigned int data_rate[I915_MAX_PIPES]; u8 num_active_planes[I915_MAX_PIPES]; - - int min_cdclk; }; #define to_intel_bw_state(x) container_of((x), struct intel_bw_state, base) @@ -64,7 +64,9 @@ void intel_bw_crtc_update(struct intel_bw_state *bw_state, const struct intel_crtc_state *crtc_state); int icl_pcode_restrict_qgv_points(struct drm_i915_private *dev_priv, u32 points_mask); -int intel_bw_calc_min_cdclk(struct intel_atomic_state *state); -int skl_bw_calc_min_cdclk(struct intel_atomic_state *state); +int intel_bw_calc_min_cdclk(struct intel_atomic_state *state, + bool *need_cdclk_calc); +int intel_bw_min_cdclk(struct drm_i915_private *i915, + const struct intel_bw_state *bw_state); #endif /* __INTEL_BW_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index 8888fda8b701..b2017d8161b4 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -72,7 +72,6 @@ struct intel_cdclk_funcs { void (*set_cdclk)(struct drm_i915_private *i915, const struct intel_cdclk_config *cdclk_config, enum pipe pipe); - int (*bw_calc_min_cdclk)(struct intel_atomic_state *state); int (*modeset_calc_cdclk)(struct intel_cdclk_state *state); u8 (*calc_voltage_level)(int cdclk); }; @@ -83,12 +82,6 @@ void intel_cdclk_get_cdclk(struct drm_i915_private *dev_priv, dev_priv->cdclk_funcs->get_cdclk(dev_priv, cdclk_config); } -static int intel_cdclk_bw_calc_min_cdclk(struct intel_atomic_state *state) -{ - struct drm_i915_private *dev_priv = to_i915(state->base.dev); - return dev_priv->cdclk_funcs->bw_calc_min_cdclk(state); -} - static void intel_cdclk_set_cdclk(struct drm_i915_private *dev_priv, const struct intel_cdclk_config *cdclk_config, enum pipe pipe) @@ -2325,13 +2318,6 @@ int intel_crtc_compute_min_cdclk(const struct intel_crtc_state *crtc_state) dev_priv->max_cdclk_freq)); } - if (min_cdclk > dev_priv->max_cdclk_freq) { - drm_dbg_kms(&dev_priv->drm, - "required cdclk (%d kHz) exceeds max (%d kHz)\n", - min_cdclk, dev_priv->max_cdclk_freq); - return -EINVAL; - } - return min_cdclk; } @@ -2339,7 +2325,7 @@ static int intel_compute_min_cdclk(struct intel_cdclk_state *cdclk_state) { struct intel_atomic_state *state = cdclk_state->base.state; struct drm_i915_private *dev_priv = to_i915(state->base.dev); - struct intel_bw_state *bw_state = NULL; + const struct intel_bw_state *bw_state; struct intel_crtc *crtc; struct intel_crtc_state *crtc_state; int min_cdclk, i; @@ -2352,10 +2338,6 @@ static int intel_compute_min_cdclk(struct intel_cdclk_state *cdclk_state) if (min_cdclk < 0) return min_cdclk; - bw_state = intel_atomic_get_bw_state(state); - if (IS_ERR(bw_state)) - return PTR_ERR(bw_state); - if (cdclk_state->min_cdclk[crtc->pipe] == min_cdclk) continue; @@ -2366,14 +2348,31 @@ static int intel_compute_min_cdclk(struct intel_cdclk_state *cdclk_state) return ret; } - min_cdclk = cdclk_state->force_min_cdclk; - for_each_pipe(dev_priv, pipe) { - min_cdclk = max(cdclk_state->min_cdclk[pipe], min_cdclk); + bw_state = intel_atomic_get_new_bw_state(state); + if (bw_state) { + min_cdclk = intel_bw_min_cdclk(dev_priv, bw_state); - if (!bw_state) - continue; + if (cdclk_state->bw_min_cdclk != min_cdclk) { + int ret; + + cdclk_state->bw_min_cdclk = min_cdclk; + + ret = intel_atomic_lock_global_state(&cdclk_state->base); + if (ret) + return ret; + } + } + + min_cdclk = max(cdclk_state->force_min_cdclk, + cdclk_state->bw_min_cdclk); + for_each_pipe(dev_priv, pipe) + min_cdclk = max(cdclk_state->min_cdclk[pipe], min_cdclk); - min_cdclk = max(bw_state->min_cdclk, min_cdclk); + if (min_cdclk > dev_priv->max_cdclk_freq) { + drm_dbg_kms(&dev_priv->drm, + "required cdclk (%d kHz) exceeds max (%d kHz)\n", + min_cdclk, dev_priv->max_cdclk_freq); + return -EINVAL; } return min_cdclk; @@ -2654,14 +2653,10 @@ intel_atomic_get_cdclk_state(struct intel_atomic_state *state) int intel_cdclk_atomic_check(struct intel_atomic_state *state, bool *need_cdclk_calc) { - struct drm_i915_private *i915 = to_i915(state->base.dev); const struct intel_cdclk_state *old_cdclk_state; const struct intel_cdclk_state *new_cdclk_state; struct intel_plane_state *plane_state; - struct intel_bw_state *new_bw_state; struct intel_plane *plane; - int min_cdclk = 0; - enum pipe pipe; int ret; int i; @@ -2676,6 +2671,10 @@ int intel_cdclk_atomic_check(struct intel_atomic_state *state, return ret; } + ret = intel_bw_calc_min_cdclk(state, need_cdclk_calc); + if (ret) + return ret; + old_cdclk_state = intel_atomic_get_old_cdclk_state(state); new_cdclk_state = intel_atomic_get_new_cdclk_state(state); @@ -2683,23 +2682,6 @@ int intel_cdclk_atomic_check(struct intel_atomic_state *state, old_cdclk_state->force_min_cdclk != new_cdclk_state->force_min_cdclk) *need_cdclk_calc = true; - ret = intel_cdclk_bw_calc_min_cdclk(state); - if (ret) - return ret; - - new_bw_state = intel_atomic_get_new_bw_state(state); - - if (!new_cdclk_state || !new_bw_state) - return 0; - - for_each_pipe(i915, pipe) { - min_cdclk = max(new_cdclk_state->min_cdclk[pipe], min_cdclk); - - /* Currently do this change only if we need to increase */ - if (new_bw_state->min_cdclk > min_cdclk) - *need_cdclk_calc = true; - } - return 0; } @@ -3072,7 +3054,6 @@ u32 intel_read_rawclk(struct drm_i915_private *dev_priv) static const struct intel_cdclk_funcs tgl_cdclk_funcs = { .get_cdclk = bxt_get_cdclk, .set_cdclk = bxt_set_cdclk, - .bw_calc_min_cdclk = skl_bw_calc_min_cdclk, .modeset_calc_cdclk = bxt_modeset_calc_cdclk, .calc_voltage_level = tgl_calc_voltage_level, }; @@ -3080,7 +3061,6 @@ static const struct intel_cdclk_funcs tgl_cdclk_funcs = { static const struct intel_cdclk_funcs ehl_cdclk_funcs = { .get_cdclk = bxt_get_cdclk, .set_cdclk = bxt_set_cdclk, - .bw_calc_min_cdclk = skl_bw_calc_min_cdclk, .modeset_calc_cdclk = bxt_modeset_calc_cdclk, .calc_voltage_level = ehl_calc_voltage_level, }; @@ -3088,7 +3068,6 @@ static const struct intel_cdclk_funcs ehl_cdclk_funcs = { static const struct intel_cdclk_funcs icl_cdclk_funcs = { .get_cdclk = bxt_get_cdclk, .set_cdclk = bxt_set_cdclk, - .bw_calc_min_cdclk = skl_bw_calc_min_cdclk, .modeset_calc_cdclk = bxt_modeset_calc_cdclk, .calc_voltage_level = icl_calc_voltage_level, }; @@ -3096,7 +3075,6 @@ static const struct intel_cdclk_funcs icl_cdclk_funcs = { static const struct intel_cdclk_funcs bxt_cdclk_funcs = { .get_cdclk = bxt_get_cdclk, .set_cdclk = bxt_set_cdclk, - .bw_calc_min_cdclk = skl_bw_calc_min_cdclk, .modeset_calc_cdclk = bxt_modeset_calc_cdclk, .calc_voltage_level = bxt_calc_voltage_level, }; @@ -3104,53 +3082,45 @@ static const struct intel_cdclk_funcs bxt_cdclk_funcs = { static const struct intel_cdclk_funcs skl_cdclk_funcs = { .get_cdclk = skl_get_cdclk, .set_cdclk = skl_set_cdclk, - .bw_calc_min_cdclk = skl_bw_calc_min_cdclk, .modeset_calc_cdclk = skl_modeset_calc_cdclk, }; static const struct intel_cdclk_funcs bdw_cdclk_funcs = { .get_cdclk = bdw_get_cdclk, .set_cdclk = bdw_set_cdclk, - .bw_calc_min_cdclk = intel_bw_calc_min_cdclk, .modeset_calc_cdclk = bdw_modeset_calc_cdclk, }; static const struct intel_cdclk_funcs chv_cdclk_funcs = { .get_cdclk = vlv_get_cdclk, .set_cdclk = chv_set_cdclk, - .bw_calc_min_cdclk = intel_bw_calc_min_cdclk, .modeset_calc_cdclk = vlv_modeset_calc_cdclk, }; static const struct intel_cdclk_funcs vlv_cdclk_funcs = { .get_cdclk = vlv_get_cdclk, .set_cdclk = vlv_set_cdclk, - .bw_calc_min_cdclk = intel_bw_calc_min_cdclk, .modeset_calc_cdclk = vlv_modeset_calc_cdclk, }; static const struct intel_cdclk_funcs hsw_cdclk_funcs = { .get_cdclk = hsw_get_cdclk, - .bw_calc_min_cdclk = intel_bw_calc_min_cdclk, .modeset_calc_cdclk = fixed_modeset_calc_cdclk, }; /* SNB, IVB, 965G, 945G */ static const struct intel_cdclk_funcs fixed_400mhz_cdclk_funcs = { .get_cdclk = fixed_400mhz_get_cdclk, - .bw_calc_min_cdclk = intel_bw_calc_min_cdclk, .modeset_calc_cdclk = fixed_modeset_calc_cdclk, }; static const struct intel_cdclk_funcs ilk_cdclk_funcs = { .get_cdclk = fixed_450mhz_get_cdclk, - .bw_calc_min_cdclk = intel_bw_calc_min_cdclk, .modeset_calc_cdclk = fixed_modeset_calc_cdclk, }; static const struct intel_cdclk_funcs gm45_cdclk_funcs = { .get_cdclk = gm45_get_cdclk, - .bw_calc_min_cdclk = intel_bw_calc_min_cdclk, .modeset_calc_cdclk = fixed_modeset_calc_cdclk, }; @@ -3158,7 +3128,6 @@ static const struct intel_cdclk_funcs gm45_cdclk_funcs = { static const struct intel_cdclk_funcs i965gm_cdclk_funcs = { .get_cdclk = i965gm_get_cdclk, - .bw_calc_min_cdclk = intel_bw_calc_min_cdclk, .modeset_calc_cdclk = fixed_modeset_calc_cdclk, }; @@ -3166,19 +3135,16 @@ static const struct intel_cdclk_funcs i965gm_cdclk_funcs = { static const struct intel_cdclk_funcs pnv_cdclk_funcs = { .get_cdclk = pnv_get_cdclk, - .bw_calc_min_cdclk = intel_bw_calc_min_cdclk, .modeset_calc_cdclk = fixed_modeset_calc_cdclk, }; static const struct intel_cdclk_funcs g33_cdclk_funcs = { .get_cdclk = g33_get_cdclk, - .bw_calc_min_cdclk = intel_bw_calc_min_cdclk, .modeset_calc_cdclk = fixed_modeset_calc_cdclk, }; static const struct intel_cdclk_funcs i945gm_cdclk_funcs = { .get_cdclk = i945gm_get_cdclk, - .bw_calc_min_cdclk = intel_bw_calc_min_cdclk, .modeset_calc_cdclk = fixed_modeset_calc_cdclk, }; @@ -3186,37 +3152,31 @@ static const struct intel_cdclk_funcs i945gm_cdclk_funcs = { static const struct intel_cdclk_funcs i915gm_cdclk_funcs = { .get_cdclk = i915gm_get_cdclk, - .bw_calc_min_cdclk = intel_bw_calc_min_cdclk, .modeset_calc_cdclk = fixed_modeset_calc_cdclk, }; static const struct intel_cdclk_funcs i915g_cdclk_funcs = { .get_cdclk = fixed_333mhz_get_cdclk, - .bw_calc_min_cdclk = intel_bw_calc_min_cdclk, .modeset_calc_cdclk = fixed_modeset_calc_cdclk, }; static const struct intel_cdclk_funcs i865g_cdclk_funcs = { .get_cdclk = fixed_266mhz_get_cdclk, - .bw_calc_min_cdclk = intel_bw_calc_min_cdclk, .modeset_calc_cdclk = fixed_modeset_calc_cdclk, }; static const struct intel_cdclk_funcs i85x_cdclk_funcs = { .get_cdclk = i85x_get_cdclk, - .bw_calc_min_cdclk = intel_bw_calc_min_cdclk, .modeset_calc_cdclk = fixed_modeset_calc_cdclk, }; static const struct intel_cdclk_funcs i845g_cdclk_funcs = { .get_cdclk = fixed_200mhz_get_cdclk, - .bw_calc_min_cdclk = intel_bw_calc_min_cdclk, .modeset_calc_cdclk = fixed_modeset_calc_cdclk, }; static const struct intel_cdclk_funcs i830_cdclk_funcs = { .get_cdclk = fixed_133mhz_get_cdclk, - .bw_calc_min_cdclk = intel_bw_calc_min_cdclk, .modeset_calc_cdclk = fixed_modeset_calc_cdclk, }; diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.h b/drivers/gpu/drm/i915/display/intel_cdclk.h index df66f66fbad0..b535cf6a7d9e 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.h +++ b/drivers/gpu/drm/i915/display/intel_cdclk.h @@ -36,6 +36,8 @@ struct intel_cdclk_state { */ struct intel_cdclk_config actual; + /* minimum acceptable cdclk to satisfy bandwidth requirements */ + int bw_min_cdclk; /* minimum acceptable cdclk for each pipe */ int min_cdclk[I915_MAX_PIPES]; /* minimum acceptable voltage level for each pipe */ diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index e94ec57260f1..34128c9c635c 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -31,12 +31,21 @@ struct intel_color_funcs { int (*color_check)(struct intel_crtc_state *crtc_state); /* - * Program double buffered color management registers during - * vblank evasion. The registers should then latch during the - * next vblank start, alongside any other double buffered registers - * involved with the same commit. + * Program non-arming double buffered color management registers + * before vblank evasion. The registers should then latch after + * the arming register is written (by color_commit_arm()) during + * the next vblank start, alongside any other double buffered + * registers involved with the same commit. This hook is optional. + */ + void (*color_commit_noarm)(const struct intel_crtc_state *crtc_state); + /* + * Program arming double buffered color management registers + * during vblank evasion. The registers (and whatever other registers + * they arm that were written by color_commit_noarm) should then latch + * during the next vblank start, alongside any other double buffered + * registers involved with the same commit. */ - void (*color_commit)(const struct intel_crtc_state *crtc_state); + void (*color_commit_arm)(const struct intel_crtc_state *crtc_state); /* * Load LUTs (and other single buffered color management * registers). Will (hopefully) be called during the vblank @@ -337,15 +346,11 @@ static void ilk_load_csc_matrix(const struct intel_crtc_state *crtc_state) ilk_csc_coeff_identity, ilk_csc_off_zero); } - - intel_de_write_fw(dev_priv, PIPE_CSC_MODE(crtc->pipe), - crtc_state->csc_mode); } static void icl_load_csc_matrix(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); if (crtc_state->hw.ctm) { u16 coeff[9]; @@ -364,9 +369,6 @@ static void icl_load_csc_matrix(const struct intel_crtc_state *crtc_state) ilk_csc_coeff_limited_range, ilk_csc_postoff_limited_range); } - - intel_de_write_fw(dev_priv, PIPE_CSC_MODE(crtc->pipe), - crtc_state->csc_mode); } static void chv_load_cgm_csc(struct intel_crtc *crtc, @@ -491,7 +493,17 @@ static void icl_lut_multi_seg_pack(struct drm_color_lut *entry, u32 ldw, u32 udw REG_FIELD_GET(PAL_PREC_MULTI_SEG_BLUE_LDW_MASK, ldw); } -static void i9xx_color_commit(const struct intel_crtc_state *crtc_state) +static void icl_color_commit_noarm(const struct intel_crtc_state *crtc_state) +{ + icl_load_csc_matrix(crtc_state); +} + +static void ilk_color_commit_noarm(const struct intel_crtc_state *crtc_state) +{ + ilk_load_csc_matrix(crtc_state); +} + +static void i9xx_color_commit_arm(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); @@ -504,7 +516,7 @@ static void i9xx_color_commit(const struct intel_crtc_state *crtc_state) intel_de_write(dev_priv, PIPECONF(pipe), val); } -static void ilk_color_commit(const struct intel_crtc_state *crtc_state) +static void ilk_color_commit_arm(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); @@ -516,10 +528,11 @@ static void ilk_color_commit(const struct intel_crtc_state *crtc_state) val |= PIPECONF_GAMMA_MODE(crtc_state->gamma_mode); intel_de_write(dev_priv, PIPECONF(pipe), val); - ilk_load_csc_matrix(crtc_state); + intel_de_write_fw(dev_priv, PIPE_CSC_MODE(pipe), + crtc_state->csc_mode); } -static void hsw_color_commit(const struct intel_crtc_state *crtc_state) +static void hsw_color_commit_arm(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); @@ -527,10 +540,11 @@ static void hsw_color_commit(const struct intel_crtc_state *crtc_state) intel_de_write(dev_priv, GAMMA_MODE(crtc->pipe), crtc_state->gamma_mode); - ilk_load_csc_matrix(crtc_state); + intel_de_write_fw(dev_priv, PIPE_CSC_MODE(crtc->pipe), + crtc_state->csc_mode); } -static void skl_color_commit(const struct intel_crtc_state *crtc_state) +static void skl_color_commit_arm(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); @@ -551,10 +565,8 @@ static void skl_color_commit(const struct intel_crtc_state *crtc_state) intel_de_write(dev_priv, GAMMA_MODE(crtc->pipe), crtc_state->gamma_mode); - if (DISPLAY_VER(dev_priv) >= 11) - icl_load_csc_matrix(crtc_state); - else - ilk_load_csc_matrix(crtc_state); + intel_de_write_fw(dev_priv, PIPE_CSC_MODE(crtc->pipe), + crtc_state->csc_mode); } static void i9xx_load_lut_8(struct intel_crtc *crtc, @@ -1169,11 +1181,19 @@ void intel_color_load_luts(const struct intel_crtc_state *crtc_state) dev_priv->color_funcs->load_luts(crtc_state); } -void intel_color_commit(const struct intel_crtc_state *crtc_state) +void intel_color_commit_noarm(const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); + + if (dev_priv->color_funcs->color_commit_noarm) + dev_priv->color_funcs->color_commit_noarm(crtc_state); +} + +void intel_color_commit_arm(const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); - dev_priv->color_funcs->color_commit(crtc_state); + dev_priv->color_funcs->color_commit_arm(crtc_state); } static bool intel_can_preload_luts(const struct intel_crtc_state *new_crtc_state) @@ -2132,70 +2152,77 @@ static void icl_read_luts(struct intel_crtc_state *crtc_state) static const struct intel_color_funcs chv_color_funcs = { .color_check = chv_color_check, - .color_commit = i9xx_color_commit, + .color_commit_arm = i9xx_color_commit_arm, .load_luts = chv_load_luts, .read_luts = chv_read_luts, }; static const struct intel_color_funcs i965_color_funcs = { .color_check = i9xx_color_check, - .color_commit = i9xx_color_commit, + .color_commit_arm = i9xx_color_commit_arm, .load_luts = i965_load_luts, .read_luts = i965_read_luts, }; static const struct intel_color_funcs i9xx_color_funcs = { .color_check = i9xx_color_check, - .color_commit = i9xx_color_commit, + .color_commit_arm = i9xx_color_commit_arm, .load_luts = i9xx_load_luts, .read_luts = i9xx_read_luts, }; static const struct intel_color_funcs icl_color_funcs = { .color_check = icl_color_check, - .color_commit = skl_color_commit, + .color_commit_noarm = icl_color_commit_noarm, + .color_commit_arm = skl_color_commit_arm, .load_luts = icl_load_luts, .read_luts = icl_read_luts, }; static const struct intel_color_funcs glk_color_funcs = { .color_check = glk_color_check, - .color_commit = skl_color_commit, + .color_commit_noarm = ilk_color_commit_noarm, + .color_commit_arm = skl_color_commit_arm, .load_luts = glk_load_luts, .read_luts = glk_read_luts, }; static const struct intel_color_funcs skl_color_funcs = { .color_check = ivb_color_check, - .color_commit = skl_color_commit, + .color_commit_noarm = ilk_color_commit_noarm, + .color_commit_arm = skl_color_commit_arm, .load_luts = bdw_load_luts, .read_luts = NULL, }; static const struct intel_color_funcs bdw_color_funcs = { .color_check = ivb_color_check, - .color_commit = hsw_color_commit, + .color_commit_noarm = ilk_color_commit_noarm, + .color_commit_arm = hsw_color_commit_arm, .load_luts = bdw_load_luts, .read_luts = NULL, }; static const struct intel_color_funcs hsw_color_funcs = { .color_check = ivb_color_check, - .color_commit = hsw_color_commit, + .color_commit_noarm = ilk_color_commit_noarm, + .color_commit_arm = hsw_color_commit_arm, .load_luts = ivb_load_luts, .read_luts = NULL, }; static const struct intel_color_funcs ivb_color_funcs = { .color_check = ivb_color_check, - .color_commit = ilk_color_commit, + .color_commit_noarm = ilk_color_commit_noarm, + .color_commit_arm = ilk_color_commit_arm, .load_luts = ivb_load_luts, .read_luts = NULL, }; static const struct intel_color_funcs ilk_color_funcs = { .color_check = ilk_color_check, - .color_commit = ilk_color_commit, + .color_commit_noarm = ilk_color_commit_noarm, + .color_commit_arm = ilk_color_commit_arm, .load_luts = ilk_load_luts, .read_luts = ilk_read_luts, }; diff --git a/drivers/gpu/drm/i915/display/intel_color.h b/drivers/gpu/drm/i915/display/intel_color.h index 173727aaa24d..fd873425e082 100644 --- a/drivers/gpu/drm/i915/display/intel_color.h +++ b/drivers/gpu/drm/i915/display/intel_color.h @@ -14,7 +14,8 @@ struct drm_property_blob; void intel_color_init(struct intel_crtc *crtc); int intel_color_check(struct intel_crtc_state *crtc_state); -void intel_color_commit(const struct intel_crtc_state *crtc_state); +void intel_color_commit_noarm(const struct intel_crtc_state *crtc_state); +void intel_color_commit_arm(const struct intel_crtc_state *crtc_state); void intel_color_load_luts(const struct intel_crtc_state *crtc_state); void intel_color_get_config(struct intel_crtc_state *crtc_state); int intel_color_get_gamma_bit_precision(const struct intel_crtc_state *crtc_state); diff --git a/drivers/gpu/drm/i915/display/intel_combo_phy.c b/drivers/gpu/drm/i915/display/intel_combo_phy.c index 4dfe77351b8b..64890f39c3cc 100644 --- a/drivers/gpu/drm/i915/display/intel_combo_phy.c +++ b/drivers/gpu/drm/i915/display/intel_combo_phy.c @@ -25,18 +25,29 @@ enum { }; static const struct icl_procmon { + const char *name; u32 dw1, dw9, dw10; } icl_procmon_values[] = { - [PROCMON_0_85V_DOT_0] = - { .dw1 = 0x00000000, .dw9 = 0x62AB67BB, .dw10 = 0x51914F96, }, - [PROCMON_0_95V_DOT_0] = - { .dw1 = 0x00000000, .dw9 = 0x86E172C7, .dw10 = 0x77CA5EAB, }, - [PROCMON_0_95V_DOT_1] = - { .dw1 = 0x00000000, .dw9 = 0x93F87FE1, .dw10 = 0x8AE871C5, }, - [PROCMON_1_05V_DOT_0] = - { .dw1 = 0x00000000, .dw9 = 0x98FA82DD, .dw10 = 0x89E46DC1, }, - [PROCMON_1_05V_DOT_1] = - { .dw1 = 0x00440000, .dw9 = 0x9A00AB25, .dw10 = 0x8AE38FF1, }, + [PROCMON_0_85V_DOT_0] = { + .name = "0.85V dot0 (low-voltage)", + .dw1 = 0x00000000, .dw9 = 0x62AB67BB, .dw10 = 0x51914F96, + }, + [PROCMON_0_95V_DOT_0] = { + .name = "0.95V dot0", + .dw1 = 0x00000000, .dw9 = 0x86E172C7, .dw10 = 0x77CA5EAB, + }, + [PROCMON_0_95V_DOT_1] = { + .name = "0.95V dot1", + .dw1 = 0x00000000, .dw9 = 0x93F87FE1, .dw10 = 0x8AE871C5, + }, + [PROCMON_1_05V_DOT_0] = { + .name = "1.05V dot0", + .dw1 = 0x00000000, .dw9 = 0x98FA82DD, .dw10 = 0x89E46DC1, + }, + [PROCMON_1_05V_DOT_1] = { + .name = "1.05V dot1", + .dw1 = 0x00440000, .dw9 = 0x9A00AB25, .dw10 = 0x8AE38FF1, + }, }; static const struct icl_procmon * @@ -113,6 +124,10 @@ static bool icl_verify_procmon_ref_values(struct drm_i915_private *dev_priv, procmon = icl_get_procmon_ref_values(dev_priv, phy); + drm_dbg_kms(&dev_priv->drm, + "Combo PHY %c Voltage/Process Info : %s\n", + phy_name(phy), procmon->name); + ret = check_phy_reg(dev_priv, phy, ICL_PORT_COMP_DW1(phy), (0xff << 16) | 0xff, procmon->dw1); ret &= check_phy_reg(dev_priv, phy, ICL_PORT_COMP_DW9(phy), diff --git a/drivers/gpu/drm/i915/display/intel_connector.c b/drivers/gpu/drm/i915/display/intel_connector.c index c65f95a9a1ec..1dcc268927a2 100644 --- a/drivers/gpu/drm/i915/display/intel_connector.c +++ b/drivers/gpu/drm/i915/display/intel_connector.c @@ -54,6 +54,8 @@ int intel_connector_init(struct intel_connector *connector) __drm_atomic_helper_connector_reset(&connector->base, &conn_state->base); + INIT_LIST_HEAD(&connector->panel.fixed_modes); + return 0; } @@ -100,7 +102,7 @@ void intel_connector_destroy(struct drm_connector *connector) if (!IS_ERR_OR_NULL(intel_connector->edid)) kfree(intel_connector->edid); - intel_panel_fini(&intel_connector->panel); + intel_panel_fini(intel_connector); drm_connector_cleanup(connector); diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c index 65827481c1b1..4442aa355f86 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc.c +++ b/drivers/gpu/drm/i915/display/intel_crtc.c @@ -24,6 +24,7 @@ #include "intel_display_debugfs.h" #include "intel_display_trace.h" #include "intel_display_types.h" +#include "intel_drrs.h" #include "intel_dsi.h" #include "intel_pipe_crc.h" #include "intel_psr.h" @@ -367,6 +368,7 @@ int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe) intel_color_init(crtc); + intel_crtc_drrs_init(crtc); intel_crtc_crc_init(crtc); cpu_latency_qos_add_request(&crtc->vblank_pm_qos, PM_QOS_DEFAULT_VALUE); @@ -485,6 +487,8 @@ void intel_pipe_update_start(struct intel_crtc_state *new_crtc_state) intel_crtc_has_type(new_crtc_state, INTEL_OUTPUT_DSI); DEFINE_WAIT(wait); + intel_psr_lock(new_crtc_state); + if (new_crtc_state->do_async_flip) return; @@ -516,7 +520,7 @@ void intel_pipe_update_start(struct intel_crtc_state *new_crtc_state) * VBL interrupts will start the PSR exit and prevent a PSR * re-entry as well. */ - intel_psr_wait_for_idle(new_crtc_state); + intel_psr_wait_for_idle_locked(new_crtc_state); local_irq_disable(); @@ -630,6 +634,8 @@ void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state) ktime_t end_vbl_time = ktime_get(); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + intel_psr_unlock(new_crtc_state); + if (new_crtc_state->do_async_flip) return; diff --git a/drivers/gpu/drm/i915/display/intel_cursor.c b/drivers/gpu/drm/i915/display/intel_cursor.c index 2ade8fdd9bdd..8c80de877605 100644 --- a/drivers/gpu/drm/i915/display/intel_cursor.c +++ b/drivers/gpu/drm/i915/display/intel_cursor.c @@ -153,6 +153,11 @@ static int intel_check_cursor(struct intel_crtc_state *crtc_state, plane_state->uapi.src = src; plane_state->uapi.dst = dst; + /* final plane coordinates will be relative to the plane's pipe */ + drm_rect_translate(&plane_state->uapi.dst, + -crtc_state->pipe_src.x1, + -crtc_state->pipe_src.y1); + ret = intel_cursor_check_surface(plane_state); if (ret) return ret; @@ -255,7 +260,6 @@ static void i845_cursor_update_arm(struct intel_plane *plane, { struct drm_i915_private *dev_priv = to_i915(plane->base.dev); u32 cntl = 0, base = 0, pos = 0, size = 0; - unsigned long irqflags; if (plane_state && plane_state->uapi.visible) { unsigned int width = drm_rect_width(&plane_state->uapi.dst); @@ -270,8 +274,6 @@ static void i845_cursor_update_arm(struct intel_plane *plane, pos = intel_cursor_position(plane_state); } - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); - /* On these chipsets we can only modify the base/size/stride * whilst the cursor is disabled. */ @@ -290,8 +292,6 @@ static void i845_cursor_update_arm(struct intel_plane *plane, } else { intel_de_write_fw(dev_priv, CURPOS(PIPE_A), pos); } - - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } static void i845_cursor_disable_arm(struct intel_plane *plane, @@ -492,7 +492,6 @@ static void i9xx_cursor_update_arm(struct intel_plane *plane, struct drm_i915_private *dev_priv = to_i915(plane->base.dev); enum pipe pipe = plane->pipe; u32 cntl = 0, base = 0, pos = 0, fbc_ctl = 0; - unsigned long irqflags; if (plane_state && plane_state->uapi.visible) { int width = drm_rect_width(&plane_state->uapi.dst); @@ -508,8 +507,6 @@ static void i9xx_cursor_update_arm(struct intel_plane *plane, pos = intel_cursor_position(plane_state); } - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); - /* * On some platforms writing CURCNTR first will also * cause CURPOS to be armed by the CURBASE write. @@ -555,8 +552,6 @@ static void i9xx_cursor_update_arm(struct intel_plane *plane, intel_de_write_fw(dev_priv, CURPOS(pipe), pos); intel_de_write_fw(dev_priv, CURBASE(pipe), base); } - - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } static void i9xx_cursor_disable_arm(struct intel_plane *plane, @@ -637,7 +632,7 @@ intel_legacy_cursor_update(struct drm_plane *_plane, * FIXME bigjoiner fastpath would be good */ if (!crtc_state->hw.active || intel_crtc_needs_modeset(crtc_state) || - crtc_state->update_pipe || crtc_state->bigjoiner) + crtc_state->update_pipe || crtc_state->bigjoiner_pipes) goto slow; /* @@ -715,6 +710,14 @@ intel_legacy_cursor_update(struct drm_plane *_plane, */ crtc_state->active_planes = new_crtc_state->active_planes; + /* + * Technically we should do a vblank evasion here to make + * sure all the cursor registers update on the same frame. + * For now just make sure the register writes happen as + * quickly as possible to minimize the race window. + */ + local_irq_disable(); + if (new_plane_state->uapi.visible) { intel_plane_update_noarm(plane, crtc_state, new_plane_state); intel_plane_update_arm(plane, crtc_state, new_plane_state); @@ -722,6 +725,8 @@ intel_legacy_cursor_update(struct drm_plane *_plane, intel_plane_disable_arm(plane, crtc_state); } + local_irq_enable(); + intel_plane_unpin_fb(old_plane_state); out_free: diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index e4260806c2a4..027cc4cc38d9 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -25,6 +25,8 @@ * */ +#include <linux/string_helpers.h> + #include <drm/drm_privacy_screen_consumer.h> #include <drm/drm_scdc_helper.h> @@ -43,7 +45,6 @@ #include "intel_dp_link_training.h" #include "intel_dp_mst.h" #include "intel_dpio_phy.h" -#include "intel_drrs.h" #include "intel_dsi.h" #include "intel_fdi.h" #include "intel_fifo_underrun.h" @@ -2152,7 +2153,7 @@ static void intel_dp_sink_set_msa_timing_par_ignore_state(struct intel_dp *intel enable ? DP_MSA_TIMING_PAR_IGNORE_EN : 0) <= 0) drm_dbg_kms(&i915->drm, "Failed to %s MSA_TIMING_PAR_IGNORE in the sink\n", - enabledisable(enable)); + str_enable_disable(enable)); } static void intel_dp_sink_set_fec_ready(struct intel_dp *intel_dp, @@ -2818,10 +2819,7 @@ static void intel_enable_ddi_dp(struct intel_atomic_state *state, if (!dig_port->lspcon.active || dig_port->dp.has_hdmi_sink) intel_dp_set_infoframes(encoder, true, crtc_state, conn_state); - intel_drrs_enable(intel_dp, crtc_state); - - if (crtc_state->has_audio) - intel_audio_codec_enable(encoder, crtc_state, conn_state); + intel_audio_codec_enable(encoder, crtc_state, conn_state); trans_port_sync_stop_link_train(state, encoder, crtc_state); } @@ -2915,8 +2913,7 @@ static void intel_enable_ddi_hdmi(struct intel_atomic_state *state, intel_de_write(dev_priv, DDI_BUF_CTL(port), dig_port->saved_port_bits | DDI_BUF_CTL_ENABLE); - if (crtc_state->has_audio) - intel_audio_codec_enable(encoder, crtc_state, conn_state); + intel_audio_codec_enable(encoder, crtc_state, conn_state); } static void intel_enable_ddi(struct intel_atomic_state *state, @@ -2957,11 +2954,8 @@ static void intel_disable_ddi_dp(struct intel_atomic_state *state, intel_dp->link_trained = false; - if (old_crtc_state->has_audio) - intel_audio_codec_disable(encoder, - old_crtc_state, old_conn_state); + intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); - intel_drrs_disable(intel_dp, old_crtc_state); intel_psr_disable(intel_dp, old_crtc_state); intel_edp_backlight_off(old_conn_state); /* Disable the decompression in DP Sink */ @@ -2980,9 +2974,7 @@ static void intel_disable_ddi_hdmi(struct intel_atomic_state *state, struct drm_i915_private *i915 = to_i915(encoder->base.dev); struct drm_connector *connector = old_conn_state->connector; - if (old_crtc_state->has_audio) - intel_audio_codec_disable(encoder, - old_crtc_state, old_conn_state); + intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); if (!intel_hdmi_handle_sink_scrambling(encoder, connector, false, false)) @@ -3011,12 +3003,9 @@ static void intel_ddi_update_pipe_dp(struct intel_atomic_state *state, const struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state) { - struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - intel_ddi_set_dp_msa(crtc_state, conn_state); intel_dp_set_infoframes(encoder, true, crtc_state, conn_state); - intel_drrs_update(intel_dp, crtc_state); intel_backlight_update(state, encoder, crtc_state, conn_state); drm_connector_update_privacy_screen(conn_state); @@ -4308,6 +4297,13 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port) return; } + if (intel_phy_is_snps(dev_priv, phy) && + dev_priv->snps_phy_failed_calibration & BIT(phy)) { + drm_dbg_kms(&dev_priv->drm, + "SNPS PHY %c failed to calibrate, proceeding anyway\n", + phy_name(phy)); + } + dig_port = kzalloc(sizeof(*dig_port), GFP_KERNEL); if (!dig_port) return; diff --git a/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c index 934a9f9e7dab..94e64661b4fd 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c +++ b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c @@ -907,7 +907,7 @@ static const union intel_ddi_buf_trans_entry _adlp_combo_phy_trans_dp_hbr[] = { { .icl = { 0xA, 0x4C, 0x3F, 0x00, 0x00 } }, /* 500 500 0.0 */ { .icl = { 0xC, 0x73, 0x34, 0x00, 0x0B } }, /* 500 700 2.9 */ { .icl = { 0x6, 0x7F, 0x2F, 0x00, 0x10 } }, /* 500 900 5.1 */ - { .icl = { 0xC, 0x73, 0x3E, 0x00, 0x01 } }, /* 650 700 0.6 */ + { .icl = { 0xC, 0x7C, 0x3C, 0x00, 0x03 } }, /* 650 700 0.6 */ { .icl = { 0x6, 0x7F, 0x35, 0x00, 0x0A } }, /* 600 900 3.5 */ { .icl = { 0x6, 0x7F, 0x3F, 0x00, 0x00 } }, /* 900 900 0.0 */ }; @@ -921,7 +921,7 @@ static const union intel_ddi_buf_trans_entry _adlp_combo_phy_trans_dp_hbr2_hbr3[ /* NT mV Trans mV db */ { .icl = { 0xA, 0x35, 0x3F, 0x00, 0x00 } }, /* 350 350 0.0 */ { .icl = { 0xA, 0x4F, 0x37, 0x00, 0x08 } }, /* 350 500 3.1 */ - { .icl = { 0xC, 0x71, 0x2F, 0x00, 0x10 } }, /* 350 700 6.0 */ + { .icl = { 0xC, 0x71, 0x30, 0x00, 0x0F } }, /* 350 700 6.0 */ { .icl = { 0x6, 0x7F, 0x2B, 0x00, 0x14 } }, /* 350 900 8.2 */ { .icl = { 0xA, 0x4C, 0x3F, 0x00, 0x00 } }, /* 500 500 0.0 */ { .icl = { 0xC, 0x73, 0x34, 0x00, 0x0B } }, /* 500 700 2.9 */ @@ -931,19 +931,47 @@ static const union intel_ddi_buf_trans_entry _adlp_combo_phy_trans_dp_hbr2_hbr3[ { .icl = { 0x6, 0x7F, 0x3F, 0x00, 0x00 } }, /* 900 900 0.0 */ }; +static const union intel_ddi_buf_trans_entry _adlp_combo_phy_trans_edp_hbr2[] = { + /* NT mV Trans mV db */ + { .icl = { 0x4, 0x50, 0x38, 0x00, 0x07 } }, /* 200 200 0.0 */ + { .icl = { 0x4, 0x58, 0x35, 0x00, 0x0A } }, /* 200 250 1.9 */ + { .icl = { 0x4, 0x60, 0x34, 0x00, 0x0B } }, /* 200 300 3.5 */ + { .icl = { 0x4, 0x6A, 0x32, 0x00, 0x0D } }, /* 200 350 4.9 */ + { .icl = { 0x4, 0x5E, 0x38, 0x00, 0x07 } }, /* 250 250 0.0 */ + { .icl = { 0x4, 0x61, 0x36, 0x00, 0x09 } }, /* 250 300 1.6 */ + { .icl = { 0x4, 0x6B, 0x34, 0x00, 0x0B } }, /* 250 350 2.9 */ + { .icl = { 0x4, 0x69, 0x39, 0x00, 0x06 } }, /* 300 300 0.0 */ + { .icl = { 0x4, 0x73, 0x37, 0x00, 0x08 } }, /* 300 350 1.3 */ + { .icl = { 0x4, 0x7A, 0x38, 0x00, 0x07 } }, /* 350 350 0.0 */ +}; + +static const union intel_ddi_buf_trans_entry _adlp_combo_phy_trans_dp_hbr2_edp_hbr3[] = { + /* NT mV Trans mV db */ + { .icl = { 0xA, 0x35, 0x3F, 0x00, 0x00 } }, /* 350 350 0.0 */ + { .icl = { 0xA, 0x4F, 0x37, 0x00, 0x08 } }, /* 350 500 3.1 */ + { .icl = { 0xC, 0x71, 0x30, 0x00, 0x0f } }, /* 350 700 6.0 */ + { .icl = { 0x6, 0x7F, 0x2B, 0x00, 0x14 } }, /* 350 900 8.2 */ + { .icl = { 0xA, 0x4C, 0x3F, 0x00, 0x00 } }, /* 500 500 0.0 */ + { .icl = { 0xC, 0x73, 0x34, 0x00, 0x0B } }, /* 500 700 2.9 */ + { .icl = { 0x6, 0x7F, 0x2F, 0x00, 0x10 } }, /* 500 900 5.1 */ + { .icl = { 0xC, 0x6C, 0x3C, 0x00, 0x03 } }, /* 650 700 0.6 */ + { .icl = { 0x6, 0x7F, 0x35, 0x00, 0x0A } }, /* 600 900 3.5 */ + { .icl = { 0x6, 0x7F, 0x3F, 0x00, 0x00 } }, /* 900 900 0.0 */ +}; + static const struct intel_ddi_buf_trans adlp_combo_phy_trans_dp_hbr2_hbr3 = { .entries = _adlp_combo_phy_trans_dp_hbr2_hbr3, .num_entries = ARRAY_SIZE(_adlp_combo_phy_trans_dp_hbr2_hbr3), }; static const struct intel_ddi_buf_trans adlp_combo_phy_trans_edp_hbr3 = { - .entries = _icl_combo_phy_trans_dp_hbr2_edp_hbr3, - .num_entries = ARRAY_SIZE(_icl_combo_phy_trans_dp_hbr2_edp_hbr3), + .entries = _adlp_combo_phy_trans_dp_hbr2_edp_hbr3, + .num_entries = ARRAY_SIZE(_adlp_combo_phy_trans_dp_hbr2_edp_hbr3), }; static const struct intel_ddi_buf_trans adlp_combo_phy_trans_edp_up_to_hbr2 = { - .entries = _icl_combo_phy_trans_edp_hbr2, - .num_entries = ARRAY_SIZE(_icl_combo_phy_trans_edp_hbr2), + .entries = _adlp_combo_phy_trans_edp_hbr2, + .num_entries = ARRAY_SIZE(_adlp_combo_phy_trans_edp_hbr2), }; static const union intel_ddi_buf_trans_entry _adlp_dkl_phy_trans_dp_hbr[] = { diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 7dfeb458aa65..29044cf58b87 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -32,6 +32,7 @@ #include <linux/module.h> #include <linux/dma-resv.h> #include <linux/slab.h> +#include <linux/string_helpers.h> #include <linux/vga_switcheroo.h> #include <drm/drm_atomic.h> @@ -76,6 +77,7 @@ #include "g4x_hdmi.h" #include "hsw_ips.h" #include "i915_drv.h" +#include "i915_utils.h" #include "icl_dsi.h" #include "intel_acpi.h" #include "intel_atomic.h" @@ -368,6 +370,11 @@ bool intel_crtc_is_bigjoiner_master(const struct intel_crtc_state *crtc_state) crtc->pipe == bigjoiner_master_pipe(crtc_state); } +static int intel_bigjoiner_num_pipes(const struct intel_crtc_state *crtc_state) +{ + return hweight8(crtc_state->bigjoiner_pipes); +} + struct intel_crtc *intel_master_crtc(const struct intel_crtc_state *crtc_state) { struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); @@ -400,7 +407,7 @@ static void wait_for_pipe_scanline_moving(struct intel_crtc *crtc, bool state) if (wait_for(pipe_scanline_is_moving(dev_priv, pipe) == state, 100)) drm_err(&dev_priv->drm, "pipe %c scanline %s wait timed out\n", - pipe_name(pipe), onoff(state)); + pipe_name(pipe), str_on_off(state)); } static void intel_wait_for_pipe_scanline_stopped(struct intel_crtc *crtc) @@ -456,7 +463,7 @@ void assert_transcoder(struct drm_i915_private *dev_priv, I915_STATE_WARN(cur_state != state, "transcoder %s assertion failure (expected %s, current %s)\n", transcoder_name(cpu_transcoder), - onoff(state), onoff(cur_state)); + str_on_off(state), str_on_off(cur_state)); } static void assert_plane(struct intel_plane *plane, bool state) @@ -468,7 +475,8 @@ static void assert_plane(struct intel_plane *plane, bool state) I915_STATE_WARN(cur_state != state, "%s assertion failure (expected %s, current %s)\n", - plane->base.name, onoff(state), onoff(cur_state)); + plane->base.name, str_on_off(state), + str_on_off(cur_state)); } #define assert_plane_enabled(p) assert_plane(p, true) @@ -517,16 +525,6 @@ void vlv_wait_port_ready(struct drm_i915_private *dev_priv, expected_mask); } -enum pipe intel_crtc_pch_transcoder(struct intel_crtc *crtc) -{ - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - - if (HAS_PCH_LPT(dev_priv)) - return PIPE_A; - else - return crtc->pipe; -} - void intel_enable_transcoder(const struct intel_crtc_state *new_crtc_state) { struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc); @@ -783,6 +781,9 @@ void intel_plane_disable_noatomic(struct intel_crtc *crtc, intel_set_plane_visible(crtc_state, plane_state, false); fixup_plane_bitmasks(crtc_state); crtc_state->data_rate[plane->id] = 0; + crtc_state->data_rate_y[plane->id] = 0; + crtc_state->rel_data_rate[plane->id] = 0; + crtc_state->rel_data_rate_y[plane->id] = 0; crtc_state->min_cdclk[plane->id] = 0; if ((crtc_state->active_planes & ~BIT(PLANE_CURSOR)) == 0 && @@ -1117,13 +1118,13 @@ static void ilk_pfit_enable(const struct intel_crtc_state *crtc_state) * e.g. x201. */ if (IS_IVYBRIDGE(dev_priv) || IS_HASWELL(dev_priv)) - intel_de_write(dev_priv, PF_CTL(pipe), PF_ENABLE | - PF_FILTER_MED_3x3 | PF_PIPE_SEL_IVB(pipe)); + intel_de_write_fw(dev_priv, PF_CTL(pipe), PF_ENABLE | + PF_FILTER_MED_3x3 | PF_PIPE_SEL_IVB(pipe)); else - intel_de_write(dev_priv, PF_CTL(pipe), PF_ENABLE | - PF_FILTER_MED_3x3); - intel_de_write(dev_priv, PF_WIN_POS(pipe), x << 16 | y); - intel_de_write(dev_priv, PF_WIN_SZ(pipe), width << 16 | height); + intel_de_write_fw(dev_priv, PF_CTL(pipe), PF_ENABLE | + PF_FILTER_MED_3x3); + intel_de_write_fw(dev_priv, PF_WIN_POS(pipe), x << 16 | y); + intel_de_write_fw(dev_priv, PF_WIN_SZ(pipe), width << 16 | height); } static void intel_crtc_dpms_overlay_disable(struct intel_crtc *crtc) @@ -1197,7 +1198,7 @@ static bool needs_async_flip_vtd_wa(const struct intel_crtc_state *crtc_state) { struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); - return crtc_state->uapi.async_flip && intel_vtd_active(i915) && + return crtc_state->uapi.async_flip && i915_vtd_active(i915) && (DISPLAY_VER(i915) == 9 || IS_BROADWELL(i915) || IS_HASWELL(i915)); } @@ -1232,7 +1233,6 @@ static void intel_post_plane_update(struct intel_atomic_state *state, hsw_ips_post_update(state, crtc); intel_fbc_post_update(state, crtc); - intel_drrs_page_flip(state, crtc); if (needs_async_flip_vtd_wa(old_crtc_state) && !needs_async_flip_vtd_wa(new_crtc_state)) @@ -1250,6 +1250,7 @@ static void intel_post_plane_update(struct intel_atomic_state *state, !needs_cursorclk_wa(new_crtc_state)) icl_wa_cursorclkgating(dev_priv, pipe, false); + intel_drrs_activate(new_crtc_state); } static void intel_crtc_enable_flip_done(struct intel_atomic_state *state, @@ -1327,6 +1328,8 @@ static void intel_pre_plane_update(struct intel_atomic_state *state, intel_atomic_get_new_crtc_state(state, crtc); enum pipe pipe = crtc->pipe; + intel_drrs_deactivate(old_crtc_state); + intel_psr_pre_plane_update(state, crtc); if (hsw_ips_pre_update(state, crtc)) @@ -1777,7 +1780,8 @@ static void ilk_crtc_enable(struct intel_atomic_state *state, * clocks enabled */ intel_color_load_luts(new_crtc_state); - intel_color_commit(new_crtc_state); + intel_color_commit_noarm(new_crtc_state); + intel_color_commit_arm(new_crtc_state); /* update DSPCNTR to configure gamma for pipe bottom color */ intel_disable_primary_plane(new_crtc_state); @@ -1822,29 +1826,6 @@ static void glk_pipe_scaler_clock_gating_wa(struct drm_i915_private *dev_priv, intel_de_write(dev_priv, CLKGATE_DIS_PSL(pipe), val); } -static void icl_pipe_mbus_enable(struct intel_crtc *crtc, bool joined_mbus) -{ - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - enum pipe pipe = crtc->pipe; - u32 val; - - /* Wa_22010947358:adl-p */ - if (IS_ALDERLAKE_P(dev_priv)) - val = joined_mbus ? MBUS_DBOX_A_CREDIT(6) : MBUS_DBOX_A_CREDIT(4); - else - val = MBUS_DBOX_A_CREDIT(2); - - if (DISPLAY_VER(dev_priv) >= 12) { - val |= MBUS_DBOX_BW_CREDIT(2); - val |= MBUS_DBOX_B_CREDIT(12); - } else { - val |= MBUS_DBOX_BW_CREDIT(1); - val |= MBUS_DBOX_B_CREDIT(8); - } - - intel_de_write(dev_priv, PIPE_MBUS_DBOX_CTL(pipe), val); -} - static void hsw_set_linetime_wm(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); @@ -1864,7 +1845,7 @@ static void hsw_set_frame_start_delay(const struct intel_crtc_state *crtc_state) val = intel_de_read(dev_priv, reg); val &= ~HSW_FRAME_START_DELAY_MASK; - val |= HSW_FRAME_START_DELAY(dev_priv->framestart_delay - 1); + val |= HSW_FRAME_START_DELAY(crtc_state->framestart_delay - 1); intel_de_write(dev_priv, reg, val); } @@ -1926,7 +1907,7 @@ static void hsw_crtc_enable(struct intel_atomic_state *state, if (drm_WARN_ON(&dev_priv->drm, crtc->active)) return; - if (!new_crtc_state->bigjoiner) { + if (!new_crtc_state->bigjoiner_pipes) { intel_encoders_pre_pll_enable(state, crtc); if (new_crtc_state->shared_dpll) @@ -1968,7 +1949,8 @@ static void hsw_crtc_enable(struct intel_atomic_state *state, * clocks enabled */ intel_color_load_luts(new_crtc_state); - intel_color_commit(new_crtc_state); + intel_color_commit_noarm(new_crtc_state); + intel_color_commit_arm(new_crtc_state); /* update DSPCNTR to configure gamma/csc for pipe bottom color */ if (DISPLAY_VER(dev_priv) < 9) intel_disable_primary_plane(new_crtc_state); @@ -1980,13 +1962,6 @@ static void hsw_crtc_enable(struct intel_atomic_state *state, intel_initial_watermarks(state, crtc); - if (DISPLAY_VER(dev_priv) >= 11) { - const struct intel_dbuf_state *dbuf_state = - intel_atomic_get_new_dbuf_state(state); - - icl_pipe_mbus_enable(crtc, dbuf_state->joined_mbus); - } - if (intel_crtc_is_bigjoiner_slave(new_crtc_state)) intel_crtc_vblank_on(new_crtc_state); @@ -2021,9 +1996,9 @@ void ilk_pfit_disable(const struct intel_crtc_state *old_crtc_state) if (!old_crtc_state->pch_pfit.enabled) return; - intel_de_write(dev_priv, PF_CTL(pipe), 0); - intel_de_write(dev_priv, PF_WIN_POS(pipe), 0); - intel_de_write(dev_priv, PF_WIN_SZ(pipe), 0); + intel_de_write_fw(dev_priv, PF_CTL(pipe), 0); + intel_de_write_fw(dev_priv, PF_WIN_POS(pipe), 0); + intel_de_write_fw(dev_priv, PF_WIN_SZ(pipe), 0); } static void ilk_crtc_disable(struct intel_atomic_state *state, @@ -2388,7 +2363,8 @@ static void valleyview_crtc_enable(struct intel_atomic_state *state, i9xx_pfit_enable(new_crtc_state); intel_color_load_luts(new_crtc_state); - intel_color_commit(new_crtc_state); + intel_color_commit_noarm(new_crtc_state); + intel_color_commit_arm(new_crtc_state); /* update DSPCNTR to configure gamma for pipe bottom color */ intel_disable_primary_plane(new_crtc_state); @@ -2427,7 +2403,8 @@ static void i9xx_crtc_enable(struct intel_atomic_state *state, i9xx_pfit_enable(new_crtc_state); intel_color_load_luts(new_crtc_state); - intel_color_commit(new_crtc_state); + intel_color_commit_noarm(new_crtc_state); + intel_color_commit_arm(new_crtc_state); /* update DSPCNTR to configure gamma for pipe bottom color */ intel_disable_primary_plane(new_crtc_state); @@ -2683,8 +2660,8 @@ static u32 ilk_pipe_pixel_rate(const struct intel_crtc_state *crtc_state) return pixel_rate; drm_rect_init(&src, 0, 0, - crtc_state->pipe_src_w << 16, - crtc_state->pipe_src_h << 16); + drm_rect_width(&crtc_state->pipe_src) << 16, + drm_rect_height(&crtc_state->pipe_src) << 16); return intel_adjusted_rate(&src, &crtc_state->pch_pfit.dst, pixel_rate); @@ -2724,58 +2701,81 @@ static void intel_crtc_compute_pixel_rate(struct intel_crtc_state *crtc_state) ilk_pipe_pixel_rate(crtc_state); } +static void intel_bigjoiner_adjust_timings(const struct intel_crtc_state *crtc_state, + struct drm_display_mode *mode) +{ + int num_pipes = intel_bigjoiner_num_pipes(crtc_state); + + if (num_pipes < 2) + return; + + mode->crtc_clock /= num_pipes; + mode->crtc_hdisplay /= num_pipes; + mode->crtc_hblank_start /= num_pipes; + mode->crtc_hblank_end /= num_pipes; + mode->crtc_hsync_start /= num_pipes; + mode->crtc_hsync_end /= num_pipes; + mode->crtc_htotal /= num_pipes; +} + +static void intel_splitter_adjust_timings(const struct intel_crtc_state *crtc_state, + struct drm_display_mode *mode) +{ + int overlap = crtc_state->splitter.pixel_overlap; + int n = crtc_state->splitter.link_count; + + if (!crtc_state->splitter.enable) + return; + + /* + * eDP MSO uses segment timings from EDID for transcoder + * timings, but full mode for everything else. + * + * h_full = (h_segment - pixel_overlap) * link_count + */ + mode->crtc_hdisplay = (mode->crtc_hdisplay - overlap) * n; + mode->crtc_hblank_start = (mode->crtc_hblank_start - overlap) * n; + mode->crtc_hblank_end = (mode->crtc_hblank_end - overlap) * n; + mode->crtc_hsync_start = (mode->crtc_hsync_start - overlap) * n; + mode->crtc_hsync_end = (mode->crtc_hsync_end - overlap) * n; + mode->crtc_htotal = (mode->crtc_htotal - overlap) * n; + mode->crtc_clock *= n; +} + static void intel_crtc_readout_derived_state(struct intel_crtc_state *crtc_state) { struct drm_display_mode *mode = &crtc_state->hw.mode; struct drm_display_mode *pipe_mode = &crtc_state->hw.pipe_mode; struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; + /* + * Start with the adjusted_mode crtc timings, which + * have been filled with the transcoder timings. + */ drm_mode_copy(pipe_mode, adjusted_mode); - if (crtc_state->bigjoiner) { - /* - * transcoder is programmed to the full mode, - * but pipe timings are half of the transcoder mode - */ - pipe_mode->crtc_hdisplay /= 2; - pipe_mode->crtc_hblank_start /= 2; - pipe_mode->crtc_hblank_end /= 2; - pipe_mode->crtc_hsync_start /= 2; - pipe_mode->crtc_hsync_end /= 2; - pipe_mode->crtc_htotal /= 2; - pipe_mode->crtc_clock /= 2; - } + /* Expand MSO per-segment transcoder timings to full */ + intel_splitter_adjust_timings(crtc_state, pipe_mode); - if (crtc_state->splitter.enable) { - int n = crtc_state->splitter.link_count; - int overlap = crtc_state->splitter.pixel_overlap; + /* + * We want the full numbers in adjusted_mode normal timings, + * adjusted_mode crtc timings are left with the raw transcoder + * timings. + */ + intel_mode_from_crtc_timings(adjusted_mode, pipe_mode); - /* - * eDP MSO uses segment timings from EDID for transcoder - * timings, but full mode for everything else. - * - * h_full = (h_segment - pixel_overlap) * link_count - */ - pipe_mode->crtc_hdisplay = (pipe_mode->crtc_hdisplay - overlap) * n; - pipe_mode->crtc_hblank_start = (pipe_mode->crtc_hblank_start - overlap) * n; - pipe_mode->crtc_hblank_end = (pipe_mode->crtc_hblank_end - overlap) * n; - pipe_mode->crtc_hsync_start = (pipe_mode->crtc_hsync_start - overlap) * n; - pipe_mode->crtc_hsync_end = (pipe_mode->crtc_hsync_end - overlap) * n; - pipe_mode->crtc_htotal = (pipe_mode->crtc_htotal - overlap) * n; - pipe_mode->crtc_clock *= n; - - intel_mode_from_crtc_timings(pipe_mode, pipe_mode); - intel_mode_from_crtc_timings(adjusted_mode, pipe_mode); - } else { - intel_mode_from_crtc_timings(pipe_mode, pipe_mode); - intel_mode_from_crtc_timings(adjusted_mode, adjusted_mode); - } + /* Populate the "user" mode with full numbers */ + drm_mode_copy(mode, pipe_mode); + intel_mode_from_crtc_timings(mode, mode); + mode->hdisplay = drm_rect_width(&crtc_state->pipe_src) * + (intel_bigjoiner_num_pipes(crtc_state) ?: 1); + mode->vdisplay = drm_rect_height(&crtc_state->pipe_src); - intel_crtc_compute_pixel_rate(crtc_state); + /* Derive per-pipe timings in case bigjoiner is used */ + intel_bigjoiner_adjust_timings(crtc_state, pipe_mode); + intel_mode_from_crtc_timings(pipe_mode, pipe_mode); - drm_mode_copy(mode, adjusted_mode); - mode->hdisplay = crtc_state->pipe_src_w << crtc_state->bigjoiner; - mode->vdisplay = crtc_state->pipe_src_h; + intel_crtc_compute_pixel_rate(crtc_state); } static void intel_encoder_get_config(struct intel_encoder *encoder, @@ -2786,44 +2786,77 @@ static void intel_encoder_get_config(struct intel_encoder *encoder, intel_crtc_readout_derived_state(crtc_state); } -static int intel_crtc_compute_config(struct intel_crtc *crtc, - struct intel_crtc_state *pipe_config) +static void intel_bigjoiner_compute_pipe_src(struct intel_crtc_state *crtc_state) { - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - struct drm_display_mode *pipe_mode = &pipe_config->hw.pipe_mode; - int clock_limit = dev_priv->max_dotclk_freq; + int num_pipes = intel_bigjoiner_num_pipes(crtc_state); + int width, height; - drm_mode_copy(pipe_mode, &pipe_config->hw.adjusted_mode); + if (num_pipes < 2) + return; - /* Adjust pipe_mode for bigjoiner, with half the horizontal mode */ - if (pipe_config->bigjoiner) { - pipe_mode->crtc_clock /= 2; - pipe_mode->crtc_hdisplay /= 2; - pipe_mode->crtc_hblank_start /= 2; - pipe_mode->crtc_hblank_end /= 2; - pipe_mode->crtc_hsync_start /= 2; - pipe_mode->crtc_hsync_end /= 2; - pipe_mode->crtc_htotal /= 2; - pipe_config->pipe_src_w /= 2; - } + width = drm_rect_width(&crtc_state->pipe_src); + height = drm_rect_height(&crtc_state->pipe_src); - if (pipe_config->splitter.enable) { - int n = pipe_config->splitter.link_count; - int overlap = pipe_config->splitter.pixel_overlap; + drm_rect_init(&crtc_state->pipe_src, 0, 0, + width / num_pipes, height); +} - pipe_mode->crtc_hdisplay = (pipe_mode->crtc_hdisplay - overlap) * n; - pipe_mode->crtc_hblank_start = (pipe_mode->crtc_hblank_start - overlap) * n; - pipe_mode->crtc_hblank_end = (pipe_mode->crtc_hblank_end - overlap) * n; - pipe_mode->crtc_hsync_start = (pipe_mode->crtc_hsync_start - overlap) * n; - pipe_mode->crtc_hsync_end = (pipe_mode->crtc_hsync_end - overlap) * n; - pipe_mode->crtc_htotal = (pipe_mode->crtc_htotal - overlap) * n; - pipe_mode->crtc_clock *= n; +static int intel_crtc_compute_pipe_src(struct intel_crtc_state *crtc_state) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + + intel_bigjoiner_compute_pipe_src(crtc_state); + + /* + * Pipe horizontal size must be even in: + * - DVO ganged mode + * - LVDS dual channel mode + * - Double wide pipe + */ + if (drm_rect_width(&crtc_state->pipe_src) & 1) { + if (crtc_state->double_wide) { + drm_dbg_kms(&i915->drm, + "[CRTC:%d:%s] Odd pipe source width not supported with double wide pipe\n", + crtc->base.base.id, crtc->base.name); + return -EINVAL; + } + + if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS) && + intel_is_dual_link_lvds(i915)) { + drm_dbg_kms(&i915->drm, + "[CRTC:%d:%s] Odd pipe source width not supported with dual link LVDS\n", + crtc->base.base.id, crtc->base.name); + return -EINVAL; + } } + return 0; +} + +static int intel_crtc_compute_pipe_mode(struct intel_crtc_state *crtc_state) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; + struct drm_display_mode *pipe_mode = &crtc_state->hw.pipe_mode; + int clock_limit = i915->max_dotclk_freq; + + /* + * Start with the adjusted_mode crtc timings, which + * have been filled with the transcoder timings. + */ + drm_mode_copy(pipe_mode, adjusted_mode); + + /* Expand MSO per-segment transcoder timings to full */ + intel_splitter_adjust_timings(crtc_state, pipe_mode); + + /* Derive per-pipe timings in case bigjoiner is used */ + intel_bigjoiner_adjust_timings(crtc_state, pipe_mode); intel_mode_from_crtc_timings(pipe_mode, pipe_mode); - if (DISPLAY_VER(dev_priv) < 4) { - clock_limit = dev_priv->max_cdclk_freq * 9 / 10; + if (DISPLAY_VER(i915) < 4) { + clock_limit = i915->max_cdclk_freq * 9 / 10; /* * Enable double wide mode when the dot clock @@ -2831,44 +2864,40 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc, */ if (intel_crtc_supports_double_wide(crtc) && pipe_mode->crtc_clock > clock_limit) { - clock_limit = dev_priv->max_dotclk_freq; - pipe_config->double_wide = true; + clock_limit = i915->max_dotclk_freq; + crtc_state->double_wide = true; } } if (pipe_mode->crtc_clock > clock_limit) { - drm_dbg_kms(&dev_priv->drm, - "requested pixel clock (%d kHz) too high (max: %d kHz, double wide: %s)\n", + drm_dbg_kms(&i915->drm, + "[CRTC:%d:%s] requested pixel clock (%d kHz) too high (max: %d kHz, double wide: %s)\n", + crtc->base.base.id, crtc->base.name, pipe_mode->crtc_clock, clock_limit, - yesno(pipe_config->double_wide)); + str_yes_no(crtc_state->double_wide)); return -EINVAL; } - /* - * Pipe horizontal size must be even in: - * - DVO ganged mode - * - LVDS dual channel mode - * - Double wide pipe - */ - if (pipe_config->pipe_src_w & 1) { - if (pipe_config->double_wide) { - drm_dbg_kms(&dev_priv->drm, - "Odd pipe source width not supported with double wide pipe\n"); - return -EINVAL; - } + return 0; +} - if (intel_crtc_has_type(pipe_config, INTEL_OUTPUT_LVDS) && - intel_is_dual_link_lvds(dev_priv)) { - drm_dbg_kms(&dev_priv->drm, - "Odd pipe source width not supported with dual link LVDS\n"); - return -EINVAL; - } - } +static int intel_crtc_compute_config(struct intel_crtc *crtc, + struct intel_crtc_state *crtc_state) +{ + int ret; - intel_crtc_compute_pixel_rate(pipe_config); + ret = intel_crtc_compute_pipe_src(crtc_state); + if (ret) + return ret; - if (pipe_config->has_pch_encoder) - return ilk_fdi_compute_config(crtc, pipe_config); + ret = intel_crtc_compute_pipe_mode(crtc_state); + if (ret) + return ret; + + intel_crtc_compute_pixel_rate(crtc_state); + + if (crtc_state->has_pch_encoder) + return ilk_fdi_compute_config(crtc, crtc_state); return 0; } @@ -2941,8 +2970,8 @@ static void intel_panel_sanitize_ssc(struct drm_i915_private *dev_priv) if (dev_priv->vbt.lvds_use_ssc != bios_lvds_use_ssc) { drm_dbg_kms(&dev_priv->drm, "SSC %s by BIOS, overriding VBT which says %s\n", - enableddisabled(bios_lvds_use_ssc), - enableddisabled(dev_priv->vbt.lvds_use_ssc)); + str_enabled_disabled(bios_lvds_use_ssc), + str_enabled_disabled(dev_priv->vbt.lvds_use_ssc)); dev_priv->vbt.lvds_use_ssc = bios_lvds_use_ssc; } } @@ -3072,14 +3101,15 @@ static void intel_set_pipe_src_size(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + int width = drm_rect_width(&crtc_state->pipe_src); + int height = drm_rect_height(&crtc_state->pipe_src); enum pipe pipe = crtc->pipe; /* pipesrc controls the size that is scaled from, which should * always be the user's requested size. */ intel_de_write(dev_priv, PIPESRC(pipe), - PIPESRC_WIDTH(crtc_state->pipe_src_w - 1) | - PIPESRC_HEIGHT(crtc_state->pipe_src_h - 1)); + PIPESRC_WIDTH(width - 1) | PIPESRC_HEIGHT(height - 1)); } static bool intel_pipe_is_interlaced(const struct intel_crtc_state *crtc_state) @@ -3142,6 +3172,23 @@ static void intel_get_transcoder_timings(struct intel_crtc *crtc, } } +static void intel_bigjoiner_adjust_pipe_src(struct intel_crtc_state *crtc_state) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + int num_pipes = intel_bigjoiner_num_pipes(crtc_state); + enum pipe master_pipe, pipe = crtc->pipe; + int width; + + if (num_pipes < 2) + return; + + master_pipe = bigjoiner_master_pipe(crtc_state); + width = drm_rect_width(&crtc_state->pipe_src); + + drm_rect_translate_to(&crtc_state->pipe_src, + (pipe - master_pipe) * width, 0); +} + static void intel_get_pipe_src_size(struct intel_crtc *crtc, struct intel_crtc_state *pipe_config) { @@ -3150,8 +3197,12 @@ static void intel_get_pipe_src_size(struct intel_crtc *crtc, u32 tmp; tmp = intel_de_read(dev_priv, PIPESRC(crtc->pipe)); - pipe_config->pipe_src_w = REG_FIELD_GET(PIPESRC_WIDTH_MASK, tmp) + 1; - pipe_config->pipe_src_h = REG_FIELD_GET(PIPESRC_HEIGHT_MASK, tmp) + 1; + + drm_rect_init(&pipe_config->pipe_src, 0, 0, + REG_FIELD_GET(PIPESRC_WIDTH_MASK, tmp) + 1, + REG_FIELD_GET(PIPESRC_HEIGHT_MASK, tmp) + 1); + + intel_bigjoiner_adjust_pipe_src(pipe_config); } static void i9xx_set_pipeconf(const struct intel_crtc_state *crtc_state) @@ -3207,7 +3258,7 @@ static void i9xx_set_pipeconf(const struct intel_crtc_state *crtc_state) pipeconf |= PIPECONF_GAMMA_MODE(crtc_state->gamma_mode); - pipeconf |= PIPECONF_FRAME_START_DELAY(dev_priv->framestart_delay - 1); + pipeconf |= PIPECONF_FRAME_START_DELAY(crtc_state->framestart_delay - 1); intel_de_write(dev_priv, PIPECONF(crtc->pipe), pipeconf); intel_de_posting_read(dev_priv, PIPECONF(crtc->pipe)); @@ -3397,6 +3448,8 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc, pipe_config->gamma_mode = REG_FIELD_GET(PIPECONF_GAMMA_MODE_MASK_I9XX, tmp); + pipe_config->framestart_delay = REG_FIELD_GET(PIPECONF_FRAME_START_DELAY_MASK, tmp) + 1; + if (IS_CHERRYVIEW(dev_priv)) pipe_config->cgm_mode = intel_de_read(dev_priv, CGM_PIPE_MODE(crtc->pipe)); @@ -3522,7 +3575,8 @@ static void ilk_set_pipeconf(const struct intel_crtc_state *crtc_state) val |= PIPECONF_GAMMA_MODE(crtc_state->gamma_mode); - val |= PIPECONF_FRAME_START_DELAY(dev_priv->framestart_delay - 1); + val |= PIPECONF_FRAME_START_DELAY(crtc_state->framestart_delay - 1); + val |= PIPECONF_MSA_TIMING_DELAY(crtc_state->msa_timing_delay); intel_de_write(dev_priv, PIPECONF(pipe), val); intel_de_posting_read(dev_priv, PIPECONF(pipe)); @@ -3554,12 +3608,8 @@ static void hsw_set_transconf(const struct intel_crtc_state *crtc_state) static void bdw_set_pipemisc(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - const struct intel_crtc_scaler_state *scaler_state = - &crtc_state->scaler_state; - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); u32 val = 0; - int i; switch (crtc_state->pipe_bpp) { case 18: @@ -3598,23 +3648,6 @@ static void bdw_set_pipemisc(const struct intel_crtc_state *crtc_state) if (DISPLAY_VER(dev_priv) >= 12) val |= PIPEMISC_PIXEL_ROUNDING_TRUNC; - if (IS_ALDERLAKE_P(dev_priv)) { - bool scaler_in_use = false; - - for (i = 0; i < crtc->num_scalers; i++) { - if (!scaler_state->scalers[i].in_use) - continue; - - scaler_in_use = true; - break; - } - - intel_de_rmw(dev_priv, PIPE_MISC2(crtc->pipe), - PIPE_MISC2_BUBBLE_COUNTER_MASK, - scaler_in_use ? PIPE_MISC2_BUBBLE_COUNTER_SCALER_EN : - PIPE_MISC2_BUBBLE_COUNTER_SCALER_DIS); - } - intel_de_write(dev_priv, PIPEMISC(crtc->pipe), val); } @@ -3830,6 +3863,10 @@ static bool ilk_get_pipe_config(struct intel_crtc *crtc, pipe_config->gamma_mode = REG_FIELD_GET(PIPECONF_GAMMA_MODE_MASK_ILK, tmp); + pipe_config->framestart_delay = REG_FIELD_GET(PIPECONF_FRAME_START_DELAY_MASK, tmp) + 1; + + pipe_config->msa_timing_delay = REG_FIELD_GET(PIPECONF_MSA_TIMING_DELAY_MASK, tmp); + pipe_config->csc_mode = intel_de_read(dev_priv, PIPE_CSC_MODE(crtc->pipe)); @@ -4164,7 +4201,6 @@ static void intel_bigjoiner_get_config(struct intel_crtc_state *crtc_state) if (((master_pipes | slave_pipes) & BIT(pipe)) == 0) return; - crtc_state->bigjoiner = true; crtc_state->bigjoiner_pipes = BIT(get_bigjoiner_master_pipe(pipe, master_pipes, slave_pipes)) | get_bigjoiner_slave_pipes(pipe, master_pipes, slave_pipes); @@ -4265,6 +4301,15 @@ static bool hsw_get_pipe_config(struct intel_crtc *crtc, pipe_config->pixel_multiplier = 1; } + if (!transcoder_is_dsi(pipe_config->cpu_transcoder)) { + tmp = intel_de_read(dev_priv, CHICKEN_TRANS(pipe_config->cpu_transcoder)); + + pipe_config->framestart_delay = REG_FIELD_GET(HSW_FRAME_START_DELAY_MASK, tmp) + 1; + } else { + /* no idea if this is correct */ + pipe_config->framestart_delay = 1; + } + out: intel_display_power_put_all_in_set(dev_priv, &power_domain_set); @@ -4746,6 +4791,8 @@ static int icl_check_nv12_planes(struct intel_crtc_state *crtc_state) crtc_state->enabled_planes &= ~BIT(plane->id); crtc_state->active_planes &= ~BIT(plane->id); crtc_state->update_planes |= BIT(plane->id); + crtc_state->data_rate[plane->id] = 0; + crtc_state->rel_data_rate[plane->id] = 0; } plane_state->planar_slave = false; @@ -4790,6 +4837,10 @@ static int icl_check_nv12_planes(struct intel_crtc_state *crtc_state) crtc_state->enabled_planes |= BIT(linked->id); crtc_state->active_planes |= BIT(linked->id); crtc_state->update_planes |= BIT(linked->id); + crtc_state->data_rate[linked->id] = + crtc_state->data_rate_y[plane->id]; + crtc_state->rel_data_rate[linked->id] = + crtc_state->rel_data_rate_y[plane->id]; drm_dbg_kms(&dev_priv->drm, "Using %s as Y plane for %s\n", linked->base.name, plane->base.name); @@ -5222,7 +5273,7 @@ static void intel_dump_plane_state(const struct intel_plane_state *plane_state) drm_dbg_kms(&i915->drm, "[PLANE:%d:%s] fb: [NOFB], visible: %s\n", plane->base.base.id, plane->base.name, - yesno(plane_state->uapi.visible)); + str_yes_no(plane_state->uapi.visible)); return; } @@ -5230,7 +5281,7 @@ static void intel_dump_plane_state(const struct intel_plane_state *plane_state) "[PLANE:%d:%s] fb: [FB:%d] %ux%u format = %p4cc modifier = 0x%llx, visible: %s\n", plane->base.base.id, plane->base.name, fb->base.id, fb->width, fb->height, &fb->format->format, - fb->modifier, yesno(plane_state->uapi.visible)); + fb->modifier, str_yes_no(plane_state->uapi.visible)); drm_dbg_kms(&i915->drm, "\trotation: 0x%x, scaler: %d\n", plane_state->hw.rotation, plane_state->scaler_id); if (plane_state->uapi.visible) @@ -5253,7 +5304,7 @@ static void intel_dump_pipe_config(const struct intel_crtc_state *pipe_config, drm_dbg_kms(&dev_priv->drm, "[CRTC:%d:%s] enable: %s %s\n", crtc->base.base.id, crtc->base.name, - yesno(pipe_config->hw.enable), context); + str_yes_no(pipe_config->hw.enable), context); if (!pipe_config->hw.enable) goto dump_planes; @@ -5261,7 +5312,7 @@ static void intel_dump_pipe_config(const struct intel_crtc_state *pipe_config, snprintf_output_types(buf, sizeof(buf), pipe_config->output_types); drm_dbg_kms(&dev_priv->drm, "active: %s, output_types: %s (0x%x), output format: %s\n", - yesno(pipe_config->hw.active), + str_yes_no(pipe_config->hw.active), buf, pipe_config->output_types, output_formats(pipe_config->output_format)); @@ -5284,7 +5335,7 @@ static void intel_dump_pipe_config(const struct intel_crtc_state *pipe_config, pipe_config->bigjoiner_pipes); drm_dbg_kms(&dev_priv->drm, "splitter: %s, link count %d, overlap %d\n", - enableddisabled(pipe_config->splitter.enable), + str_enabled_disabled(pipe_config->splitter.enable), pipe_config->splitter.link_count, pipe_config->splitter.pixel_overlap); @@ -5302,6 +5353,9 @@ static void intel_dump_pipe_config(const struct intel_crtc_state *pipe_config, &pipe_config->dp_m2_n2); } + drm_dbg_kms(&dev_priv->drm, "framestart delay: %d, MSA timing delay: %d\n", + pipe_config->framestart_delay, pipe_config->msa_timing_delay); + drm_dbg_kms(&dev_priv->drm, "audio: %i, infoframes: %i, infoframes enabled: 0x%x\n", pipe_config->has_audio, pipe_config->has_infoframe, @@ -5331,25 +5385,24 @@ static void intel_dump_pipe_config(const struct intel_crtc_state *pipe_config, intel_dump_dp_vsc_sdp(dev_priv, &pipe_config->infoframes.vsc); drm_dbg_kms(&dev_priv->drm, "vrr: %s, vmin: %d, vmax: %d, pipeline full: %d, guardband: %d flipline: %d, vmin vblank: %d, vmax vblank: %d\n", - yesno(pipe_config->vrr.enable), + str_yes_no(pipe_config->vrr.enable), pipe_config->vrr.vmin, pipe_config->vrr.vmax, pipe_config->vrr.pipeline_full, pipe_config->vrr.guardband, pipe_config->vrr.flipline, intel_vrr_vmin_vblank_start(pipe_config), intel_vrr_vmax_vblank_start(pipe_config)); - drm_dbg_kms(&dev_priv->drm, "requested mode:\n"); - drm_mode_debug_printmodeline(&pipe_config->hw.mode); - drm_dbg_kms(&dev_priv->drm, "adjusted mode:\n"); - drm_mode_debug_printmodeline(&pipe_config->hw.adjusted_mode); + drm_dbg_kms(&dev_priv->drm, "requested mode: " DRM_MODE_FMT "\n", + DRM_MODE_ARG(&pipe_config->hw.mode)); + drm_dbg_kms(&dev_priv->drm, "adjusted mode: " DRM_MODE_FMT "\n", + DRM_MODE_ARG(&pipe_config->hw.adjusted_mode)); intel_dump_crtc_timings(dev_priv, &pipe_config->hw.adjusted_mode); - drm_dbg_kms(&dev_priv->drm, "pipe mode:\n"); - drm_mode_debug_printmodeline(&pipe_config->hw.pipe_mode); + drm_dbg_kms(&dev_priv->drm, "pipe mode: " DRM_MODE_FMT "\n", + DRM_MODE_ARG(&pipe_config->hw.pipe_mode)); intel_dump_crtc_timings(dev_priv, &pipe_config->hw.pipe_mode); drm_dbg_kms(&dev_priv->drm, - "port clock: %d, pipe src size: %dx%d, pixel rate %d\n", - pipe_config->port_clock, - pipe_config->pipe_src_w, pipe_config->pipe_src_h, + "port clock: %d, pipe src: " DRM_RECT_FMT ", pixel rate %d\n", + pipe_config->port_clock, DRM_RECT_ARG(&pipe_config->pipe_src), pipe_config->pixel_rate); drm_dbg_kms(&dev_priv->drm, "linetime: %d, ips linetime: %d\n", @@ -5372,11 +5425,12 @@ static void intel_dump_pipe_config(const struct intel_crtc_state *pipe_config, drm_dbg_kms(&dev_priv->drm, "pch pfit: " DRM_RECT_FMT ", %s, force thru: %s\n", DRM_RECT_ARG(&pipe_config->pch_pfit.dst), - enableddisabled(pipe_config->pch_pfit.enabled), - yesno(pipe_config->pch_pfit.force_thru)); + str_enabled_disabled(pipe_config->pch_pfit.enabled), + str_yes_no(pipe_config->pch_pfit.force_thru)); - drm_dbg_kms(&dev_priv->drm, "ips: %i, double wide: %i\n", - pipe_config->ips_enabled, pipe_config->double_wide); + drm_dbg_kms(&dev_priv->drm, "ips: %i, double wide: %i, drrs: %i\n", + pipe_config->ips_enabled, pipe_config->double_wide, + pipe_config->has_drrs); intel_dpll_dump_hw_state(dev_priv, &pipe_config->dpll_hw_state); @@ -5504,8 +5558,10 @@ intel_crtc_copy_uapi_to_hw_state_modeset(struct intel_atomic_state *state, crtc_state->hw.enable = crtc_state->uapi.enable; crtc_state->hw.active = crtc_state->uapi.active; - crtc_state->hw.mode = crtc_state->uapi.mode; - crtc_state->hw.adjusted_mode = crtc_state->uapi.adjusted_mode; + drm_mode_copy(&crtc_state->hw.mode, + &crtc_state->uapi.mode); + drm_mode_copy(&crtc_state->hw.adjusted_mode, + &crtc_state->uapi.adjusted_mode); crtc_state->hw.scaling_filter = crtc_state->uapi.scaling_filter; intel_crtc_copy_uapi_to_hw_state_nomodeset(state, crtc); @@ -5563,6 +5619,9 @@ copy_bigjoiner_crtc_state_modeset(struct intel_atomic_state *state, intel_atomic_get_new_crtc_state(state, master_crtc); struct intel_crtc_state *saved_state; + WARN_ON(master_crtc_state->bigjoiner_pipes != + slave_crtc_state->bigjoiner_pipes); + saved_state = kmemdup(master_crtc_state, sizeof(*saved_state), GFP_KERNEL); if (!saved_state) return -ENOMEM; @@ -5582,19 +5641,22 @@ copy_bigjoiner_crtc_state_modeset(struct intel_atomic_state *state, memset(&slave_crtc_state->hw, 0, sizeof(slave_crtc_state->hw)); slave_crtc_state->hw.enable = master_crtc_state->hw.enable; slave_crtc_state->hw.active = master_crtc_state->hw.active; - slave_crtc_state->hw.mode = master_crtc_state->hw.mode; - slave_crtc_state->hw.pipe_mode = master_crtc_state->hw.pipe_mode; - slave_crtc_state->hw.adjusted_mode = master_crtc_state->hw.adjusted_mode; + drm_mode_copy(&slave_crtc_state->hw.mode, + &master_crtc_state->hw.mode); + drm_mode_copy(&slave_crtc_state->hw.pipe_mode, + &master_crtc_state->hw.pipe_mode); + drm_mode_copy(&slave_crtc_state->hw.adjusted_mode, + &master_crtc_state->hw.adjusted_mode); slave_crtc_state->hw.scaling_filter = master_crtc_state->hw.scaling_filter; copy_bigjoiner_crtc_state_nomodeset(state, slave_crtc); - /* Some fixups */ slave_crtc_state->uapi.mode_changed = master_crtc_state->uapi.mode_changed; slave_crtc_state->uapi.connectors_changed = master_crtc_state->uapi.connectors_changed; slave_crtc_state->uapi.active_changed = master_crtc_state->uapi.active_changed; - slave_crtc_state->cpu_transcoder = master_crtc_state->cpu_transcoder; - slave_crtc_state->has_audio = master_crtc_state->has_audio; + + WARN_ON(master_crtc_state->bigjoiner_pipes != + slave_crtc_state->bigjoiner_pipes); return 0; } @@ -5647,12 +5709,15 @@ intel_modeset_pipe_config(struct intel_atomic_state *state, struct drm_i915_private *i915 = to_i915(pipe_config->uapi.crtc->dev); struct drm_connector *connector; struct drm_connector_state *connector_state; + int pipe_src_w, pipe_src_h; int base_bpp, ret, i; bool retry = true; pipe_config->cpu_transcoder = (enum transcoder) to_intel_crtc(crtc)->pipe; + pipe_config->framestart_delay = 1; + /* * Sanitize sync polarity flags based on requested ones. If neither * positive or negative polarity is requested, treat this as meaning @@ -5682,8 +5747,9 @@ intel_modeset_pipe_config(struct intel_atomic_state *state, * can be changed by the connectors in the below retry loop. */ drm_mode_get_hv_timing(&pipe_config->hw.mode, - &pipe_config->pipe_src_w, - &pipe_config->pipe_src_h); + &pipe_src_w, &pipe_src_h); + drm_rect_init(&pipe_config->pipe_src, 0, 0, + pipe_src_w, pipe_src_h); for_each_new_connector_in_state(&state->base, connector, connector_state, i) { struct intel_encoder *encoder = @@ -5786,6 +5852,8 @@ intel_modeset_pipe_config_late(struct intel_crtc_state *crtc_state) struct drm_connector *connector; int i; + intel_bigjoiner_adjust_pipe_src(crtc_state); + for_each_new_connector_in_state(&state->base, connector, conn_state, i) { struct intel_encoder *encoder = @@ -6022,8 +6090,8 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, if (current_config->name != pipe_config->name) { \ pipe_config_mismatch(fastset, crtc, __stringify(name), \ "(expected %s, found %s)", \ - yesno(current_config->name), \ - yesno(pipe_config->name)); \ + str_yes_no(current_config->name), \ + str_yes_no(pipe_config->name)); \ ret = false; \ } \ } while (0) @@ -6039,8 +6107,8 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, } else { \ pipe_config_mismatch(fastset, crtc, __stringify(name), \ "unable to verify whether state matches exactly, forcing modeset (expected %s, found %s)", \ - yesno(current_config->name), \ - yesno(pipe_config->name)); \ + str_yes_no(current_config->name), \ + str_yes_no(pipe_config->name)); \ ret = false; \ } \ } while (0) @@ -6190,6 +6258,9 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, PIPE_CONF_CHECK_X(output_types); + PIPE_CONF_CHECK_I(framestart_delay); + PIPE_CONF_CHECK_I(msa_timing_delay); + PIPE_CONF_CHECK_I(hw.pipe_mode.crtc_hdisplay); PIPE_CONF_CHECK_I(hw.pipe_mode.crtc_htotal); PIPE_CONF_CHECK_I(hw.pipe_mode.crtc_hblank_start); @@ -6260,8 +6331,10 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, PIPE_CONF_CHECK_BOOL(pch_pfit.force_thru); if (!fastset) { - PIPE_CONF_CHECK_I(pipe_src_w); - PIPE_CONF_CHECK_I(pipe_src_h); + PIPE_CONF_CHECK_I(pipe_src.x1); + PIPE_CONF_CHECK_I(pipe_src.y1); + PIPE_CONF_CHECK_I(pipe_src.x2); + PIPE_CONF_CHECK_I(pipe_src.y2); PIPE_CONF_CHECK_BOOL(pch_pfit.enabled); if (current_config->pch_pfit.enabled) { @@ -6363,7 +6436,6 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, PIPE_CONF_CHECK_X(sync_mode_slaves_mask); PIPE_CONF_CHECK_I(master_transcoder); - PIPE_CONF_CHECK_BOOL(bigjoiner); PIPE_CONF_CHECK_X(bigjoiner_pipes); PIPE_CONF_CHECK_I(dsc.compression_enable); @@ -6420,8 +6492,8 @@ static void verify_wm_state(struct intel_crtc *crtc, { struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); struct skl_hw_state { + struct skl_ddb_entry ddb[I915_MAX_PLANES]; struct skl_ddb_entry ddb_y[I915_MAX_PLANES]; - struct skl_ddb_entry ddb_uv[I915_MAX_PLANES]; struct skl_pipe_wm wm; } *hw; const struct skl_pipe_wm *sw_wm = &new_crtc_state->wm.skl.optimal; @@ -6438,7 +6510,7 @@ static void verify_wm_state(struct intel_crtc *crtc, skl_pipe_wm_get_hw_state(crtc, &hw->wm); - skl_pipe_ddb_get_hw_state(crtc, hw->ddb_y, hw->ddb_uv); + skl_pipe_ddb_get_hw_state(crtc, hw->ddb, hw->ddb_y); hw_enabled_slices = intel_enabled_dbuf_slices_mask(dev_priv); @@ -6520,8 +6592,8 @@ static void verify_wm_state(struct intel_crtc *crtc, } /* DDB */ - hw_ddb_entry = &hw->ddb_y[plane->id]; - sw_ddb_entry = &new_crtc_state->wm.skl.plane_ddb_y[plane->id]; + hw_ddb_entry = &hw->ddb[PLANE_CURSOR]; + sw_ddb_entry = &new_crtc_state->wm.skl.plane_ddb[PLANE_CURSOR]; if (!skl_ddb_entry_equal(hw_ddb_entry, sw_ddb_entry)) { drm_err(&dev_priv->drm, @@ -7294,32 +7366,26 @@ static int intel_atomic_check_bigjoiner(struct intel_atomic_state *state, struct intel_crtc_state *master_crtc_state = intel_atomic_get_new_crtc_state(state, master_crtc); struct intel_crtc *slave_crtc; - u8 slave_pipes; - - /* - * TODO: encoder.compute_config() may be the best - * place to populate the bitmask for the master crtc. - * For now encoder.compute_config() just flags things - * as needing bigjoiner and we populate the bitmask - * here. - */ - WARN_ON(master_crtc_state->bigjoiner_pipes); - if (!master_crtc_state->bigjoiner) + if (!master_crtc_state->bigjoiner_pipes) return 0; - slave_pipes = BIT(master_crtc->pipe + 1); + /* sanity check */ + if (drm_WARN_ON(&i915->drm, + master_crtc->pipe != bigjoiner_master_pipe(master_crtc_state))) + return -EINVAL; - if (slave_pipes & ~bigjoiner_pipes(i915)) { + if (master_crtc_state->bigjoiner_pipes & ~bigjoiner_pipes(i915)) { drm_dbg_kms(&i915->drm, "[CRTC:%d:%s] Cannot act as big joiner master " - "(need 0x%x as slave pipes, only 0x%x possible)\n", + "(need 0x%x as pipes, only 0x%x possible)\n", master_crtc->base.base.id, master_crtc->base.name, - slave_pipes, bigjoiner_pipes(i915)); + master_crtc_state->bigjoiner_pipes, bigjoiner_pipes(i915)); return -EINVAL; } - for_each_intel_crtc_in_pipe_mask(&i915->drm, slave_crtc, slave_pipes) { + for_each_intel_crtc_in_pipe_mask(&i915->drm, slave_crtc, + intel_crtc_bigjoiner_slave_pipes(master_crtc_state)) { struct intel_crtc_state *slave_crtc_state; int ret; @@ -7353,10 +7419,8 @@ static int intel_atomic_check_bigjoiner(struct intel_atomic_state *state, slave_crtc->base.base.id, slave_crtc->base.name, master_crtc->base.base.id, master_crtc->base.name); - master_crtc_state->bigjoiner_pipes = - BIT(master_crtc->pipe) | BIT(slave_crtc->pipe); slave_crtc_state->bigjoiner_pipes = - BIT(master_crtc->pipe) | BIT(slave_crtc->pipe); + master_crtc_state->bigjoiner_pipes; ret = copy_bigjoiner_crtc_state_modeset(state, slave_crtc); if (ret) @@ -7379,13 +7443,11 @@ static void kill_bigjoiner_slave(struct intel_atomic_state *state, struct intel_crtc_state *slave_crtc_state = intel_atomic_get_new_crtc_state(state, slave_crtc); - slave_crtc_state->bigjoiner = false; slave_crtc_state->bigjoiner_pipes = 0; intel_crtc_copy_uapi_to_hw_state_modeset(state, slave_crtc); } - master_crtc_state->bigjoiner = false; master_crtc_state->bigjoiner_pipes = 0; } @@ -7479,18 +7541,24 @@ static int intel_async_flip_check_hw(struct intel_atomic_state *state, struct in if (!new_crtc_state->uapi.async_flip) return 0; - if (intel_crtc_needs_modeset(new_crtc_state)) { - drm_dbg_kms(&i915->drm, "Modeset Required. Async flip not supported\n"); + if (!new_crtc_state->hw.active) { + drm_dbg_kms(&i915->drm, + "[CRTC:%d:%s] not active\n", + crtc->base.base.id, crtc->base.name); return -EINVAL; } - if (!new_crtc_state->hw.active) { - drm_dbg_kms(&i915->drm, "CRTC inactive\n"); + if (intel_crtc_needs_modeset(new_crtc_state)) { + drm_dbg_kms(&i915->drm, + "[CRTC:%d:%s] modeset required\n", + crtc->base.base.id, crtc->base.name); return -EINVAL; } + if (old_crtc_state->active_planes != new_crtc_state->active_planes) { drm_dbg_kms(&i915->drm, - "Active planes cannot be changed during async flip\n"); + "[CRTC:%d:%s] Active planes cannot be in async flip\n", + crtc->base.base.id, crtc->base.name); return -EINVAL; } @@ -7528,78 +7596,98 @@ static int intel_async_flip_check_hw(struct intel_atomic_state *state, struct in case I915_FORMAT_MOD_X_TILED: case I915_FORMAT_MOD_Y_TILED: case I915_FORMAT_MOD_Yf_TILED: + case I915_FORMAT_MOD_4_TILED: break; default: drm_dbg_kms(&i915->drm, - "Linear memory/CCS does not support async flips\n"); + "[PLANE:%d:%s] Modifier does not support async flips\n", + plane->base.base.id, plane->base.name); return -EINVAL; } if (new_plane_state->hw.fb->format->num_planes > 1) { drm_dbg_kms(&i915->drm, - "Planar formats not supported with async flips\n"); + "[PLANE:%d:%s] Planar formats do not support async flips\n", + plane->base.base.id, plane->base.name); return -EINVAL; } if (old_plane_state->view.color_plane[0].mapping_stride != new_plane_state->view.color_plane[0].mapping_stride) { - drm_dbg_kms(&i915->drm, "Stride cannot be changed in async flip\n"); + drm_dbg_kms(&i915->drm, + "[PLANE:%d:%s] Stride cannot be changed in async flip\n", + plane->base.base.id, plane->base.name); return -EINVAL; } if (old_plane_state->hw.fb->modifier != new_plane_state->hw.fb->modifier) { drm_dbg_kms(&i915->drm, - "Framebuffer modifiers cannot be changed in async flip\n"); + "[PLANE:%d:%s] Modifier cannot be changed in async flip\n", + plane->base.base.id, plane->base.name); return -EINVAL; } if (old_plane_state->hw.fb->format != new_plane_state->hw.fb->format) { drm_dbg_kms(&i915->drm, - "Framebuffer format cannot be changed in async flip\n"); + "[PLANE:%d:%s] Pixel format cannot be changed in async flip\n", + plane->base.base.id, plane->base.name); return -EINVAL; } if (old_plane_state->hw.rotation != new_plane_state->hw.rotation) { - drm_dbg_kms(&i915->drm, "Rotation cannot be changed in async flip\n"); + drm_dbg_kms(&i915->drm, + "[PLANE:%d:%s] Rotation cannot be changed in async flip\n", + plane->base.base.id, plane->base.name); return -EINVAL; } if (!drm_rect_equals(&old_plane_state->uapi.src, &new_plane_state->uapi.src) || !drm_rect_equals(&old_plane_state->uapi.dst, &new_plane_state->uapi.dst)) { drm_dbg_kms(&i915->drm, - "Plane size/co-ordinates cannot be changed in async flip\n"); + "[PLANE:%d:%s] Size/co-ordinates cannot be changed in async flip\n", + plane->base.base.id, plane->base.name); return -EINVAL; } if (old_plane_state->hw.alpha != new_plane_state->hw.alpha) { - drm_dbg_kms(&i915->drm, "Alpha value cannot be changed in async flip\n"); + drm_dbg_kms(&i915->drm, + "[PLANES:%d:%s] Alpha value cannot be changed in async flip\n", + plane->base.base.id, plane->base.name); return -EINVAL; } if (old_plane_state->hw.pixel_blend_mode != new_plane_state->hw.pixel_blend_mode) { drm_dbg_kms(&i915->drm, - "Pixel blend mode cannot be changed in async flip\n"); + "[PLANE:%d:%s] Pixel blend mode cannot be changed in async flip\n", + plane->base.base.id, plane->base.name); return -EINVAL; } if (old_plane_state->hw.color_encoding != new_plane_state->hw.color_encoding) { drm_dbg_kms(&i915->drm, - "Color encoding cannot be changed in async flip\n"); + "[PLANE:%d:%s] Color encoding cannot be changed in async flip\n", + plane->base.base.id, plane->base.name); return -EINVAL; } if (old_plane_state->hw.color_range != new_plane_state->hw.color_range) { - drm_dbg_kms(&i915->drm, "Color range cannot be changed in async flip\n"); + drm_dbg_kms(&i915->drm, + "[PLANE:%d:%s] Color range cannot be changed in async flip\n", + plane->base.base.id, plane->base.name); return -EINVAL; } /* plane decryption is allow to change only in synchronous flips */ - if (old_plane_state->decrypt != new_plane_state->decrypt) + if (old_plane_state->decrypt != new_plane_state->decrypt) { + drm_dbg_kms(&i915->drm, + "[PLANE:%d:%s] Decryption cannot be changed in async flip\n", + plane->base.base.id, plane->base.name); return -EINVAL; + } } return 0; @@ -7772,7 +7860,7 @@ static int intel_atomic_check(struct drm_device *dev, } } - if (new_crtc_state->bigjoiner) { + if (new_crtc_state->bigjoiner_pipes) { if (intel_pipes_need_modeset(state, new_crtc_state->bigjoiner_pipes)) { new_crtc_state->uapi.mode_changed = true; new_crtc_state->update_pipe = false; @@ -7970,7 +8058,7 @@ static void commit_pipe_pre_planes(struct intel_atomic_state *state, if (!modeset) { if (new_crtc_state->uapi.color_mgmt_changed || new_crtc_state->update_pipe) - intel_color_commit(new_crtc_state); + intel_color_commit_arm(new_crtc_state); if (DISPLAY_VER(dev_priv) >= 9 || IS_BROADWELL(dev_priv)) bdw_set_pipemisc(new_crtc_state); @@ -8050,6 +8138,11 @@ static void intel_update_crtc(struct intel_atomic_state *state, intel_fbc_update(state, crtc); + if (!modeset && + (new_crtc_state->uapi.color_mgmt_changed || + new_crtc_state->update_pipe)) + intel_color_commit_noarm(new_crtc_state); + intel_crtc_planes_update_noarm(state, crtc); /* Perform vblank evasion around commit operation */ @@ -8384,7 +8477,9 @@ static void intel_atomic_prepare_plane_clear_colors(struct intel_atomic_state *s /* * The layout of the fast clear color value expected by HW - * (the DRM ABI requiring this value to be located in fb at offset 0 of plane#2): + * (the DRM ABI requiring this value to be located in fb at + * offset 0 of cc plane, plane #2 previous generations or + * plane #1 for flat ccs): * - 4 x 4 bytes per-channel value * (in surface type specific float/int format provided by the fb user) * - 8 bytes native color value used by the display @@ -8467,6 +8562,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) intel_encoders_update_prepare(state); intel_dbuf_pre_plane_update(state); + intel_mbus_dbox_update(state); for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { if (new_crtc_state->do_async_flip) @@ -9573,8 +9669,6 @@ int intel_modeset_init_noirq(struct drm_i915_private *i915) i915->flip_wq = alloc_workqueue("i915_flip", WQ_HIGHPRI | WQ_UNBOUND, WQ_UNBOUND_MAX_ACTIVE); - i915->framestart_delay = 1; /* 1-4 */ - i915->window2_delay = 0; /* No DSB so no window2 delay */ intel_mode_config_init(i915); @@ -9871,64 +9965,6 @@ static struct intel_connector *intel_encoder_find_connector(struct intel_encoder return NULL; } -static bool has_pch_trancoder(struct drm_i915_private *dev_priv, - enum pipe pch_transcoder) -{ - return HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv) || - (HAS_PCH_LPT_H(dev_priv) && pch_transcoder == PIPE_A); -} - -static void intel_sanitize_frame_start_delay(const struct intel_crtc_state *crtc_state) -{ - struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; - - if (DISPLAY_VER(dev_priv) >= 9 || - IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv)) { - i915_reg_t reg = CHICKEN_TRANS(cpu_transcoder); - u32 val; - - if (transcoder_is_dsi(cpu_transcoder)) - return; - - val = intel_de_read(dev_priv, reg); - val &= ~HSW_FRAME_START_DELAY_MASK; - val |= HSW_FRAME_START_DELAY(dev_priv->framestart_delay - 1); - intel_de_write(dev_priv, reg, val); - } else { - i915_reg_t reg = PIPECONF(cpu_transcoder); - u32 val; - - val = intel_de_read(dev_priv, reg); - val &= ~PIPECONF_FRAME_START_DELAY_MASK; - val |= PIPECONF_FRAME_START_DELAY(dev_priv->framestart_delay - 1); - intel_de_write(dev_priv, reg, val); - } - - if (!crtc_state->has_pch_encoder) - return; - - if (HAS_PCH_IBX(dev_priv)) { - i915_reg_t reg = PCH_TRANSCONF(crtc->pipe); - u32 val; - - val = intel_de_read(dev_priv, reg); - val &= ~TRANS_FRAME_START_DELAY_MASK; - val |= TRANS_FRAME_START_DELAY(dev_priv->framestart_delay - 1); - intel_de_write(dev_priv, reg, val); - } else { - enum pipe pch_transcoder = intel_crtc_pch_transcoder(crtc); - i915_reg_t reg = TRANS_CHICKEN2(pch_transcoder); - u32 val; - - val = intel_de_read(dev_priv, reg); - val &= ~TRANS_CHICKEN2_FRAME_START_DELAY_MASK; - val |= TRANS_CHICKEN2_FRAME_START_DELAY(dev_priv->framestart_delay - 1); - intel_de_write(dev_priv, reg, val); - } -} - static void intel_sanitize_crtc(struct intel_crtc *crtc, struct drm_modeset_acquire_ctx *ctx) { @@ -9939,9 +9975,6 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc, if (crtc_state->hw.active) { struct intel_plane *plane; - /* Clear any frame start delays used for debugging left by the BIOS */ - intel_sanitize_frame_start_delay(crtc_state); - /* Disable everything but the primary plane */ for_each_intel_plane_on_crtc(dev, crtc, plane) { const struct intel_plane_state *plane_state = @@ -9953,7 +9986,8 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc, } /* Disable any background color/etc. set by the BIOS */ - intel_color_commit(crtc_state); + intel_color_commit_noarm(crtc_state); + intel_color_commit_arm(crtc_state); } /* Adjust the state of the output pipe according to whether we @@ -9986,7 +10020,7 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc, * PCH transcoders B and C would prevent enabling the south * error interrupt (see cpt_can_enable_serr_int()). */ - if (has_pch_trancoder(dev_priv, crtc->pipe)) + if (intel_has_pch_trancoder(dev_priv, crtc->pipe)) crtc->pch_fifo_underrun_disabled = true; } } @@ -10105,7 +10139,7 @@ static void readout_plane_state(struct drm_i915_private *dev_priv) drm_dbg_kms(&dev_priv->drm, "[PLANE:%d:%s] hw state readout: %s, pipe %c\n", plane->base.base.id, plane->base.name, - enableddisabled(visible), pipe_name(pipe)); + str_enabled_disabled(visible), pipe_name(pipe)); } for_each_intel_crtc(&dev_priv->drm, crtc) { @@ -10151,7 +10185,7 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) drm_dbg_kms(&dev_priv->drm, "[CRTC:%d:%s] hw state readout: %s\n", crtc->base.base.id, crtc->base.name, - enableddisabled(crtc_state->hw.active)); + str_enabled_disabled(crtc_state->hw.active)); } cdclk_state->active_pipes = dbuf_state->active_pipes = active_pipes; @@ -10171,7 +10205,7 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) intel_encoder_get_config(encoder, crtc_state); /* read out to slave crtc as well for bigjoiner */ - if (crtc_state->bigjoiner) { + if (crtc_state->bigjoiner_pipes) { struct intel_crtc *slave_crtc; /* encoder should read be linked to bigjoiner master */ @@ -10195,7 +10229,7 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) drm_dbg_kms(&dev_priv->drm, "[ENCODER:%d:%s] hw state readout: %s, pipe %c\n", encoder->base.base.id, encoder->base.name, - enableddisabled(encoder->base.crtc), + str_enabled_disabled(encoder->base.crtc), pipe_name(pipe)); } @@ -10233,7 +10267,7 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) drm_dbg_kms(&dev_priv->drm, "[CONNECTOR:%d:%s] hw state readout: %s\n", connector->base.base.id, connector->base.name, - enableddisabled(connector->base.encoder)); + str_enabled_disabled(connector->base.encoder)); } drm_connector_list_iter_end(&conn_iter); @@ -10359,66 +10393,6 @@ static void intel_early_display_was(struct drm_i915_private *dev_priv) } } -static void ibx_sanitize_pch_hdmi_port(struct drm_i915_private *dev_priv, - enum port port, i915_reg_t hdmi_reg) -{ - u32 val = intel_de_read(dev_priv, hdmi_reg); - - if (val & SDVO_ENABLE || - (val & SDVO_PIPE_SEL_MASK) == SDVO_PIPE_SEL(PIPE_A)) - return; - - drm_dbg_kms(&dev_priv->drm, - "Sanitizing transcoder select for HDMI %c\n", - port_name(port)); - - val &= ~SDVO_PIPE_SEL_MASK; - val |= SDVO_PIPE_SEL(PIPE_A); - - intel_de_write(dev_priv, hdmi_reg, val); -} - -static void ibx_sanitize_pch_dp_port(struct drm_i915_private *dev_priv, - enum port port, i915_reg_t dp_reg) -{ - u32 val = intel_de_read(dev_priv, dp_reg); - - if (val & DP_PORT_EN || - (val & DP_PIPE_SEL_MASK) == DP_PIPE_SEL(PIPE_A)) - return; - - drm_dbg_kms(&dev_priv->drm, - "Sanitizing transcoder select for DP %c\n", - port_name(port)); - - val &= ~DP_PIPE_SEL_MASK; - val |= DP_PIPE_SEL(PIPE_A); - - intel_de_write(dev_priv, dp_reg, val); -} - -static void ibx_sanitize_pch_ports(struct drm_i915_private *dev_priv) -{ - /* - * The BIOS may select transcoder B on some of the PCH - * ports even it doesn't enable the port. This would trip - * assert_pch_dp_disabled() and assert_pch_hdmi_disabled(). - * Sanitize the transcoder select bits to prevent that. We - * assume that the BIOS never actually enabled the port, - * because if it did we'd actually have to toggle the port - * on and back off to make the transcoder A select stick - * (see. intel_dp_link_down(), intel_disable_hdmi(), - * intel_disable_sdvo()). - */ - ibx_sanitize_pch_dp_port(dev_priv, PORT_B, PCH_DP_B); - ibx_sanitize_pch_dp_port(dev_priv, PORT_C, PCH_DP_C); - ibx_sanitize_pch_dp_port(dev_priv, PORT_D, PCH_DP_D); - - /* PCH SDVOB multiplex with HDMIB */ - ibx_sanitize_pch_hdmi_port(dev_priv, PORT_B, PCH_HDMIB); - ibx_sanitize_pch_hdmi_port(dev_priv, PORT_C, PCH_HDMIC); - ibx_sanitize_pch_hdmi_port(dev_priv, PORT_D, PCH_HDMID); -} /* Scan out the current hw modeset state, * and sanitizes it to the current state @@ -10440,8 +10414,7 @@ intel_modeset_setup_hw_state(struct drm_device *dev, /* HW state is read out, now we need to sanitize this mess. */ get_encoder_power_domains(dev_priv); - if (HAS_PCH_IBX(dev_priv)) - ibx_sanitize_pch_ports(dev_priv); + intel_pch_sanitize(dev_priv); /* * intel_sanitize_plane_mapping() may need to do vblank @@ -10457,6 +10430,8 @@ intel_modeset_setup_hw_state(struct drm_device *dev, intel_crtc_vblank_on(crtc_state); } + intel_fbc_sanitize(dev_priv); + intel_sanitize_plane_mapping(dev_priv); for_each_intel_encoder(dev, encoder) @@ -10595,8 +10570,6 @@ void intel_modeset_driver_remove_noirq(struct drm_i915_private *i915) intel_unregister_dsm_handler(); - intel_fbc_global_disable(i915); - /* flush any delayed tasks or pending work */ flush_scheduled_work(); @@ -10697,3 +10670,8 @@ void intel_display_driver_unregister(struct drm_i915_private *i915) acpi_video_unregister(); intel_opregion_unregister(i915); } + +bool intel_scanout_needs_vtd_wa(struct drm_i915_private *i915) +{ + return DISPLAY_VER(i915) >= 6 && i915_vtd_active(i915); +} diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index 11d6134c53c8..867fa248f042 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -565,7 +565,6 @@ void intel_enable_transcoder(const struct intel_crtc_state *new_crtc_state); void intel_disable_transcoder(const struct intel_crtc_state *old_crtc_state); void i830_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe); void i830_disable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe); -enum pipe intel_crtc_pch_transcoder(struct intel_crtc *crtc); int vlv_get_hpll_vco(struct drm_i915_private *dev_priv); int vlv_get_cck_clock(struct drm_i915_private *dev_priv, const char *name, u32 reg, int ref_freq); @@ -695,4 +694,6 @@ void assert_transcoder(struct drm_i915_private *dev_priv, #define I915_STATE_WARN_ON(x) \ I915_STATE_WARN((x), "%s", "WARN_ON(" __stringify(x) ")") +bool intel_scanout_needs_vtd_wa(struct drm_i915_private *i915); + #endif diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c index ffe6822d7414..452d773fd4e3 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c @@ -3,6 +3,8 @@ * Copyright © 2020 Intel Corporation */ +#include <linux/string_helpers.h> + #include <drm/drm_debugfs.h> #include <drm/drm_fourcc.h> @@ -10,6 +12,7 @@ #include "intel_de.h" #include "intel_display_debugfs.h" #include "intel_display_power.h" +#include "intel_display_power_well.h" #include "intel_display_types.h" #include "intel_dmc.h" #include "intel_dp.h" @@ -19,6 +22,7 @@ #include "intel_fbdev.h" #include "intel_hdcp.h" #include "intel_hdmi.h" +#include "intel_panel.h" #include "intel_pm.h" #include "intel_psr.h" #include "intel_sprite.h" @@ -52,7 +56,7 @@ static int i915_ips_status(struct seq_file *m, void *unused) wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm); seq_printf(m, "Enabled by kernel parameter: %s\n", - yesno(dev_priv->params.enable_ips)); + str_yes_no(dev_priv->params.enable_ips)); if (DISPLAY_VER(dev_priv) >= 8) { seq_puts(m, "Currently: unknown\n"); @@ -92,7 +96,7 @@ static int i915_sr_status(struct seq_file *m, void *unused) intel_display_power_put(dev_priv, POWER_DOMAIN_INIT, wakeref); - seq_printf(m, "self-refresh: %s\n", enableddisabled(sr_enabled)); + seq_printf(m, "self-refresh: %s\n", str_enabled_disabled(sr_enabled)); return 0; } @@ -260,7 +264,7 @@ static int intel_psr_status(struct seq_file *m, struct intel_dp *intel_dp) bool enabled; u32 val; - seq_printf(m, "Sink support: %s", yesno(psr->sink_support)); + seq_printf(m, "Sink support: %s", str_yes_no(psr->sink_support)); if (psr->sink_support) seq_printf(m, " [0x%02x]", intel_dp->psr_dpcd[0]); seq_puts(m, "\n"); @@ -279,7 +283,7 @@ static int intel_psr_status(struct seq_file *m, struct intel_dp *intel_dp) if (!psr->enabled) { seq_printf(m, "PSR sink not reliable: %s\n", - yesno(psr->sink_not_reliable)); + str_yes_no(psr->sink_not_reliable)); goto unlock; } @@ -294,7 +298,7 @@ static int intel_psr_status(struct seq_file *m, struct intel_dp *intel_dp) enabled = val & EDP_PSR_ENABLE; } seq_printf(m, "Source PSR ctl: %s [0x%08x]\n", - enableddisabled(enabled), val); + str_enabled_disabled(enabled), val); psr_source_status(intel_dp, m); seq_printf(m, "Busy frontbuffer bits: 0x%08x\n", psr->busy_frontbuffer_bits); @@ -341,7 +345,7 @@ static int intel_psr_status(struct seq_file *m, struct intel_dp *intel_dp) } seq_printf(m, "PSR2 selective fetch: %s\n", - enableddisabled(psr->psr2_sel_fetch_enabled)); + str_enabled_disabled(psr->psr2_sel_fetch_enabled)); } unlock: @@ -432,75 +436,6 @@ static int i915_power_domain_info(struct seq_file *m, void *unused) return 0; } -static int i915_dmc_info(struct seq_file *m, void *unused) -{ - struct drm_i915_private *dev_priv = node_to_i915(m->private); - intel_wakeref_t wakeref; - struct intel_dmc *dmc; - i915_reg_t dc5_reg, dc6_reg = {}; - - if (!HAS_DMC(dev_priv)) - return -ENODEV; - - dmc = &dev_priv->dmc; - - wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm); - - seq_printf(m, "fw loaded: %s\n", yesno(intel_dmc_has_payload(dev_priv))); - seq_printf(m, "path: %s\n", dmc->fw_path); - seq_printf(m, "Pipe A fw support: %s\n", - yesno(GRAPHICS_VER(dev_priv) >= 12)); - seq_printf(m, "Pipe A fw loaded: %s\n", yesno(dmc->dmc_info[DMC_FW_PIPEA].payload)); - seq_printf(m, "Pipe B fw support: %s\n", yesno(IS_ALDERLAKE_P(dev_priv))); - seq_printf(m, "Pipe B fw loaded: %s\n", yesno(dmc->dmc_info[DMC_FW_PIPEB].payload)); - - if (!intel_dmc_has_payload(dev_priv)) - goto out; - - seq_printf(m, "version: %d.%d\n", DMC_VERSION_MAJOR(dmc->version), - DMC_VERSION_MINOR(dmc->version)); - - if (DISPLAY_VER(dev_priv) >= 12) { - if (IS_DGFX(dev_priv)) { - dc5_reg = DG1_DMC_DEBUG_DC5_COUNT; - } else { - dc5_reg = TGL_DMC_DEBUG_DC5_COUNT; - dc6_reg = TGL_DMC_DEBUG_DC6_COUNT; - } - - /* - * NOTE: DMC_DEBUG3 is a general purpose reg. - * According to B.Specs:49196 DMC f/w reuses DC5/6 counter - * reg for DC3CO debugging and validation, - * but TGL DMC f/w is using DMC_DEBUG3 reg for DC3CO counter. - */ - seq_printf(m, "DC3CO count: %d\n", intel_de_read(dev_priv, IS_DGFX(dev_priv) ? - DG1_DMC_DEBUG3 : TGL_DMC_DEBUG3)); - } else { - dc5_reg = IS_BROXTON(dev_priv) ? BXT_DMC_DC3_DC5_COUNT : - SKL_DMC_DC3_DC5_COUNT; - if (!IS_GEMINILAKE(dev_priv) && !IS_BROXTON(dev_priv)) - dc6_reg = SKL_DMC_DC5_DC6_COUNT; - } - - seq_printf(m, "DC3 -> DC5 count: %d\n", - intel_de_read(dev_priv, dc5_reg)); - if (dc6_reg.reg) - seq_printf(m, "DC5 -> DC6 count: %d\n", - intel_de_read(dev_priv, dc6_reg)); - -out: - seq_printf(m, "program base: 0x%08x\n", - intel_de_read(dev_priv, DMC_PROGRAM(dmc->dmc_info[DMC_FW_MAIN].start_mmioaddr, 0))); - seq_printf(m, "ssp base: 0x%08x\n", - intel_de_read(dev_priv, DMC_SSP_BASE)); - seq_printf(m, "htp: 0x%08x\n", intel_de_read(dev_priv, DMC_HTP_SKL)); - - intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref); - - return 0; -} - static void intel_seq_print_mode(struct seq_file *m, int tabs, const struct drm_display_mode *mode) { @@ -537,11 +472,18 @@ static void intel_encoder_info(struct seq_file *m, drm_connector_list_iter_end(&conn_iter); } -static void intel_panel_info(struct seq_file *m, struct intel_panel *panel) +static void intel_panel_info(struct seq_file *m, + struct intel_connector *connector) { - const struct drm_display_mode *mode = panel->fixed_mode; + const struct drm_display_mode *fixed_mode; + + if (list_empty(&connector->panel.fixed_modes)) + return; - seq_printf(m, "\tfixed mode: " DRM_MODE_FMT "\n", DRM_MODE_ARG(mode)); + seq_puts(m, "\tfixed modes:\n"); + + list_for_each_entry(fixed_mode, &connector->panel.fixed_modes, head) + intel_seq_print_mode(m, 2, fixed_mode); } static void intel_hdcp_info(struct seq_file *m, @@ -577,9 +519,8 @@ static void intel_dp_info(struct seq_file *m, const struct drm_property_blob *edid = intel_connector->base.edid_blob_ptr; seq_printf(m, "\tDPCD rev: %x\n", intel_dp->dpcd[DP_DPCD_REV]); - seq_printf(m, "\taudio support: %s\n", yesno(intel_dp->has_audio)); - if (intel_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP) - intel_panel_info(m, &intel_connector->panel); + seq_printf(m, "\taudio support: %s\n", + str_yes_no(intel_dp->has_audio)); drm_dp_downstream_debug(m, intel_dp->dpcd, intel_dp->downstream_ports, edid ? edid->data : NULL, &intel_dp->aux); @@ -590,7 +531,7 @@ static void intel_dp_mst_info(struct seq_file *m, { bool has_audio = intel_connector->port->has_audio; - seq_printf(m, "\taudio support: %s\n", yesno(has_audio)); + seq_printf(m, "\taudio support: %s\n", str_yes_no(has_audio)); } static void intel_hdmi_info(struct seq_file *m, @@ -599,13 +540,8 @@ static void intel_hdmi_info(struct seq_file *m, struct intel_encoder *intel_encoder = intel_attached_encoder(intel_connector); struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(intel_encoder); - seq_printf(m, "\taudio support: %s\n", yesno(intel_hdmi->has_audio)); -} - -static void intel_lvds_info(struct seq_file *m, - struct intel_connector *intel_connector) -{ - intel_panel_info(m, &intel_connector->panel); + seq_printf(m, "\taudio support: %s\n", + str_yes_no(intel_hdmi->has_audio)); } static void intel_connector_info(struct seq_file *m, @@ -642,10 +578,6 @@ static void intel_connector_info(struct seq_file *m, else intel_dp_info(m, intel_connector); break; - case DRM_MODE_CONNECTOR_LVDS: - if (encoder->type == INTEL_OUTPUT_LVDS) - intel_lvds_info(m, intel_connector); - break; case DRM_MODE_CONNECTOR_HDMIA: if (encoder->type == INTEL_OUTPUT_HDMI || encoder->type == INTEL_OUTPUT_DDI) @@ -658,6 +590,8 @@ static void intel_connector_info(struct seq_file *m, seq_puts(m, "\tHDCP version: "); intel_hdcp_info(m, intel_connector); + intel_panel_info(m, intel_connector); + seq_printf(m, "\tmodes:\n"); list_for_each_entry(mode, &connector->modes, head) intel_seq_print_mode(m, 2, mode); @@ -757,7 +691,7 @@ static void intel_plane_hw_info(struct seq_file *m, struct intel_plane *plane) DRM_RECT_FP_FMT ", dst=" DRM_RECT_FMT ", rotation=%s\n", fb->base.id, &fb->format->format, fb->modifier, fb->width, fb->height, - yesno(plane_state->uapi.visible), + str_yes_no(plane_state->uapi.visible), DRM_RECT_FP_ARG(&plane_state->uapi.src), DRM_RECT_ARG(&plane_state->uapi.dst), rot_str); @@ -796,7 +730,7 @@ static void intel_scaler_info(struct seq_file *m, struct intel_crtc *crtc) &crtc_state->scaler_state.scalers[i]; seq_printf(m, ", scalers[%d]: use=%s, mode=%x", - i, yesno(sc->in_use), sc->mode); + i, str_yes_no(sc->in_use), sc->mode); } seq_puts(m, "\n"); } else { @@ -919,24 +853,24 @@ static void intel_crtc_info(struct seq_file *m, struct intel_crtc *crtc) crtc->base.base.id, crtc->base.name); seq_printf(m, "\tuapi: enable=%s, active=%s, mode=" DRM_MODE_FMT "\n", - yesno(crtc_state->uapi.enable), - yesno(crtc_state->uapi.active), + str_yes_no(crtc_state->uapi.enable), + str_yes_no(crtc_state->uapi.active), DRM_MODE_ARG(&crtc_state->uapi.mode)); seq_printf(m, "\thw: enable=%s, active=%s\n", - yesno(crtc_state->hw.enable), yesno(crtc_state->hw.active)); + str_yes_no(crtc_state->hw.enable), str_yes_no(crtc_state->hw.active)); seq_printf(m, "\tadjusted_mode=" DRM_MODE_FMT "\n", DRM_MODE_ARG(&crtc_state->hw.adjusted_mode)); seq_printf(m, "\tpipe__mode=" DRM_MODE_FMT "\n", DRM_MODE_ARG(&crtc_state->hw.pipe_mode)); - seq_printf(m, "\tpipe src size=%dx%d, dither=%s, bpp=%d\n", - crtc_state->pipe_src_w, crtc_state->pipe_src_h, - yesno(crtc_state->dither), crtc_state->pipe_bpp); + seq_printf(m, "\tpipe src=" DRM_RECT_FMT ", dither=%s, bpp=%d\n", + DRM_RECT_ARG(&crtc_state->pipe_src), + str_yes_no(crtc_state->dither), crtc_state->pipe_bpp); intel_scaler_info(m, crtc); - if (crtc_state->bigjoiner) + if (crtc_state->bigjoiner_pipes) seq_printf(m, "\tLinked to 0x%x pipes as a %s\n", crtc_state->bigjoiner_pipes, intel_crtc_is_bigjoiner_slave(crtc_state) ? "slave" : "master"); @@ -948,8 +882,8 @@ static void intel_crtc_info(struct seq_file *m, struct intel_crtc *crtc) intel_plane_info(m, crtc); seq_printf(m, "\tunderrun reporting: cpu=%s pch=%s\n", - yesno(!crtc->cpu_fifo_underrun_disabled), - yesno(!crtc->pch_fifo_underrun_disabled)); + str_yes_no(!crtc->cpu_fifo_underrun_disabled), + str_yes_no(!crtc->pch_fifo_underrun_disabled)); crtc_updates_info(m, crtc, "\t"); } @@ -1005,7 +939,8 @@ static int i915_shared_dplls_info(struct seq_file *m, void *unused) seq_printf(m, "DPLL%i: %s, id: %i\n", i, pll->info->name, pll->info->id); seq_printf(m, " pipe_mask: 0x%x, active: 0x%x, on: %s\n", - pll->state.pipe_mask, pll->active_mask, yesno(pll->on)); + pll->state.pipe_mask, pll->active_mask, + str_yes_no(pll->on)); seq_printf(m, " tracked hardware state:\n"); seq_printf(m, " dpll: 0x%08x\n", pll->state.hw_state.dpll); seq_printf(m, " dpll_md: 0x%08x\n", @@ -1047,7 +982,7 @@ static int i915_ipc_status_show(struct seq_file *m, void *data) struct drm_i915_private *dev_priv = m->private; seq_printf(m, "Isochronous Priority Control: %s\n", - yesno(dev_priv->ipc_enabled)); + str_yes_no(dev_priv->ipc_enabled)); return 0; } @@ -1117,13 +1052,13 @@ static int i915_ddb_info(struct seq_file *m, void *unused) seq_printf(m, "Pipe %c\n", pipe_name(pipe)); for_each_plane_id_on_crtc(crtc, plane_id) { - entry = &crtc_state->wm.skl.plane_ddb_y[plane_id]; + entry = &crtc_state->wm.skl.plane_ddb[plane_id]; seq_printf(m, " Plane%-8d%8u%8u%8u\n", plane_id + 1, entry->start, entry->end, skl_ddb_entry_size(entry)); } - entry = &crtc_state->wm.skl.plane_ddb_y[PLANE_CURSOR]; + entry = &crtc_state->wm.skl.plane_ddb[PLANE_CURSOR]; seq_printf(m, " %-13s%8u%8u%8u\n", "Cursor", entry->start, entry->end, skl_ddb_entry_size(entry)); } @@ -1133,97 +1068,48 @@ static int i915_ddb_info(struct seq_file *m, void *unused) return 0; } -static void drrs_status_per_crtc(struct seq_file *m, - struct drm_device *dev, - struct intel_crtc *crtc) +static int i915_drrs_status(struct seq_file *m, void *unused) { - struct drm_i915_private *dev_priv = to_i915(dev); - struct i915_drrs *drrs = &dev_priv->drrs; - int vrefresh = 0; - struct drm_connector *connector; + struct drm_i915_private *dev_priv = node_to_i915(m->private); struct drm_connector_list_iter conn_iter; + struct intel_connector *connector; + struct intel_crtc *crtc; - drm_connector_list_iter_begin(dev, &conn_iter); - drm_for_each_connector_iter(connector, &conn_iter) { - bool supported = false; - - if (connector->state->crtc != &crtc->base) - continue; - - seq_printf(m, "%s:\n", connector->name); - - if (connector->connector_type == DRM_MODE_CONNECTOR_eDP && - drrs->type == SEAMLESS_DRRS_SUPPORT) - supported = true; - - seq_printf(m, "\tDRRS Supported: %s\n", yesno(supported)); + drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter); + for_each_intel_connector_iter(connector, &conn_iter) { + seq_printf(m, "[CONNECTOR:%d:%s] DRRS type: %s\n", + connector->base.base.id, connector->base.name, + intel_drrs_type_str(intel_panel_drrs_type(connector))); } drm_connector_list_iter_end(&conn_iter); seq_puts(m, "\n"); - if (to_intel_crtc_state(crtc->base.state)->has_drrs) { - struct intel_panel *panel; + for_each_intel_crtc(&dev_priv->drm, crtc) { + const struct intel_crtc_state *crtc_state = + to_intel_crtc_state(crtc->base.state); - mutex_lock(&drrs->mutex); - /* DRRS Supported */ - seq_puts(m, "\tDRRS Enabled: Yes\n"); + seq_printf(m, "[CRTC:%d:%s]:\n", + crtc->base.base.id, crtc->base.name); - /* disable_drrs() will make drrs->dp NULL */ - if (!drrs->dp) { - seq_puts(m, "Idleness DRRS: Disabled\n"); - mutex_unlock(&drrs->mutex); - return; - } + mutex_lock(&crtc->drrs.mutex); - panel = &drrs->dp->attached_connector->panel; - seq_printf(m, "\t\tBusy_frontbuffer_bits: 0x%X", - drrs->busy_frontbuffer_bits); - - seq_puts(m, "\n\t\t"); - if (drrs->refresh_rate_type == DRRS_HIGH_RR) { - seq_puts(m, "DRRS_State: DRRS_HIGH_RR\n"); - vrefresh = drm_mode_vrefresh(panel->fixed_mode); - } else if (drrs->refresh_rate_type == DRRS_LOW_RR) { - seq_puts(m, "DRRS_State: DRRS_LOW_RR\n"); - vrefresh = drm_mode_vrefresh(panel->downclock_mode); - } else { - seq_printf(m, "DRRS_State: Unknown(%d)\n", - drrs->refresh_rate_type); - mutex_unlock(&drrs->mutex); - return; - } - seq_printf(m, "\t\tVrefresh: %d", vrefresh); + /* DRRS Supported */ + seq_printf(m, "\tDRRS Enabled: %s\n", + str_yes_no(crtc_state->has_drrs)); - seq_puts(m, "\n\t\t"); - mutex_unlock(&drrs->mutex); - } else { - /* DRRS not supported. Print the VBT parameter*/ - seq_puts(m, "\tDRRS Enabled : No"); - } - seq_puts(m, "\n"); -} + seq_printf(m, "\tDRRS Active: %s\n", + str_yes_no(intel_drrs_is_active(crtc))); -static int i915_drrs_status(struct seq_file *m, void *unused) -{ - struct drm_i915_private *dev_priv = node_to_i915(m->private); - struct drm_device *dev = &dev_priv->drm; - struct intel_crtc *crtc; - int active_crtc_cnt = 0; + seq_printf(m, "\tBusy_frontbuffer_bits: 0x%X\n", + crtc->drrs.busy_frontbuffer_bits); - drm_modeset_lock_all(dev); - for_each_intel_crtc(dev, crtc) { - if (crtc->base.state->active) { - active_crtc_cnt++; - seq_printf(m, "\nCRTC %d: ", active_crtc_cnt); + seq_printf(m, "\tDRRS refresh rate: %s\n", + crtc->drrs.refresh_rate == DRRS_REFRESH_RATE_LOW ? + "low" : "high"); - drrs_status_per_crtc(m, dev, crtc); - } + mutex_unlock(&crtc->drrs.mutex); } - drm_modeset_unlock_all(dev); - - if (!active_crtc_cnt) - seq_puts(m, "No active crtc found\n"); return 0; } @@ -1259,7 +1145,7 @@ static int i915_lpsp_status(struct seq_file *m, void *unused) return 0; } - seq_printf(m, "LPSP: %s\n", enableddisabled(lpsp_enabled)); + seq_printf(m, "LPSP: %s\n", str_enabled_disabled(lpsp_enabled)); return 0; } @@ -1740,7 +1626,7 @@ static int i915_hpd_storm_ctl_show(struct seq_file *m, void *data) seq_printf(m, "Threshold: %d\n", hotplug->hpd_storm_threshold); seq_printf(m, "Detected: %s\n", - yesno(delayed_work_pending(&hotplug->reenable_work))); + str_yes_no(delayed_work_pending(&hotplug->reenable_work))); return 0; } @@ -1814,7 +1700,7 @@ static int i915_hpd_short_storm_ctl_show(struct seq_file *m, void *data) struct drm_i915_private *dev_priv = m->private; seq_printf(m, "Enabled: %s\n", - yesno(dev_priv->hotplug.hpd_short_storm_enabled)); + str_yes_no(dev_priv->hotplug.hpd_short_storm_enabled)); return 0; } @@ -1888,13 +1774,8 @@ static int i915_drrs_ctl_set(void *data, u64 val) struct drm_device *dev = &dev_priv->drm; struct intel_crtc *crtc; - if (DISPLAY_VER(dev_priv) < 7) - return -ENODEV; - for_each_intel_crtc(dev, crtc) { - struct drm_connector_list_iter conn_iter; struct intel_crtc_state *crtc_state; - struct drm_connector *connector; struct drm_crtc_commit *commit; int ret; @@ -1915,30 +1796,13 @@ static int i915_drrs_ctl_set(void *data, u64 val) goto out; } - drm_connector_list_iter_begin(dev, &conn_iter); - drm_for_each_connector_iter(connector, &conn_iter) { - struct intel_encoder *encoder; - struct intel_dp *intel_dp; - - if (!(crtc_state->uapi.connector_mask & - drm_connector_mask(connector))) - continue; - - encoder = intel_attached_encoder(to_intel_connector(connector)); - if (encoder->type != INTEL_OUTPUT_EDP) - continue; - - drm_dbg(&dev_priv->drm, - "Manually %sabling DRRS. %llu\n", - val ? "en" : "dis", val); + drm_dbg(&dev_priv->drm, + "Manually %sactivating DRRS\n", val ? "" : "de"); - intel_dp = enc_to_intel_dp(encoder); - if (val) - intel_drrs_enable(intel_dp, crtc_state); - else - intel_drrs_disable(intel_dp, crtc_state); - } - drm_connector_list_iter_end(&conn_iter); + if (val) + intel_drrs_activate(crtc_state); + else + intel_drrs_deactivate(crtc_state); out: drm_modeset_unlock(&crtc->base.mutex); @@ -2020,7 +1884,6 @@ static const struct drm_info_list intel_display_debugfs_list[] = { {"i915_gem_framebuffer", i915_gem_framebuffer_info, 0}, {"i915_edp_psr_status", i915_edp_psr_status, 0}, {"i915_power_domain_info", i915_power_domain_info, 0}, - {"i915_dmc_info", i915_dmc_info, 0}, {"i915_display_info", i915_display_info, 0}, {"i915_shared_dplls_info", i915_shared_dplls_info, 0}, {"i915_dp_mst_info", i915_dp_mst_info, 0}, @@ -2064,6 +1927,7 @@ void intel_display_debugfs_register(struct drm_i915_private *i915) ARRAY_SIZE(intel_display_debugfs_list), minor->debugfs_root, minor); + intel_dmc_debugfs_register(i915); intel_fbc_debugfs_register(i915); } @@ -2209,14 +2073,14 @@ static int i915_dsc_fec_support_show(struct seq_file *m, void *data) intel_dp = intel_attached_dp(to_intel_connector(connector)); crtc_state = to_intel_crtc_state(crtc->state); seq_printf(m, "DSC_Enabled: %s\n", - yesno(crtc_state->dsc.compression_enable)); + str_yes_no(crtc_state->dsc.compression_enable)); seq_printf(m, "DSC_Sink_Support: %s\n", - yesno(drm_dp_sink_supports_dsc(intel_dp->dsc_dpcd))); + str_yes_no(drm_dp_sink_supports_dsc(intel_dp->dsc_dpcd))); seq_printf(m, "Force_DSC_Enable: %s\n", - yesno(intel_dp->force_dsc_en)); + str_yes_no(intel_dp->force_dsc_en)); if (!intel_dp_is_edp(intel_dp)) seq_printf(m, "FEC_Sink_Support: %s\n", - yesno(drm_dp_sink_supports_fec(intel_dp->fec_capable))); + str_yes_no(drm_dp_sink_supports_fec(intel_dp->fec_capable))); } while (try_again); drm_modeset_drop_locks(&ctx); diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index 9ebae7ac3235..6a5695008f7c 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -3,6 +3,8 @@ * Copyright © 2019 Intel Corporation */ +#include <linux/string_helpers.h> + #include "i915_drv.h" #include "i915_irq.h" #include "intel_cdclk.h" @@ -11,6 +13,7 @@ #include "intel_crt.h" #include "intel_de.h" #include "intel_display_power.h" +#include "intel_display_power_well.h" #include "intel_display_types.h" #include "intel_dmc.h" #include "intel_dpio_phy.h" @@ -26,101 +29,6 @@ #include "intel_vga.h" #include "vlv_sideband.h" -struct i915_power_well_ops { - /* - * Synchronize the well's hw state to match the current sw state, for - * example enable/disable it based on the current refcount. Called - * during driver init and resume time, possibly after first calling - * the enable/disable handlers. - */ - void (*sync_hw)(struct drm_i915_private *dev_priv, - struct i915_power_well *power_well); - /* - * Enable the well and resources that depend on it (for example - * interrupts located on the well). Called after the 0->1 refcount - * transition. - */ - void (*enable)(struct drm_i915_private *dev_priv, - struct i915_power_well *power_well); - /* - * Disable the well and resources that depend on it. Called after - * the 1->0 refcount transition. - */ - void (*disable)(struct drm_i915_private *dev_priv, - struct i915_power_well *power_well); - /* Returns the hw enabled state. */ - bool (*is_enabled)(struct drm_i915_private *dev_priv, - struct i915_power_well *power_well); -}; - -struct i915_power_well_regs { - i915_reg_t bios; - i915_reg_t driver; - i915_reg_t kvmr; - i915_reg_t debug; -}; - -/* Power well structure for haswell */ -struct i915_power_well_desc { - const char *name; - bool always_on; - u64 domains; - /* unique identifier for this power well */ - enum i915_power_well_id id; - /* - * Arbitraty data associated with this power well. Platform and power - * well specific. - */ - union { - struct { - /* - * request/status flag index in the PUNIT power well - * control/status registers. - */ - u8 idx; - } vlv; - struct { - enum dpio_phy phy; - } bxt; - struct { - const struct i915_power_well_regs *regs; - /* - * request/status flag index in the power well - * constrol/status registers. - */ - u8 idx; - /* Mask of pipes whose IRQ logic is backed by the pw */ - u8 irq_pipe_mask; - /* - * Instead of waiting for the status bit to ack enables, - * just wait a specific amount of time and then consider - * the well enabled. - */ - u16 fixed_enable_delay; - /* The pw is backing the VGA functionality */ - bool has_vga:1; - bool has_fuses:1; - /* - * The pw is for an ICL+ TypeC PHY port in - * Thunderbolt mode. - */ - bool is_tc_tbt:1; - } hsw; - }; - const struct i915_power_well_ops *ops; -}; - -struct i915_power_well { - const struct i915_power_well_desc *desc; - /* power well enable/disable usage count */ - int count; - /* cached hw enabled state */ - bool hw_enabled; -}; - -bool intel_display_power_well_is_enabled(struct drm_i915_private *dev_priv, - enum i915_power_well_id power_well_id); - const char * intel_display_power_domain_str(enum intel_display_power_domain domain) { @@ -153,12 +61,12 @@ intel_display_power_domain_str(enum intel_display_power_domain domain) return "TRANSCODER_D"; case POWER_DOMAIN_TRANSCODER_EDP: return "TRANSCODER_EDP"; - case POWER_DOMAIN_TRANSCODER_VDSC_PW2: - return "TRANSCODER_VDSC_PW2"; case POWER_DOMAIN_TRANSCODER_DSI_A: return "TRANSCODER_DSI_A"; case POWER_DOMAIN_TRANSCODER_DSI_C: return "TRANSCODER_DSI_C"; + case POWER_DOMAIN_TRANSCODER_VDSC_PW2: + return "TRANSCODER_VDSC_PW2"; case POWER_DOMAIN_PORT_DDI_A_LANES: return "PORT_DDI_A_LANES"; case POWER_DOMAIN_PORT_DDI_B_LANES: @@ -259,40 +167,6 @@ intel_display_power_domain_str(enum intel_display_power_domain domain) } } -static void intel_power_well_enable(struct drm_i915_private *dev_priv, - struct i915_power_well *power_well) -{ - drm_dbg_kms(&dev_priv->drm, "enabling %s\n", power_well->desc->name); - power_well->desc->ops->enable(dev_priv, power_well); - power_well->hw_enabled = true; -} - -static void intel_power_well_disable(struct drm_i915_private *dev_priv, - struct i915_power_well *power_well) -{ - drm_dbg_kms(&dev_priv->drm, "disabling %s\n", power_well->desc->name); - power_well->hw_enabled = false; - power_well->desc->ops->disable(dev_priv, power_well); -} - -static void intel_power_well_get(struct drm_i915_private *dev_priv, - struct i915_power_well *power_well) -{ - if (!power_well->count++) - intel_power_well_enable(dev_priv, power_well); -} - -static void intel_power_well_put(struct drm_i915_private *dev_priv, - struct i915_power_well *power_well) -{ - drm_WARN(&dev_priv->drm, !power_well->count, - "Use count on power well %s is already zero", - power_well->desc->name); - - if (!--power_well->count) - intel_power_well_disable(dev_priv, power_well); -} - /** * __intel_display_power_is_enabled - unlocked check for a power domain * @dev_priv: i915 device instance @@ -317,10 +191,10 @@ bool __intel_display_power_is_enabled(struct drm_i915_private *dev_priv, is_enabled = true; for_each_power_domain_well_reverse(dev_priv, power_well, BIT_ULL(domain)) { - if (power_well->desc->always_on) + if (intel_power_well_is_always_on(power_well)) continue; - if (!power_well->hw_enabled) { + if (!intel_power_well_is_enabled_cached(power_well)) { is_enabled = false; break; } @@ -438,7 +312,7 @@ static void hsw_wait_for_power_well_enable(struct drm_i915_private *dev_priv, struct i915_power_well *power_well, bool timeout_expected) { - const struct i915_power_well_regs *regs = power_well->desc->hsw.regs; + const struct i915_power_well_regs *regs = power_well->desc->ops->regs; int pw_idx = power_well->desc->hsw.idx; int enable_delay = power_well->desc->hsw.fixed_enable_delay; @@ -456,7 +330,7 @@ static void hsw_wait_for_power_well_enable(struct drm_i915_private *dev_priv, if (intel_de_wait_for_set(dev_priv, regs->driver, HSW_PWR_WELL_CTL_STATE(pw_idx), 1)) { drm_dbg_kms(&dev_priv->drm, "%s power well enable timeout\n", - power_well->desc->name); + intel_power_well_name(power_well)); drm_WARN_ON(&dev_priv->drm, !timeout_expected); @@ -482,7 +356,7 @@ static u32 hsw_power_well_requesters(struct drm_i915_private *dev_priv, static void hsw_wait_for_power_well_disable(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { - const struct i915_power_well_regs *regs = power_well->desc->hsw.regs; + const struct i915_power_well_regs *regs = power_well->desc->ops->regs; int pw_idx = power_well->desc->hsw.idx; bool disabled; u32 reqs; @@ -504,7 +378,7 @@ static void hsw_wait_for_power_well_disable(struct drm_i915_private *dev_priv, drm_dbg_kms(&dev_priv->drm, "%s forced on (bios:%d driver:%d kvmr:%d debug:%d)\n", - power_well->desc->name, + intel_power_well_name(power_well), !!(reqs & 1), !!(reqs & 2), !!(reqs & 4), !!(reqs & 8)); } @@ -520,7 +394,7 @@ static void gen9_wait_for_power_well_fuses(struct drm_i915_private *dev_priv, static void hsw_power_well_enable(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { - const struct i915_power_well_regs *regs = power_well->desc->hsw.regs; + const struct i915_power_well_regs *regs = power_well->desc->ops->regs; int pw_idx = power_well->desc->hsw.idx; u32 val; @@ -567,7 +441,7 @@ static void hsw_power_well_enable(struct drm_i915_private *dev_priv, static void hsw_power_well_disable(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { - const struct i915_power_well_regs *regs = power_well->desc->hsw.regs; + const struct i915_power_well_regs *regs = power_well->desc->ops->regs; int pw_idx = power_well->desc->hsw.idx; u32 val; @@ -584,7 +458,7 @@ static void icl_combo_phy_aux_power_well_enable(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { - const struct i915_power_well_regs *regs = power_well->desc->hsw.regs; + const struct i915_power_well_regs *regs = power_well->desc->ops->regs; int pw_idx = power_well->desc->hsw.idx; enum phy phy = icl_aux_pw_to_phy(dev_priv, power_well); u32 val; @@ -616,7 +490,7 @@ static void icl_combo_phy_aux_power_well_disable(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { - const struct i915_power_well_regs *regs = power_well->desc->hsw.regs; + const struct i915_power_well_regs *regs = power_well->desc->ops->regs; int pw_idx = power_well->desc->hsw.idx; enum phy phy = icl_aux_pw_to_phy(dev_priv, power_well); u32 val; @@ -636,28 +510,10 @@ icl_combo_phy_aux_power_well_disable(struct drm_i915_private *dev_priv, #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM) -static u64 async_put_domains_mask(struct i915_power_domains *power_domains); - -static int power_well_async_ref_count(struct drm_i915_private *dev_priv, - struct i915_power_well *power_well) -{ - int refs = hweight64(power_well->desc->domains & - async_put_domains_mask(&dev_priv->power_domains)); - - drm_WARN_ON(&dev_priv->drm, refs > power_well->count); - - return refs; -} - static void icl_tc_port_assert_ref_held(struct drm_i915_private *dev_priv, struct i915_power_well *power_well, struct intel_digital_port *dig_port) { - /* Bypass the check if all references are released asynchronously */ - if (power_well_async_ref_count(dev_priv, power_well) == - power_well->count) - return; - if (drm_WARN_ON(&dev_priv->drm, !dig_port)) return; @@ -706,7 +562,7 @@ icl_tc_phy_aux_power_well_enable(struct drm_i915_private *dev_priv, { enum aux_ch aux_ch = icl_aux_pw_to_ch(power_well); struct intel_digital_port *dig_port = aux_ch_to_digital_port(dev_priv, aux_ch); - const struct i915_power_well_regs *regs = power_well->desc->hsw.regs; + const struct i915_power_well_regs *regs = power_well->desc->ops->regs; bool is_tbt = power_well->desc->hsw.is_tc_tbt; bool timeout_expected; u32 val; @@ -749,18 +605,6 @@ icl_tc_phy_aux_power_well_enable(struct drm_i915_private *dev_priv, } static void -icl_tc_phy_aux_power_well_disable(struct drm_i915_private *dev_priv, - struct i915_power_well *power_well) -{ - enum aux_ch aux_ch = icl_aux_pw_to_ch(power_well); - struct intel_digital_port *dig_port = aux_ch_to_digital_port(dev_priv, aux_ch); - - icl_tc_port_assert_ref_held(dev_priv, power_well, dig_port); - - hsw_power_well_disable(dev_priv, power_well); -} - -static void icl_aux_power_well_enable(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { @@ -782,7 +626,7 @@ icl_aux_power_well_disable(struct drm_i915_private *dev_priv, enum phy phy = icl_aux_pw_to_phy(dev_priv, power_well); if (intel_phy_is_tc(dev_priv, phy)) - return icl_tc_phy_aux_power_well_disable(dev_priv, power_well); + return hsw_power_well_disable(dev_priv, power_well); else if (IS_ICELAKE(dev_priv)) return icl_combo_phy_aux_power_well_disable(dev_priv, power_well); @@ -798,7 +642,7 @@ icl_aux_power_well_disable(struct drm_i915_private *dev_priv, static bool hsw_power_well_enabled(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { - const struct i915_power_well_regs *regs = power_well->desc->hsw.regs; + const struct i915_power_well_regs *regs = power_well->desc->ops->regs; enum i915_power_well_id id = power_well->desc->id; int pw_idx = power_well->desc->hsw.idx; u32 mask = HSW_PWR_WELL_CTL_REQ(pw_idx) | @@ -1061,41 +905,6 @@ static void bxt_disable_dc9(struct drm_i915_private *dev_priv) intel_pps_unlock_regs_wa(dev_priv); } -static void assert_dmc_loaded(struct drm_i915_private *dev_priv) -{ - drm_WARN_ONCE(&dev_priv->drm, - !intel_de_read(dev_priv, - DMC_PROGRAM(dev_priv->dmc.dmc_info[DMC_FW_MAIN].start_mmioaddr, 0)), - "DMC program storage start is NULL\n"); - drm_WARN_ONCE(&dev_priv->drm, !intel_de_read(dev_priv, DMC_SSP_BASE), - "DMC SSP Base Not fine\n"); - drm_WARN_ONCE(&dev_priv->drm, !intel_de_read(dev_priv, DMC_HTP_SKL), - "DMC HTP Not fine\n"); -} - -static struct i915_power_well * -lookup_power_well(struct drm_i915_private *dev_priv, - enum i915_power_well_id power_well_id) -{ - struct i915_power_well *power_well; - - for_each_power_well(dev_priv, power_well) - if (power_well->desc->id == power_well_id) - return power_well; - - /* - * It's not feasible to add error checking code to the callers since - * this condition really shouldn't happen and it doesn't even make sense - * to abort things like display initialization sequences. Just return - * the first power well and hope the WARN gets reported so we can fix - * our driver. - */ - drm_WARN(&dev_priv->drm, 1, - "Power well %d not defined for this platform\n", - power_well_id); - return &dev_priv->power_domains.power_wells[0]; -} - /** * intel_display_power_set_target_dc_state - Set target dc state. * @dev_priv: i915 device @@ -1123,19 +932,18 @@ void intel_display_power_set_target_dc_state(struct drm_i915_private *dev_priv, if (state == dev_priv->dmc.target_dc_state) goto unlock; - dc_off_enabled = power_well->desc->ops->is_enabled(dev_priv, - power_well); + dc_off_enabled = intel_power_well_is_enabled(dev_priv, power_well); /* * If DC off power well is disabled, need to enable and disable the * DC off power well to effect target DC state. */ if (!dc_off_enabled) - power_well->desc->ops->enable(dev_priv, power_well); + intel_power_well_enable(dev_priv, power_well); dev_priv->dmc.target_dc_state = state; if (!dc_off_enabled) - power_well->desc->ops->disable(dev_priv, power_well); + intel_power_well_disable(dev_priv, power_well); unlock: mutex_unlock(&power_domains->lock); @@ -1208,7 +1016,7 @@ static void skl_enable_dc6(struct drm_i915_private *dev_priv) static void hsw_power_well_sync_hw(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { - const struct i915_power_well_regs *regs = power_well->desc->hsw.regs; + const struct i915_power_well_regs *regs = power_well->desc->ops->regs; int pw_idx = power_well->desc->hsw.idx; u32 mask = HSW_PWR_WELL_CTL_REQ(pw_idx); u32 bios_req = intel_de_read(dev_priv, regs->bios); @@ -1246,17 +1054,17 @@ static void bxt_verify_ddi_phy_power_wells(struct drm_i915_private *dev_priv) struct i915_power_well *power_well; power_well = lookup_power_well(dev_priv, BXT_DISP_PW_DPIO_CMN_A); - if (power_well->count > 0) + if (intel_power_well_refcount(power_well) > 0) bxt_ddi_phy_verify_state(dev_priv, power_well->desc->bxt.phy); power_well = lookup_power_well(dev_priv, VLV_DISP_PW_DPIO_CMN_BC); - if (power_well->count > 0) + if (intel_power_well_refcount(power_well) > 0) bxt_ddi_phy_verify_state(dev_priv, power_well->desc->bxt.phy); if (IS_GEMINILAKE(dev_priv)) { power_well = lookup_power_well(dev_priv, GLK_DISP_PW_DPIO_CMN_C); - if (power_well->count > 0) + if (intel_power_well_refcount(power_well) > 0) bxt_ddi_phy_verify_state(dev_priv, power_well->desc->bxt.phy); } @@ -1382,7 +1190,7 @@ static bool i830_pipes_power_well_enabled(struct drm_i915_private *dev_priv, static void i830_pipes_power_well_sync_hw(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { - if (power_well->count > 0) + if (intel_power_well_refcount(power_well) > 0) i830_pipes_power_well_enable(dev_priv, power_well); else i830_pipes_power_well_disable(dev_priv, power_well); @@ -1655,7 +1463,7 @@ static void assert_chv_phy_status(struct drm_i915_private *dev_priv) PHY_STATUS_SPLINE_LDO(DPIO_PHY1, DPIO_CH0, 0) | PHY_STATUS_SPLINE_LDO(DPIO_PHY1, DPIO_CH0, 1)); - if (cmn_bc->desc->ops->is_enabled(dev_priv, cmn_bc)) { + if (intel_power_well_is_enabled(dev_priv, cmn_bc)) { phy_status |= PHY_POWERGOOD(DPIO_PHY0); /* this assumes override is only used to enable lanes */ @@ -1696,7 +1504,7 @@ static void assert_chv_phy_status(struct drm_i915_private *dev_priv) phy_status |= PHY_STATUS_SPLINE_LDO(DPIO_PHY0, DPIO_CH1, 1); } - if (cmn_d->desc->ops->is_enabled(dev_priv, cmn_d)) { + if (intel_power_well_is_enabled(dev_priv, cmn_d)) { phy_status |= PHY_POWERGOOD(DPIO_PHY1); /* this assumes override is only used to enable lanes */ @@ -3280,7 +3088,15 @@ static const struct i915_power_well_desc i830_power_wells[] = { }, }; +static const struct i915_power_well_regs hsw_power_well_regs = { + .bios = HSW_PWR_WELL_CTL1, + .driver = HSW_PWR_WELL_CTL2, + .kvmr = HSW_PWR_WELL_CTL3, + .debug = HSW_PWR_WELL_CTL4, +}; + static const struct i915_power_well_ops hsw_power_well_ops = { + .regs = &hsw_power_well_regs, .sync_hw = hsw_power_well_sync_hw, .enable = hsw_power_well_enable, .disable = hsw_power_well_disable, @@ -3301,13 +3117,6 @@ static const struct i915_power_well_ops bxt_dpio_cmn_power_well_ops = { .is_enabled = bxt_dpio_cmn_power_well_enabled, }; -static const struct i915_power_well_regs hsw_power_well_regs = { - .bios = HSW_PWR_WELL_CTL1, - .driver = HSW_PWR_WELL_CTL2, - .kvmr = HSW_PWR_WELL_CTL3, - .debug = HSW_PWR_WELL_CTL4, -}; - static const struct i915_power_well_desc hsw_power_wells[] = { { .name = "always-on", @@ -3322,7 +3131,6 @@ static const struct i915_power_well_desc hsw_power_wells[] = { .ops = &hsw_power_well_ops, .id = HSW_DISP_PW_GLOBAL, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = HSW_PW_CTL_IDX_GLOBAL, .hsw.has_vga = true, }, @@ -3343,7 +3151,6 @@ static const struct i915_power_well_desc bdw_power_wells[] = { .ops = &hsw_power_well_ops, .id = HSW_DISP_PW_GLOBAL, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = HSW_PW_CTL_IDX_GLOBAL, .hsw.irq_pipe_mask = BIT(PIPE_B) | BIT(PIPE_C), .hsw.has_vga = true, @@ -3487,18 +3294,6 @@ static const struct i915_power_well_desc chv_power_wells[] = { }, }; -bool intel_display_power_well_is_enabled(struct drm_i915_private *dev_priv, - enum i915_power_well_id power_well_id) -{ - struct i915_power_well *power_well; - bool ret; - - power_well = lookup_power_well(dev_priv, power_well_id); - ret = power_well->desc->ops->is_enabled(dev_priv, power_well); - - return ret; -} - static const struct i915_power_well_desc skl_power_wells[] = { { .name = "always-on", @@ -3515,7 +3310,6 @@ static const struct i915_power_well_desc skl_power_wells[] = { .ops = &hsw_power_well_ops, .id = SKL_DISP_PW_1, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = SKL_PW_CTL_IDX_PW_1, .hsw.has_fuses = true, }, @@ -3528,7 +3322,6 @@ static const struct i915_power_well_desc skl_power_wells[] = { .ops = &hsw_power_well_ops, .id = SKL_DISP_PW_MISC_IO, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = SKL_PW_CTL_IDX_MISC_IO, }, }, @@ -3544,7 +3337,6 @@ static const struct i915_power_well_desc skl_power_wells[] = { .ops = &hsw_power_well_ops, .id = SKL_DISP_PW_2, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = SKL_PW_CTL_IDX_PW_2, .hsw.irq_pipe_mask = BIT(PIPE_B) | BIT(PIPE_C), .hsw.has_vga = true, @@ -3557,7 +3349,6 @@ static const struct i915_power_well_desc skl_power_wells[] = { .ops = &hsw_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = SKL_PW_CTL_IDX_DDI_A_E, }, }, @@ -3567,7 +3358,6 @@ static const struct i915_power_well_desc skl_power_wells[] = { .ops = &hsw_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = SKL_PW_CTL_IDX_DDI_B, }, }, @@ -3577,7 +3367,6 @@ static const struct i915_power_well_desc skl_power_wells[] = { .ops = &hsw_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = SKL_PW_CTL_IDX_DDI_C, }, }, @@ -3587,7 +3376,6 @@ static const struct i915_power_well_desc skl_power_wells[] = { .ops = &hsw_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = SKL_PW_CTL_IDX_DDI_D, }, }, @@ -3609,7 +3397,6 @@ static const struct i915_power_well_desc bxt_power_wells[] = { .ops = &hsw_power_well_ops, .id = SKL_DISP_PW_1, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = SKL_PW_CTL_IDX_PW_1, .hsw.has_fuses = true, }, @@ -3626,7 +3413,6 @@ static const struct i915_power_well_desc bxt_power_wells[] = { .ops = &hsw_power_well_ops, .id = SKL_DISP_PW_2, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = SKL_PW_CTL_IDX_PW_2, .hsw.irq_pipe_mask = BIT(PIPE_B) | BIT(PIPE_C), .hsw.has_vga = true, @@ -3669,7 +3455,6 @@ static const struct i915_power_well_desc glk_power_wells[] = { .ops = &hsw_power_well_ops, .id = SKL_DISP_PW_1, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = SKL_PW_CTL_IDX_PW_1, .hsw.has_fuses = true, }, @@ -3686,7 +3471,6 @@ static const struct i915_power_well_desc glk_power_wells[] = { .ops = &hsw_power_well_ops, .id = SKL_DISP_PW_2, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = SKL_PW_CTL_IDX_PW_2, .hsw.irq_pipe_mask = BIT(PIPE_B) | BIT(PIPE_C), .hsw.has_vga = true, @@ -3726,7 +3510,6 @@ static const struct i915_power_well_desc glk_power_wells[] = { .ops = &hsw_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = GLK_PW_CTL_IDX_AUX_A, }, }, @@ -3736,7 +3519,6 @@ static const struct i915_power_well_desc glk_power_wells[] = { .ops = &hsw_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = GLK_PW_CTL_IDX_AUX_B, }, }, @@ -3746,7 +3528,6 @@ static const struct i915_power_well_desc glk_power_wells[] = { .ops = &hsw_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = GLK_PW_CTL_IDX_AUX_C, }, }, @@ -3756,7 +3537,6 @@ static const struct i915_power_well_desc glk_power_wells[] = { .ops = &hsw_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = GLK_PW_CTL_IDX_DDI_A, }, }, @@ -3766,7 +3546,6 @@ static const struct i915_power_well_desc glk_power_wells[] = { .ops = &hsw_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = SKL_PW_CTL_IDX_DDI_B, }, }, @@ -3776,31 +3555,39 @@ static const struct i915_power_well_desc glk_power_wells[] = { .ops = &hsw_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = SKL_PW_CTL_IDX_DDI_C, }, }, }; +static const struct i915_power_well_regs icl_aux_power_well_regs = { + .bios = ICL_PWR_WELL_CTL_AUX1, + .driver = ICL_PWR_WELL_CTL_AUX2, + .debug = ICL_PWR_WELL_CTL_AUX4, +}; + static const struct i915_power_well_ops icl_aux_power_well_ops = { + .regs = &icl_aux_power_well_regs, .sync_hw = hsw_power_well_sync_hw, .enable = icl_aux_power_well_enable, .disable = icl_aux_power_well_disable, .is_enabled = hsw_power_well_enabled, }; -static const struct i915_power_well_regs icl_aux_power_well_regs = { - .bios = ICL_PWR_WELL_CTL_AUX1, - .driver = ICL_PWR_WELL_CTL_AUX2, - .debug = ICL_PWR_WELL_CTL_AUX4, -}; - static const struct i915_power_well_regs icl_ddi_power_well_regs = { .bios = ICL_PWR_WELL_CTL_DDI1, .driver = ICL_PWR_WELL_CTL_DDI2, .debug = ICL_PWR_WELL_CTL_DDI4, }; +static const struct i915_power_well_ops icl_ddi_power_well_ops = { + .regs = &icl_ddi_power_well_regs, + .sync_hw = hsw_power_well_sync_hw, + .enable = hsw_power_well_enable, + .disable = hsw_power_well_disable, + .is_enabled = hsw_power_well_enabled, +}; + static const struct i915_power_well_desc icl_power_wells[] = { { .name = "always-on", @@ -3817,7 +3604,6 @@ static const struct i915_power_well_desc icl_power_wells[] = { .ops = &hsw_power_well_ops, .id = SKL_DISP_PW_1, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_PW_1, .hsw.has_fuses = true, }, @@ -3834,7 +3620,6 @@ static const struct i915_power_well_desc icl_power_wells[] = { .ops = &hsw_power_well_ops, .id = SKL_DISP_PW_2, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_PW_2, .hsw.has_fuses = true, }, @@ -3845,7 +3630,6 @@ static const struct i915_power_well_desc icl_power_wells[] = { .ops = &hsw_power_well_ops, .id = ICL_DISP_PW_3, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_PW_3, .hsw.irq_pipe_mask = BIT(PIPE_B), .hsw.has_vga = true, @@ -3855,60 +3639,54 @@ static const struct i915_power_well_desc icl_power_wells[] = { { .name = "DDI A IO", .domains = ICL_DDI_IO_A_POWER_DOMAINS, - .ops = &hsw_power_well_ops, + .ops = &icl_ddi_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_ddi_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_DDI_A, }, }, { .name = "DDI B IO", .domains = ICL_DDI_IO_B_POWER_DOMAINS, - .ops = &hsw_power_well_ops, + .ops = &icl_ddi_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_ddi_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_DDI_B, }, }, { .name = "DDI C IO", .domains = ICL_DDI_IO_C_POWER_DOMAINS, - .ops = &hsw_power_well_ops, + .ops = &icl_ddi_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_ddi_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_DDI_C, }, }, { .name = "DDI D IO", .domains = ICL_DDI_IO_D_POWER_DOMAINS, - .ops = &hsw_power_well_ops, + .ops = &icl_ddi_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_ddi_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_DDI_D, }, }, { .name = "DDI E IO", .domains = ICL_DDI_IO_E_POWER_DOMAINS, - .ops = &hsw_power_well_ops, + .ops = &icl_ddi_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_ddi_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_DDI_E, }, }, { .name = "DDI F IO", .domains = ICL_DDI_IO_F_POWER_DOMAINS, - .ops = &hsw_power_well_ops, + .ops = &icl_ddi_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_ddi_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_DDI_F, }, }, @@ -3918,7 +3696,6 @@ static const struct i915_power_well_desc icl_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_AUX_A, }, }, @@ -3928,7 +3705,6 @@ static const struct i915_power_well_desc icl_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_AUX_B, }, }, @@ -3938,7 +3714,6 @@ static const struct i915_power_well_desc icl_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_AUX_C, .hsw.is_tc_tbt = false, }, @@ -3949,7 +3724,6 @@ static const struct i915_power_well_desc icl_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_AUX_D, .hsw.is_tc_tbt = false, }, @@ -3960,7 +3734,6 @@ static const struct i915_power_well_desc icl_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_AUX_E, .hsw.is_tc_tbt = false, }, @@ -3971,7 +3744,6 @@ static const struct i915_power_well_desc icl_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_AUX_F, .hsw.is_tc_tbt = false, }, @@ -3982,7 +3754,6 @@ static const struct i915_power_well_desc icl_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_AUX_TBT1, .hsw.is_tc_tbt = true, }, @@ -3993,7 +3764,6 @@ static const struct i915_power_well_desc icl_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_AUX_TBT2, .hsw.is_tc_tbt = true, }, @@ -4004,7 +3774,6 @@ static const struct i915_power_well_desc icl_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_AUX_TBT3, .hsw.is_tc_tbt = true, }, @@ -4015,7 +3784,6 @@ static const struct i915_power_well_desc icl_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_AUX_TBT4, .hsw.is_tc_tbt = true, }, @@ -4026,7 +3794,6 @@ static const struct i915_power_well_desc icl_power_wells[] = { .ops = &hsw_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_PW_4, .hsw.has_fuses = true, .hsw.irq_pipe_mask = BIT(PIPE_C), @@ -4094,7 +3861,7 @@ static void tgl_tc_cold_off_power_well_sync_hw(struct drm_i915_private *i915, struct i915_power_well *power_well) { - if (power_well->count > 0) + if (intel_power_well_refcount(power_well) > 0) tgl_tc_cold_off_power_well_enable(i915, power_well); else tgl_tc_cold_off_power_well_disable(i915, power_well); @@ -4108,7 +3875,7 @@ tgl_tc_cold_off_power_well_is_enabled(struct drm_i915_private *dev_priv, * Not the correctly implementation but there is no way to just read it * from PCODE, so returning count to avoid state mismatch errors */ - return power_well->count; + return intel_power_well_refcount(power_well); } static const struct i915_power_well_ops tgl_tc_cold_off_ops = { @@ -4134,7 +3901,6 @@ static const struct i915_power_well_desc tgl_power_wells[] = { .ops = &hsw_power_well_ops, .id = SKL_DISP_PW_1, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_PW_1, .hsw.has_fuses = true, }, @@ -4151,7 +3917,6 @@ static const struct i915_power_well_desc tgl_power_wells[] = { .ops = &hsw_power_well_ops, .id = SKL_DISP_PW_2, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_PW_2, .hsw.has_fuses = true, }, @@ -4162,7 +3927,6 @@ static const struct i915_power_well_desc tgl_power_wells[] = { .ops = &hsw_power_well_ops, .id = ICL_DISP_PW_3, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_PW_3, .hsw.irq_pipe_mask = BIT(PIPE_B), .hsw.has_vga = true, @@ -4172,90 +3936,81 @@ static const struct i915_power_well_desc tgl_power_wells[] = { { .name = "DDI A IO", .domains = ICL_DDI_IO_A_POWER_DOMAINS, - .ops = &hsw_power_well_ops, + .ops = &icl_ddi_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_ddi_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_DDI_A, } }, { .name = "DDI B IO", .domains = ICL_DDI_IO_B_POWER_DOMAINS, - .ops = &hsw_power_well_ops, + .ops = &icl_ddi_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_ddi_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_DDI_B, } }, { .name = "DDI C IO", .domains = ICL_DDI_IO_C_POWER_DOMAINS, - .ops = &hsw_power_well_ops, + .ops = &icl_ddi_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_ddi_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_DDI_C, } }, { .name = "DDI IO TC1", .domains = TGL_DDI_IO_TC1_POWER_DOMAINS, - .ops = &hsw_power_well_ops, + .ops = &icl_ddi_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_ddi_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_DDI_TC1, }, }, { .name = "DDI IO TC2", .domains = TGL_DDI_IO_TC2_POWER_DOMAINS, - .ops = &hsw_power_well_ops, + .ops = &icl_ddi_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_ddi_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_DDI_TC2, }, }, { .name = "DDI IO TC3", .domains = TGL_DDI_IO_TC3_POWER_DOMAINS, - .ops = &hsw_power_well_ops, + .ops = &icl_ddi_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_ddi_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_DDI_TC3, }, }, { .name = "DDI IO TC4", .domains = TGL_DDI_IO_TC4_POWER_DOMAINS, - .ops = &hsw_power_well_ops, + .ops = &icl_ddi_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_ddi_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_DDI_TC4, }, }, { .name = "DDI IO TC5", .domains = TGL_DDI_IO_TC5_POWER_DOMAINS, - .ops = &hsw_power_well_ops, + .ops = &icl_ddi_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_ddi_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_DDI_TC5, }, }, { .name = "DDI IO TC6", .domains = TGL_DDI_IO_TC6_POWER_DOMAINS, - .ops = &hsw_power_well_ops, + .ops = &icl_ddi_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_ddi_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_DDI_TC6, }, }, @@ -4271,7 +4026,6 @@ static const struct i915_power_well_desc tgl_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_AUX_A, }, }, @@ -4281,7 +4035,6 @@ static const struct i915_power_well_desc tgl_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_AUX_B, }, }, @@ -4291,7 +4044,6 @@ static const struct i915_power_well_desc tgl_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_AUX_C, }, }, @@ -4301,7 +4053,6 @@ static const struct i915_power_well_desc tgl_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_AUX_TC1, .hsw.is_tc_tbt = false, }, @@ -4312,7 +4063,6 @@ static const struct i915_power_well_desc tgl_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_AUX_TC2, .hsw.is_tc_tbt = false, }, @@ -4323,7 +4073,6 @@ static const struct i915_power_well_desc tgl_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_AUX_TC3, .hsw.is_tc_tbt = false, }, @@ -4334,7 +4083,6 @@ static const struct i915_power_well_desc tgl_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_AUX_TC4, .hsw.is_tc_tbt = false, }, @@ -4345,7 +4093,6 @@ static const struct i915_power_well_desc tgl_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_AUX_TC5, .hsw.is_tc_tbt = false, }, @@ -4356,7 +4103,6 @@ static const struct i915_power_well_desc tgl_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_AUX_TC6, .hsw.is_tc_tbt = false, }, @@ -4367,7 +4113,6 @@ static const struct i915_power_well_desc tgl_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_AUX_TBT1, .hsw.is_tc_tbt = true, }, @@ -4378,7 +4123,6 @@ static const struct i915_power_well_desc tgl_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_AUX_TBT2, .hsw.is_tc_tbt = true, }, @@ -4389,7 +4133,6 @@ static const struct i915_power_well_desc tgl_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_AUX_TBT3, .hsw.is_tc_tbt = true, }, @@ -4400,7 +4143,6 @@ static const struct i915_power_well_desc tgl_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_AUX_TBT4, .hsw.is_tc_tbt = true, }, @@ -4411,7 +4153,6 @@ static const struct i915_power_well_desc tgl_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_AUX_TBT5, .hsw.is_tc_tbt = true, }, @@ -4422,7 +4163,6 @@ static const struct i915_power_well_desc tgl_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_AUX_TBT6, .hsw.is_tc_tbt = true, }, @@ -4433,7 +4173,6 @@ static const struct i915_power_well_desc tgl_power_wells[] = { .ops = &hsw_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_PW_4, .hsw.has_fuses = true, .hsw.irq_pipe_mask = BIT(PIPE_C), @@ -4445,7 +4184,6 @@ static const struct i915_power_well_desc tgl_power_wells[] = { .ops = &hsw_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_PW_5, .hsw.has_fuses = true, .hsw.irq_pipe_mask = BIT(PIPE_D), @@ -4469,7 +4207,6 @@ static const struct i915_power_well_desc rkl_power_wells[] = { .ops = &hsw_power_well_ops, .id = SKL_DISP_PW_1, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_PW_1, .hsw.has_fuses = true, }, @@ -4486,7 +4223,6 @@ static const struct i915_power_well_desc rkl_power_wells[] = { .ops = &hsw_power_well_ops, .id = ICL_DISP_PW_3, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_PW_3, .hsw.irq_pipe_mask = BIT(PIPE_B), .hsw.has_vga = true, @@ -4499,7 +4235,6 @@ static const struct i915_power_well_desc rkl_power_wells[] = { .ops = &hsw_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_PW_4, .hsw.has_fuses = true, .hsw.irq_pipe_mask = BIT(PIPE_C), @@ -4508,40 +4243,36 @@ static const struct i915_power_well_desc rkl_power_wells[] = { { .name = "DDI A IO", .domains = ICL_DDI_IO_A_POWER_DOMAINS, - .ops = &hsw_power_well_ops, + .ops = &icl_ddi_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_ddi_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_DDI_A, } }, { .name = "DDI B IO", .domains = ICL_DDI_IO_B_POWER_DOMAINS, - .ops = &hsw_power_well_ops, + .ops = &icl_ddi_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_ddi_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_DDI_B, } }, { .name = "DDI IO TC1", .domains = TGL_DDI_IO_TC1_POWER_DOMAINS, - .ops = &hsw_power_well_ops, + .ops = &icl_ddi_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_ddi_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_DDI_TC1, }, }, { .name = "DDI IO TC2", .domains = TGL_DDI_IO_TC2_POWER_DOMAINS, - .ops = &hsw_power_well_ops, + .ops = &icl_ddi_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_ddi_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_DDI_TC2, }, }, @@ -4551,7 +4282,6 @@ static const struct i915_power_well_desc rkl_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_AUX_A, }, }, @@ -4561,7 +4291,6 @@ static const struct i915_power_well_desc rkl_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_AUX_B, }, }, @@ -4571,7 +4300,6 @@ static const struct i915_power_well_desc rkl_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_AUX_TC1, }, }, @@ -4581,7 +4309,6 @@ static const struct i915_power_well_desc rkl_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_AUX_TC2, }, }, @@ -4603,7 +4330,6 @@ static const struct i915_power_well_desc dg1_power_wells[] = { .ops = &hsw_power_well_ops, .id = SKL_DISP_PW_1, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_PW_1, .hsw.has_fuses = true, }, @@ -4620,7 +4346,6 @@ static const struct i915_power_well_desc dg1_power_wells[] = { .ops = &hsw_power_well_ops, .id = SKL_DISP_PW_2, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_PW_2, .hsw.has_fuses = true, }, @@ -4631,7 +4356,6 @@ static const struct i915_power_well_desc dg1_power_wells[] = { .ops = &hsw_power_well_ops, .id = ICL_DISP_PW_3, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_PW_3, .hsw.irq_pipe_mask = BIT(PIPE_B), .hsw.has_vga = true, @@ -4641,40 +4365,36 @@ static const struct i915_power_well_desc dg1_power_wells[] = { { .name = "DDI A IO", .domains = ICL_DDI_IO_A_POWER_DOMAINS, - .ops = &hsw_power_well_ops, + .ops = &icl_ddi_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_ddi_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_DDI_A, } }, { .name = "DDI B IO", .domains = ICL_DDI_IO_B_POWER_DOMAINS, - .ops = &hsw_power_well_ops, + .ops = &icl_ddi_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_ddi_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_DDI_B, } }, { .name = "DDI IO TC1", .domains = TGL_DDI_IO_TC1_POWER_DOMAINS, - .ops = &hsw_power_well_ops, + .ops = &icl_ddi_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_ddi_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_DDI_TC1, }, }, { .name = "DDI IO TC2", .domains = TGL_DDI_IO_TC2_POWER_DOMAINS, - .ops = &hsw_power_well_ops, + .ops = &icl_ddi_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_ddi_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_DDI_TC2, }, }, @@ -4684,7 +4404,6 @@ static const struct i915_power_well_desc dg1_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_AUX_A, }, }, @@ -4694,7 +4413,6 @@ static const struct i915_power_well_desc dg1_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_AUX_B, }, }, @@ -4704,7 +4422,6 @@ static const struct i915_power_well_desc dg1_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_AUX_TC1, .hsw.is_tc_tbt = false, }, @@ -4715,7 +4432,6 @@ static const struct i915_power_well_desc dg1_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_AUX_TC2, .hsw.is_tc_tbt = false, }, @@ -4726,7 +4442,6 @@ static const struct i915_power_well_desc dg1_power_wells[] = { .ops = &hsw_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_PW_4, .hsw.has_fuses = true, .hsw.irq_pipe_mask = BIT(PIPE_C), @@ -4738,7 +4453,6 @@ static const struct i915_power_well_desc dg1_power_wells[] = { .ops = &hsw_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_PW_5, .hsw.has_fuses = true, .hsw.irq_pipe_mask = BIT(PIPE_D), @@ -4762,7 +4476,6 @@ static const struct i915_power_well_desc xelpd_power_wells[] = { .ops = &hsw_power_well_ops, .id = SKL_DISP_PW_1, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_PW_1, .hsw.has_fuses = true, }, @@ -4779,7 +4492,6 @@ static const struct i915_power_well_desc xelpd_power_wells[] = { .ops = &hsw_power_well_ops, .id = SKL_DISP_PW_2, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_PW_2, .hsw.has_vga = true, .hsw.has_fuses = true, @@ -4791,7 +4503,6 @@ static const struct i915_power_well_desc xelpd_power_wells[] = { .ops = &hsw_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = XELPD_PW_CTL_IDX_PW_A, .hsw.irq_pipe_mask = BIT(PIPE_A), .hsw.has_fuses = true, @@ -4803,7 +4514,6 @@ static const struct i915_power_well_desc xelpd_power_wells[] = { .ops = &hsw_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = XELPD_PW_CTL_IDX_PW_B, .hsw.irq_pipe_mask = BIT(PIPE_B), .hsw.has_fuses = true, @@ -4815,7 +4525,6 @@ static const struct i915_power_well_desc xelpd_power_wells[] = { .ops = &hsw_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = XELPD_PW_CTL_IDX_PW_C, .hsw.irq_pipe_mask = BIT(PIPE_C), .hsw.has_fuses = true, @@ -4827,7 +4536,6 @@ static const struct i915_power_well_desc xelpd_power_wells[] = { .ops = &hsw_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &hsw_power_well_regs, .hsw.idx = XELPD_PW_CTL_IDX_PW_D, .hsw.irq_pipe_mask = BIT(PIPE_D), .hsw.has_fuses = true, @@ -4836,90 +4544,81 @@ static const struct i915_power_well_desc xelpd_power_wells[] = { { .name = "DDI A IO", .domains = ICL_DDI_IO_A_POWER_DOMAINS, - .ops = &hsw_power_well_ops, + .ops = &icl_ddi_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_ddi_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_DDI_A, } }, { .name = "DDI B IO", .domains = ICL_DDI_IO_B_POWER_DOMAINS, - .ops = &hsw_power_well_ops, + .ops = &icl_ddi_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_ddi_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_DDI_B, } }, { .name = "DDI C IO", .domains = ICL_DDI_IO_C_POWER_DOMAINS, - .ops = &hsw_power_well_ops, + .ops = &icl_ddi_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_ddi_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_DDI_C, } }, { .name = "DDI IO D_XELPD", .domains = XELPD_DDI_IO_D_XELPD_POWER_DOMAINS, - .ops = &hsw_power_well_ops, + .ops = &icl_ddi_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_ddi_power_well_regs, .hsw.idx = XELPD_PW_CTL_IDX_DDI_D, } }, { .name = "DDI IO E_XELPD", .domains = XELPD_DDI_IO_E_XELPD_POWER_DOMAINS, - .ops = &hsw_power_well_ops, + .ops = &icl_ddi_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_ddi_power_well_regs, .hsw.idx = XELPD_PW_CTL_IDX_DDI_E, } }, { .name = "DDI IO TC1", .domains = XELPD_DDI_IO_TC1_POWER_DOMAINS, - .ops = &hsw_power_well_ops, + .ops = &icl_ddi_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_ddi_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_DDI_TC1, } }, { .name = "DDI IO TC2", .domains = XELPD_DDI_IO_TC2_POWER_DOMAINS, - .ops = &hsw_power_well_ops, + .ops = &icl_ddi_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_ddi_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_DDI_TC2, } }, { .name = "DDI IO TC3", .domains = XELPD_DDI_IO_TC3_POWER_DOMAINS, - .ops = &hsw_power_well_ops, + .ops = &icl_ddi_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_ddi_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_DDI_TC3, } }, { .name = "DDI IO TC4", .domains = XELPD_DDI_IO_TC4_POWER_DOMAINS, - .ops = &hsw_power_well_ops, + .ops = &icl_ddi_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_ddi_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_DDI_TC4, } }, @@ -4929,7 +4628,6 @@ static const struct i915_power_well_desc xelpd_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_AUX_A, .hsw.fixed_enable_delay = 600, }, @@ -4940,7 +4638,6 @@ static const struct i915_power_well_desc xelpd_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_AUX_B, .hsw.fixed_enable_delay = 600, }, @@ -4951,7 +4648,6 @@ static const struct i915_power_well_desc xelpd_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = ICL_PW_CTL_IDX_AUX_C, .hsw.fixed_enable_delay = 600, }, @@ -4962,7 +4658,6 @@ static const struct i915_power_well_desc xelpd_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = XELPD_PW_CTL_IDX_AUX_D, .hsw.fixed_enable_delay = 600, }, @@ -4973,7 +4668,6 @@ static const struct i915_power_well_desc xelpd_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = XELPD_PW_CTL_IDX_AUX_E, }, }, @@ -4983,7 +4677,6 @@ static const struct i915_power_well_desc xelpd_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_AUX_TC1, .hsw.fixed_enable_delay = 600, }, @@ -4994,7 +4687,6 @@ static const struct i915_power_well_desc xelpd_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_AUX_TC2, }, }, @@ -5004,7 +4696,6 @@ static const struct i915_power_well_desc xelpd_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_AUX_TC3, }, }, @@ -5014,7 +4705,6 @@ static const struct i915_power_well_desc xelpd_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_AUX_TC4, }, }, @@ -5024,7 +4714,6 @@ static const struct i915_power_well_desc xelpd_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_AUX_TBT1, .hsw.is_tc_tbt = true, }, @@ -5035,7 +4724,6 @@ static const struct i915_power_well_desc xelpd_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_AUX_TBT2, .hsw.is_tc_tbt = true, }, @@ -5046,7 +4734,6 @@ static const struct i915_power_well_desc xelpd_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_AUX_TBT3, .hsw.is_tc_tbt = true, }, @@ -5057,7 +4744,6 @@ static const struct i915_power_well_desc xelpd_power_wells[] = { .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { - .hsw.regs = &icl_aux_power_well_regs, .hsw.idx = TGL_PW_CTL_IDX_AUX_TBT4, .hsw.is_tc_tbt = true, }, @@ -5281,11 +4967,8 @@ static void intel_power_domains_sync_hw(struct drm_i915_private *dev_priv) struct i915_power_well *power_well; mutex_lock(&power_domains->lock); - for_each_power_well(dev_priv, power_well) { - power_well->desc->ops->sync_hw(dev_priv, power_well); - power_well->hw_enabled = - power_well->desc->ops->is_enabled(dev_priv, power_well); - } + for_each_power_well(dev_priv, power_well) + intel_power_well_sync_hw(dev_priv, power_well); mutex_unlock(&power_domains->lock); } @@ -5303,7 +4986,7 @@ static void gen9_dbuf_slice_set(struct drm_i915_private *dev_priv, state = intel_de_read(dev_priv, reg) & DBUF_POWER_STATE; drm_WARN(&dev_priv->drm, enable != state, "DBuf slice %d power %s timeout!\n", - slice, enabledisable(enable)); + slice, str_enable_disable(enable)); } void gen9_dbuf_slices_update(struct drm_i915_private *dev_priv, @@ -5692,7 +5375,7 @@ static void skl_display_core_init(struct drm_i915_private *dev_priv, gen9_dbuf_enable(dev_priv); - if (resume && intel_dmc_has_payload(dev_priv)) + if (resume) intel_dmc_load_program(dev_priv); } @@ -5759,7 +5442,7 @@ static void bxt_display_core_init(struct drm_i915_private *dev_priv, bool resume gen9_dbuf_enable(dev_priv); - if (resume && intel_dmc_has_payload(dev_priv)) + if (resume) intel_dmc_load_program(dev_priv); } @@ -5923,7 +5606,7 @@ static void icl_display_core_init(struct drm_i915_private *dev_priv, if (IS_DG2(dev_priv)) intel_snps_phy_wait_for_calibration(dev_priv); - if (resume && intel_dmc_has_payload(dev_priv)) + if (resume) intel_dmc_load_program(dev_priv); /* Wa_14011508470:tgl,dg1,rkl,adl-s,adl-p */ @@ -5998,7 +5681,7 @@ static void chv_phy_control_init(struct drm_i915_private *dev_priv) * override and set the lane powerdown bits accding to the * current lane status. */ - if (cmn_bc->desc->ops->is_enabled(dev_priv, cmn_bc)) { + if (intel_power_well_is_enabled(dev_priv, cmn_bc)) { u32 status = intel_de_read(dev_priv, DPLL(PIPE_A)); unsigned int mask; @@ -6029,7 +5712,7 @@ static void chv_phy_control_init(struct drm_i915_private *dev_priv) dev_priv->chv_phy_assert[DPIO_PHY0] = true; } - if (cmn_d->desc->ops->is_enabled(dev_priv, cmn_d)) { + if (intel_power_well_is_enabled(dev_priv, cmn_d)) { u32 status = intel_de_read(dev_priv, DPIO_PHY_STATUS); unsigned int mask; @@ -6065,15 +5748,15 @@ static void vlv_cmnlane_wa(struct drm_i915_private *dev_priv) lookup_power_well(dev_priv, VLV_DISP_PW_DISP2D); /* If the display might be already active skip this */ - if (cmn->desc->ops->is_enabled(dev_priv, cmn) && - disp2d->desc->ops->is_enabled(dev_priv, disp2d) && + if (intel_power_well_is_enabled(dev_priv, cmn) && + intel_power_well_is_enabled(dev_priv, disp2d) && intel_de_read(dev_priv, DPIO_CTL) & DPIO_CMNRST) return; drm_dbg_kms(&dev_priv->drm, "toggling display PHY side reset\n"); /* cmnlane needs DPLL registers */ - disp2d->desc->ops->enable(dev_priv, disp2d); + intel_power_well_enable(dev_priv, disp2d); /* * From VLV2A0_DP_eDP_HDMI_DPIO_driver_vbios_notes_11.docx: @@ -6082,7 +5765,7 @@ static void vlv_cmnlane_wa(struct drm_i915_private *dev_priv) * Simply ungating isn't enough to reset the PHY enough to get * ports and lanes running. */ - cmn->desc->ops->disable(dev_priv, cmn); + intel_power_well_disable(dev_priv, cmn); } static bool vlv_punit_is_power_gated(struct drm_i915_private *dev_priv, u32 reg0) @@ -6233,12 +5916,12 @@ void intel_power_domains_sanitize_state(struct drm_i915_private *i915) for_each_power_well_reverse(i915, power_well) { if (power_well->desc->always_on || power_well->count || - !power_well->desc->ops->is_enabled(i915, power_well)) + !intel_power_well_is_enabled(i915, power_well)) continue; drm_dbg_kms(&i915->drm, "BIOS left unused %s power well enabled, disabling it\n", - power_well->desc->name); + intel_power_well_name(power_well)); intel_power_well_disable(i915, power_well); } @@ -6377,9 +6060,9 @@ static void intel_power_domains_dump_info(struct drm_i915_private *i915) enum intel_display_power_domain domain; drm_dbg(&i915->drm, "%-25s %d\n", - power_well->desc->name, power_well->count); + intel_power_well_name(power_well), intel_power_well_refcount(power_well)); - for_each_power_domain(domain, power_well->desc->domains) + for_each_power_domain(domain, intel_power_well_domains(power_well)) drm_dbg(&i915->drm, " %-23s %d\n", intel_display_power_domain_str(domain), power_domains->domain_use_count[domain]); @@ -6412,23 +6095,25 @@ static void intel_power_domains_verify_state(struct drm_i915_private *i915) int domains_count; bool enabled; - enabled = power_well->desc->ops->is_enabled(i915, power_well); - if ((power_well->count || power_well->desc->always_on) != + enabled = intel_power_well_is_enabled(i915, power_well); + if ((intel_power_well_refcount(power_well) || + intel_power_well_is_always_on(power_well)) != enabled) drm_err(&i915->drm, "power well %s state mismatch (refcount %d/enabled %d)", - power_well->desc->name, - power_well->count, enabled); + intel_power_well_name(power_well), + intel_power_well_refcount(power_well), enabled); domains_count = 0; - for_each_power_domain(domain, power_well->desc->domains) + for_each_power_domain(domain, intel_power_well_domains(power_well)) domains_count += power_domains->domain_use_count[domain]; - if (power_well->count != domains_count) { + if (intel_power_well_refcount(power_well) != domains_count) { drm_err(&i915->drm, "power well %s refcount/domain refcount mismatch " "(refcount %d/domains refcount %d)\n", - power_well->desc->name, power_well->count, + intel_power_well_name(power_well), + intel_power_well_refcount(power_well), domains_count); dump_domain_info = true; } @@ -6533,10 +6218,10 @@ void intel_display_power_debug(struct drm_i915_private *i915, struct seq_file *m enum intel_display_power_domain power_domain; power_well = &power_domains->power_wells[i]; - seq_printf(m, "%-25s %d\n", power_well->desc->name, - power_well->count); + seq_printf(m, "%-25s %d\n", intel_power_well_name(power_well), + intel_power_well_refcount(power_well)); - for_each_power_domain(power_domain, power_well->desc->domains) + for_each_power_domain(power_domain, intel_power_well_domains(power_well)) seq_printf(m, " %-23s %d\n", intel_display_power_domain_str(power_domain), power_domains->domain_use_count[power_domain]); diff --git a/drivers/gpu/drm/i915/display/intel_display_power.h b/drivers/gpu/drm/i915/display/intel_display_power.h index f6d0e6e73c6d..ced384b0a165 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.h +++ b/drivers/gpu/drm/i915/display/intel_display_power.h @@ -14,6 +14,11 @@ struct drm_i915_private; struct i915_power_well; struct intel_encoder; +/* + * Keep the pipe, transcoder, port (DDI_LANES,DDI_IO,AUX) domain instances + * consecutive, so that the pipe,transcoder,port -> power domain macros + * work correctly. + */ enum intel_display_power_domain { POWER_DOMAIN_DISPLAY_CORE, POWER_DOMAIN_PIPE_A, @@ -29,10 +34,12 @@ enum intel_display_power_domain { POWER_DOMAIN_TRANSCODER_C, POWER_DOMAIN_TRANSCODER_D, POWER_DOMAIN_TRANSCODER_EDP, - /* VDSC/joining for eDP/DSI transcoder (ICL) or pipe A (TGL) */ - POWER_DOMAIN_TRANSCODER_VDSC_PW2, POWER_DOMAIN_TRANSCODER_DSI_A, POWER_DOMAIN_TRANSCODER_DSI_C, + + /* VDSC/joining for eDP/DSI transcoder (ICL) or pipe A (TGL) */ + POWER_DOMAIN_TRANSCODER_VDSC_PW2, + POWER_DOMAIN_PORT_DDI_A_LANES, POWER_DOMAIN_PORT_DDI_B_LANES, POWER_DOMAIN_PORT_DDI_C_LANES, @@ -125,30 +132,6 @@ enum intel_display_power_domain { POWER_DOMAIN_NUM, }; -/* - * i915_power_well_id: - * - * IDs used to look up power wells. Power wells accessed directly bypassing - * the power domains framework must be assigned a unique ID. The rest of power - * wells must be assigned DISP_PW_ID_NONE. - */ -enum i915_power_well_id { - DISP_PW_ID_NONE, - - VLV_DISP_PW_DISP2D, - BXT_DISP_PW_DPIO_CMN_A, - VLV_DISP_PW_DPIO_CMN_BC, - GLK_DISP_PW_DPIO_CMN_C, - CHV_DISP_PW_DPIO_CMN_D, - HSW_DISP_PW_GLOBAL, - SKL_DISP_PW_MISC_IO, - SKL_DISP_PW_1, - SKL_DISP_PW_2, - ICL_DISP_PW_3, - SKL_DISP_DC_OFF, - TGL_DISP_PW_TC_COLD_OFF, -}; - #define POWER_DOMAIN_PIPE(pipe) ((pipe) + POWER_DOMAIN_PIPE_A) #define POWER_DOMAIN_PIPE_PANEL_FITTER(pipe) \ ((pipe) + POWER_DOMAIN_PIPE_A_PANEL_FITTER) @@ -232,8 +215,6 @@ intel_display_power_domain_str(enum intel_display_power_domain domain); bool intel_display_power_is_enabled(struct drm_i915_private *dev_priv, enum intel_display_power_domain domain); -bool intel_display_power_well_is_enabled(struct drm_i915_private *dev_priv, - enum i915_power_well_id power_well_id); bool __intel_display_power_is_enabled(struct drm_i915_private *dev_priv, enum intel_display_power_domain domain); intel_wakeref_t intel_display_power_get(struct drm_i915_private *dev_priv, diff --git a/drivers/gpu/drm/i915/display/intel_display_power_well.c b/drivers/gpu/drm/i915/display/intel_display_power_well.c new file mode 100644 index 000000000000..2a0fb9d9c60f --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_display_power_well.c @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2022 Intel Corporation + */ + +#include "i915_drv.h" +#include "intel_display_power_well.h" + +struct i915_power_well * +lookup_power_well(struct drm_i915_private *i915, + enum i915_power_well_id power_well_id) +{ + struct i915_power_well *power_well; + + for_each_power_well(i915, power_well) + if (power_well->desc->id == power_well_id) + return power_well; + + /* + * It's not feasible to add error checking code to the callers since + * this condition really shouldn't happen and it doesn't even make sense + * to abort things like display initialization sequences. Just return + * the first power well and hope the WARN gets reported so we can fix + * our driver. + */ + drm_WARN(&i915->drm, 1, + "Power well %d not defined for this platform\n", + power_well_id); + return &i915->power_domains.power_wells[0]; +} + +void intel_power_well_enable(struct drm_i915_private *i915, + struct i915_power_well *power_well) +{ + drm_dbg_kms(&i915->drm, "enabling %s\n", power_well->desc->name); + power_well->desc->ops->enable(i915, power_well); + power_well->hw_enabled = true; +} + +void intel_power_well_disable(struct drm_i915_private *i915, + struct i915_power_well *power_well) +{ + drm_dbg_kms(&i915->drm, "disabling %s\n", power_well->desc->name); + power_well->hw_enabled = false; + power_well->desc->ops->disable(i915, power_well); +} + +void intel_power_well_sync_hw(struct drm_i915_private *i915, + struct i915_power_well *power_well) +{ + power_well->desc->ops->sync_hw(i915, power_well); + power_well->hw_enabled = + power_well->desc->ops->is_enabled(i915, power_well); +} + +void intel_power_well_get(struct drm_i915_private *i915, + struct i915_power_well *power_well) +{ + if (!power_well->count++) + intel_power_well_enable(i915, power_well); +} + +void intel_power_well_put(struct drm_i915_private *i915, + struct i915_power_well *power_well) +{ + drm_WARN(&i915->drm, !power_well->count, + "Use count on power well %s is already zero", + power_well->desc->name); + + if (!--power_well->count) + intel_power_well_disable(i915, power_well); +} + +bool intel_power_well_is_enabled(struct drm_i915_private *i915, + struct i915_power_well *power_well) +{ + return power_well->desc->ops->is_enabled(i915, power_well); +} + +bool intel_power_well_is_enabled_cached(struct i915_power_well *power_well) +{ + return power_well->hw_enabled; +} + +bool intel_display_power_well_is_enabled(struct drm_i915_private *dev_priv, + enum i915_power_well_id power_well_id) +{ + struct i915_power_well *power_well; + + power_well = lookup_power_well(dev_priv, power_well_id); + + return intel_power_well_is_enabled(dev_priv, power_well); +} + +bool intel_power_well_is_always_on(struct i915_power_well *power_well) +{ + return power_well->desc->always_on; +} + +const char *intel_power_well_name(struct i915_power_well *power_well) +{ + return power_well->desc->name; +} + +u64 intel_power_well_domains(struct i915_power_well *power_well) +{ + return power_well->desc->domains; +} + +int intel_power_well_refcount(struct i915_power_well *power_well) +{ + return power_well->count; +} diff --git a/drivers/gpu/drm/i915/display/intel_display_power_well.h b/drivers/gpu/drm/i915/display/intel_display_power_well.h new file mode 100644 index 000000000000..9a3756fdcf7f --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_display_power_well.h @@ -0,0 +1,153 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2022 Intel Corporation + */ +#ifndef __INTEL_DISPLAY_POWER_WELL_H__ +#define __INTEL_DISPLAY_POWER_WELL_H__ + +#include <linux/types.h> + +#include "intel_display.h" + +struct drm_i915_private; +struct i915_power_well; + +/* + * i915_power_well_id: + * + * IDs used to look up power wells. Power wells accessed directly bypassing + * the power domains framework must be assigned a unique ID. The rest of power + * wells must be assigned DISP_PW_ID_NONE. + */ +enum i915_power_well_id { + DISP_PW_ID_NONE, + + VLV_DISP_PW_DISP2D, + BXT_DISP_PW_DPIO_CMN_A, + VLV_DISP_PW_DPIO_CMN_BC, + GLK_DISP_PW_DPIO_CMN_C, + CHV_DISP_PW_DPIO_CMN_D, + HSW_DISP_PW_GLOBAL, + SKL_DISP_PW_MISC_IO, + SKL_DISP_PW_1, + SKL_DISP_PW_2, + ICL_DISP_PW_3, + SKL_DISP_DC_OFF, + TGL_DISP_PW_TC_COLD_OFF, +}; + +struct i915_power_well_regs { + i915_reg_t bios; + i915_reg_t driver; + i915_reg_t kvmr; + i915_reg_t debug; +}; + +struct i915_power_well_ops { + const struct i915_power_well_regs *regs; + /* + * Synchronize the well's hw state to match the current sw state, for + * example enable/disable it based on the current refcount. Called + * during driver init and resume time, possibly after first calling + * the enable/disable handlers. + */ + void (*sync_hw)(struct drm_i915_private *i915, + struct i915_power_well *power_well); + /* + * Enable the well and resources that depend on it (for example + * interrupts located on the well). Called after the 0->1 refcount + * transition. + */ + void (*enable)(struct drm_i915_private *i915, + struct i915_power_well *power_well); + /* + * Disable the well and resources that depend on it. Called after + * the 1->0 refcount transition. + */ + void (*disable)(struct drm_i915_private *i915, + struct i915_power_well *power_well); + /* Returns the hw enabled state. */ + bool (*is_enabled)(struct drm_i915_private *i915, + struct i915_power_well *power_well); +}; + +struct i915_power_well_desc { + const char *name; + bool always_on; + u64 domains; + /* unique identifier for this power well */ + enum i915_power_well_id id; + /* + * Arbitraty data associated with this power well. Platform and power + * well specific. + */ + union { + struct { + /* + * request/status flag index in the PUNIT power well + * control/status registers. + */ + u8 idx; + } vlv; + struct { + enum dpio_phy phy; + } bxt; + struct { + /* + * request/status flag index in the power well + * constrol/status registers. + */ + u8 idx; + /* Mask of pipes whose IRQ logic is backed by the pw */ + u8 irq_pipe_mask; + /* + * Instead of waiting for the status bit to ack enables, + * just wait a specific amount of time and then consider + * the well enabled. + */ + u16 fixed_enable_delay; + /* The pw is backing the VGA functionality */ + bool has_vga:1; + bool has_fuses:1; + /* + * The pw is for an ICL+ TypeC PHY port in + * Thunderbolt mode. + */ + bool is_tc_tbt:1; + } hsw; + }; + const struct i915_power_well_ops *ops; +}; + +struct i915_power_well { + const struct i915_power_well_desc *desc; + /* power well enable/disable usage count */ + int count; + /* cached hw enabled state */ + bool hw_enabled; +}; + +struct i915_power_well *lookup_power_well(struct drm_i915_private *i915, + enum i915_power_well_id id); + +void intel_power_well_enable(struct drm_i915_private *i915, + struct i915_power_well *power_well); +void intel_power_well_disable(struct drm_i915_private *i915, + struct i915_power_well *power_well); +void intel_power_well_sync_hw(struct drm_i915_private *i915, + struct i915_power_well *power_well); +void intel_power_well_get(struct drm_i915_private *i915, + struct i915_power_well *power_well); +void intel_power_well_put(struct drm_i915_private *i915, + struct i915_power_well *power_well); +bool intel_power_well_is_enabled(struct drm_i915_private *i915, + struct i915_power_well *power_well); +bool intel_power_well_is_enabled_cached(struct i915_power_well *power_well); +bool intel_display_power_well_is_enabled(struct drm_i915_private *dev_priv, + enum i915_power_well_id power_well_id); +bool intel_power_well_is_always_on(struct i915_power_well *power_well); +const char *intel_power_well_name(struct i915_power_well *power_well); +u64 intel_power_well_domains(struct i915_power_well *power_well); +int intel_power_well_refcount(struct i915_power_well *power_well); + +#endif diff --git a/drivers/gpu/drm/i915/display/intel_display_trace.h b/drivers/gpu/drm/i915/display/intel_display_trace.h index f05f0f9b5103..2dd5a4b7f5d8 100644 --- a/drivers/gpu/drm/i915/display/intel_display_trace.h +++ b/drivers/gpu/drm/i915/display/intel_display_trace.h @@ -9,6 +9,7 @@ #if !defined(__INTEL_DISPLAY_TRACE_H__) || defined(TRACE_HEADER_MULTI_READ) #define __INTEL_DISPLAY_TRACE_H__ +#include <linux/string_helpers.h> #include <linux/types.h> #include <linux/tracepoint.h> @@ -161,7 +162,7 @@ TRACE_EVENT(intel_memory_cxsr, ), TP_printk("%s->%s, pipe A: frame=%u, scanline=%u, pipe B: frame=%u, scanline=%u, pipe C: frame=%u, scanline=%u", - onoff(__entry->old), onoff(__entry->new), + str_on_off(__entry->old), str_on_off(__entry->new), __entry->frame[PIPE_A], __entry->scanline[PIPE_A], __entry->frame[PIPE_B], __entry->scanline[PIPE_B], __entry->frame[PIPE_C], __entry->scanline[PIPE_C]) @@ -210,9 +211,9 @@ TRACE_EVENT(g4x_wm, TP_printk("pipe %c, frame=%u, scanline=%u, wm %d/%d/%d, sr %s/%d/%d/%d, hpll %s/%d/%d/%d, fbc %s", pipe_name(__entry->pipe), __entry->frame, __entry->scanline, __entry->primary, __entry->sprite, __entry->cursor, - yesno(__entry->cxsr), __entry->sr_plane, __entry->sr_cursor, __entry->sr_fbc, - yesno(__entry->hpll), __entry->hpll_plane, __entry->hpll_cursor, __entry->hpll_fbc, - yesno(__entry->fbc)) + str_yes_no(__entry->cxsr), __entry->sr_plane, __entry->sr_cursor, __entry->sr_fbc, + str_yes_no(__entry->hpll), __entry->hpll_plane, __entry->hpll_cursor, __entry->hpll_fbc, + str_yes_no(__entry->fbc)) ); TRACE_EVENT(vlv_wm, diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 776b3e6662f2..cfd042117b10 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -280,8 +280,7 @@ struct intel_panel_bl_funcs { }; struct intel_panel { - struct drm_display_mode *fixed_mode; - struct drm_display_mode *downclock_mode; + struct list_head fixed_modes; /* backlight */ struct { @@ -847,8 +846,13 @@ struct intel_crtc_wm_state { /* gen9+ only needs 1-step wm programming */ struct skl_pipe_wm optimal; struct skl_ddb_entry ddb; + /* + * pre-icl: for packed/planar CbCr + * icl+: for everything + */ + struct skl_ddb_entry plane_ddb[I915_MAX_PLANES]; + /* pre-icl: for planar Y */ struct skl_ddb_entry plane_ddb_y[I915_MAX_PLANES]; - struct skl_ddb_entry plane_ddb_uv[I915_MAX_PLANES]; } skl; struct { @@ -954,7 +958,7 @@ struct intel_crtc_state { /* Pipe source size (ie. panel fitter input size) * All planes will be positioned inside this space, * and get clipped at the edges. */ - int pipe_src_w, pipe_src_h; + struct drm_rect pipe_src; /* * Pipe pixel rate, adjusted for @@ -1125,11 +1129,14 @@ struct intel_crtc_state { int min_cdclk[I915_MAX_PLANES]; + /* for packed/planar CbCr */ u32 data_rate[I915_MAX_PLANES]; + /* for planar Y */ + u32 data_rate_y[I915_MAX_PLANES]; - /* FIXME unify with data_rate[] */ - u64 plane_data_rate[I915_MAX_PLANES]; - u64 uv_plane_data_rate[I915_MAX_PLANES]; + /* FIXME unify with data_rate[]? */ + u64 rel_data_rate[I915_MAX_PLANES]; + u64 rel_data_rate_y[I915_MAX_PLANES]; /* Gamma mode programmed on the pipe */ u32 gamma_mode; @@ -1154,6 +1161,9 @@ struct intel_crtc_state { /* bitmask of planes that will be updated during the commit */ u8 update_planes; + u8 framestart_delay; /* 1-4 */ + u8 msa_timing_delay; /* 0-3 */ + struct { u32 enable; u32 gcp; @@ -1179,9 +1189,6 @@ struct intel_crtc_state { /* enable pipe csc? */ bool csc_enable; - /* enable pipe big joiner? */ - bool bigjoiner; - /* big joiner pipe bitmask */ u8 bigjoiner_pipes; @@ -1252,6 +1259,11 @@ enum intel_pipe_crc_source { INTEL_PIPE_CRC_SOURCE_MAX, }; +enum drrs_refresh_rate { + DRRS_REFRESH_RATE_HIGH, + DRRS_REFRESH_RATE_LOW, +}; + #define INTEL_PIPE_CRC_ENTRIES_NR 128 struct intel_pipe_crc { spinlock_t lock; @@ -1294,6 +1306,16 @@ struct intel_crtc { } active; } wm; + struct { + struct mutex mutex; + struct delayed_work work; + enum drrs_refresh_rate refresh_rate; + unsigned int frontbuffer_bits; + unsigned int busy_frontbuffer_bits; + enum transcoder cpu_transcoder; + struct intel_link_m_n m_n, m2_n2; + } drrs; + int scanline_offset; struct { @@ -1503,6 +1525,7 @@ struct intel_psr { bool colorimetry_support; bool psr2_enabled; bool psr2_sel_fetch_enabled; + bool psr2_sel_fetch_cff_enabled; bool req_psr2_sdp_prior_scanline; u8 sink_sync_latency; ktime_t last_entry_attempt; diff --git a/drivers/gpu/drm/i915/display/intel_dmc.c b/drivers/gpu/drm/i915/display/intel_dmc.c index 7616a3906b9e..257cf662f9f4 100644 --- a/drivers/gpu/drm/i915/display/intel_dmc.c +++ b/drivers/gpu/drm/i915/display/intel_dmc.c @@ -28,6 +28,7 @@ #include "i915_reg.h" #include "intel_de.h" #include "intel_dmc.h" +#include "intel_dmc_regs.h" /** * DOC: DMC Firmware Support @@ -37,6 +38,10 @@ * low-power state and comes back to normal. */ +#define DMC_VERSION(major, minor) ((major) << 16 | (minor)) +#define DMC_VERSION_MAJOR(version) ((version) >> 16) +#define DMC_VERSION_MINOR(version) ((version) & 0xffff) + #define DMC_PATH(platform, major, minor) \ "i915/" \ __stringify(platform) "_dmc_ver" \ @@ -47,8 +52,8 @@ #define DISPLAY_VER12_DMC_MAX_FW_SIZE ICL_DMC_MAX_FW_SIZE -#define ADLP_DMC_PATH DMC_PATH(adlp, 2, 14) -#define ADLP_DMC_VERSION_REQUIRED DMC_VERSION(2, 14) +#define ADLP_DMC_PATH DMC_PATH(adlp, 2, 16) +#define ADLP_DMC_VERSION_REQUIRED DMC_VERSION(2, 16) MODULE_FIRMWARE(ADLP_DMC_PATH); #define ADLS_DMC_PATH DMC_PATH(adls, 2, 01) @@ -276,17 +281,8 @@ void intel_dmc_load_program(struct drm_i915_private *dev_priv) struct intel_dmc *dmc = &dev_priv->dmc; u32 id, i; - if (!HAS_DMC(dev_priv)) { - drm_err(&dev_priv->drm, - "No DMC support available for this platform\n"); + if (!intel_dmc_has_payload(dev_priv)) return; - } - - if (!dev_priv->dmc.dmc_info[DMC_FW_MAIN].payload) { - drm_err(&dev_priv->drm, - "Tried to program CSR with empty payload\n"); - return; - } assert_rpm_wakelock_held(&dev_priv->runtime_pm); @@ -314,6 +310,17 @@ void intel_dmc_load_program(struct drm_i915_private *dev_priv) gen9_set_dc_state_debugmask(dev_priv); } +void assert_dmc_loaded(struct drm_i915_private *i915) +{ + drm_WARN_ONCE(&i915->drm, + !intel_de_read(i915, DMC_PROGRAM(i915->dmc.dmc_info[DMC_FW_MAIN].start_mmioaddr, 0)), + "DMC program storage start is NULL\n"); + drm_WARN_ONCE(&i915->drm, !intel_de_read(i915, DMC_SSP_BASE), + "DMC SSP Base Not fine\n"); + drm_WARN_ONCE(&i915->drm, !intel_de_read(i915, DMC_HTP_SKL), + "DMC HTP Not fine\n"); +} + static bool fw_info_matches_stepping(const struct intel_fw_info *fw_info, const struct stepping_info *si) { @@ -697,7 +704,7 @@ void intel_dmc_ucode_init(struct drm_i915_private *dev_priv) dmc->fw_path = RKL_DMC_PATH; dmc->required_version = RKL_DMC_VERSION_REQUIRED; dmc->max_fw_size = DISPLAY_VER12_DMC_MAX_FW_SIZE; - } else if (DISPLAY_VER(dev_priv) >= 12) { + } else if (IS_TIGERLAKE(dev_priv)) { dmc->fw_path = TGL_DMC_PATH; dmc->required_version = TGL_DMC_VERSION_REQUIRED; dmc->max_fw_size = DISPLAY_VER12_DMC_MAX_FW_SIZE; @@ -808,3 +815,101 @@ void intel_dmc_ucode_fini(struct drm_i915_private *dev_priv) for (id = 0; id < DMC_FW_MAX; id++) kfree(dev_priv->dmc.dmc_info[id].payload); } + +void intel_dmc_print_error_state(struct drm_i915_error_state_buf *m, + struct drm_i915_private *i915) +{ + struct intel_dmc *dmc = &i915->dmc; + + if (!HAS_DMC(i915)) + return; + + i915_error_printf(m, "DMC loaded: %s\n", + str_yes_no(intel_dmc_has_payload(i915))); + i915_error_printf(m, "DMC fw version: %d.%d\n", + DMC_VERSION_MAJOR(dmc->version), + DMC_VERSION_MINOR(dmc->version)); +} + +static int intel_dmc_debugfs_status_show(struct seq_file *m, void *unused) +{ + struct drm_i915_private *i915 = m->private; + intel_wakeref_t wakeref; + struct intel_dmc *dmc; + i915_reg_t dc5_reg, dc6_reg = INVALID_MMIO_REG; + + if (!HAS_DMC(i915)) + return -ENODEV; + + dmc = &i915->dmc; + + wakeref = intel_runtime_pm_get(&i915->runtime_pm); + + seq_printf(m, "fw loaded: %s\n", + str_yes_no(intel_dmc_has_payload(i915))); + seq_printf(m, "path: %s\n", dmc->fw_path); + seq_printf(m, "Pipe A fw support: %s\n", + str_yes_no(GRAPHICS_VER(i915) >= 12)); + seq_printf(m, "Pipe A fw loaded: %s\n", + str_yes_no(dmc->dmc_info[DMC_FW_PIPEA].payload)); + seq_printf(m, "Pipe B fw support: %s\n", + str_yes_no(IS_ALDERLAKE_P(i915))); + seq_printf(m, "Pipe B fw loaded: %s\n", + str_yes_no(dmc->dmc_info[DMC_FW_PIPEB].payload)); + + if (!intel_dmc_has_payload(i915)) + goto out; + + seq_printf(m, "version: %d.%d\n", DMC_VERSION_MAJOR(dmc->version), + DMC_VERSION_MINOR(dmc->version)); + + if (DISPLAY_VER(i915) >= 12) { + if (IS_DGFX(i915)) { + dc5_reg = DG1_DMC_DEBUG_DC5_COUNT; + } else { + dc5_reg = TGL_DMC_DEBUG_DC5_COUNT; + dc6_reg = TGL_DMC_DEBUG_DC6_COUNT; + } + + /* + * NOTE: DMC_DEBUG3 is a general purpose reg. + * According to B.Specs:49196 DMC f/w reuses DC5/6 counter + * reg for DC3CO debugging and validation, + * but TGL DMC f/w is using DMC_DEBUG3 reg for DC3CO counter. + */ + seq_printf(m, "DC3CO count: %d\n", + intel_de_read(i915, IS_DGFX(i915) ? + DG1_DMC_DEBUG3 : TGL_DMC_DEBUG3)); + } else { + dc5_reg = IS_BROXTON(i915) ? BXT_DMC_DC3_DC5_COUNT : + SKL_DMC_DC3_DC5_COUNT; + if (!IS_GEMINILAKE(i915) && !IS_BROXTON(i915)) + dc6_reg = SKL_DMC_DC5_DC6_COUNT; + } + + seq_printf(m, "DC3 -> DC5 count: %d\n", intel_de_read(i915, dc5_reg)); + if (i915_mmio_reg_valid(dc6_reg)) + seq_printf(m, "DC5 -> DC6 count: %d\n", + intel_de_read(i915, dc6_reg)); + +out: + seq_printf(m, "program base: 0x%08x\n", + intel_de_read(i915, DMC_PROGRAM(dmc->dmc_info[DMC_FW_MAIN].start_mmioaddr, 0))); + seq_printf(m, "ssp base: 0x%08x\n", + intel_de_read(i915, DMC_SSP_BASE)); + seq_printf(m, "htp: 0x%08x\n", intel_de_read(i915, DMC_HTP_SKL)); + + intel_runtime_pm_put(&i915->runtime_pm, wakeref); + + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(intel_dmc_debugfs_status); + +void intel_dmc_debugfs_register(struct drm_i915_private *i915) +{ + struct drm_minor *minor = i915->drm.primary; + + debugfs_create_file("i915_dmc_info", 0444, minor->debugfs_root, + i915, &intel_dmc_debugfs_status_fops); +} diff --git a/drivers/gpu/drm/i915/display/intel_dmc.h b/drivers/gpu/drm/i915/display/intel_dmc.h index 7c590309a3a9..41091aee3b47 100644 --- a/drivers/gpu/drm/i915/display/intel_dmc.h +++ b/drivers/gpu/drm/i915/display/intel_dmc.h @@ -10,12 +10,9 @@ #include "intel_wakeref.h" #include <linux/workqueue.h> +struct drm_i915_error_state_buf; struct drm_i915_private; -#define DMC_VERSION(major, minor) ((major) << 16 | (minor)) -#define DMC_VERSION_MAJOR(version) ((version) >> 16) -#define DMC_VERSION_MINOR(version) ((version) & 0xffff) - enum { DMC_FW_MAIN = 0, DMC_FW_PIPEA, @@ -54,5 +51,10 @@ void intel_dmc_ucode_fini(struct drm_i915_private *i915); void intel_dmc_ucode_suspend(struct drm_i915_private *i915); void intel_dmc_ucode_resume(struct drm_i915_private *i915); bool intel_dmc_has_payload(struct drm_i915_private *i915); +void intel_dmc_debugfs_register(struct drm_i915_private *i915); +void intel_dmc_print_error_state(struct drm_i915_error_state_buf *m, + struct drm_i915_private *i915); + +void assert_dmc_loaded(struct drm_i915_private *i915); #endif /* __INTEL_DMC_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_dmc_regs.h b/drivers/gpu/drm/i915/display/intel_dmc_regs.h new file mode 100644 index 000000000000..d65e698832eb --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_dmc_regs.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2022 Intel Corporation + */ + +#ifndef __INTEL_DMC_REGS_H__ +#define __INTEL_DMC_REGS_H__ + +#include "i915_reg_defs.h" + +#define DMC_PROGRAM(addr, i) _MMIO((addr) + (i) * 4) +#define DMC_SSP_BASE_ADDR_GEN9 0x00002FC0 +#define DMC_HTP_ADDR_SKL 0x00500034 +#define DMC_SSP_BASE _MMIO(0x8F074) +#define DMC_HTP_SKL _MMIO(0x8F004) +#define DMC_LAST_WRITE _MMIO(0x8F034) +#define DMC_LAST_WRITE_VALUE 0xc003b400 +#define DMC_MMIO_START_RANGE 0x80000 +#define DMC_MMIO_END_RANGE 0x8FFFF +#define SKL_DMC_DC3_DC5_COUNT _MMIO(0x80030) +#define SKL_DMC_DC5_DC6_COUNT _MMIO(0x8002C) +#define BXT_DMC_DC3_DC5_COUNT _MMIO(0x80038) +#define TGL_DMC_DEBUG_DC5_COUNT _MMIO(0x101084) +#define TGL_DMC_DEBUG_DC6_COUNT _MMIO(0x101088) +#define DG1_DMC_DEBUG_DC5_COUNT _MMIO(0x134154) + +#define TGL_DMC_DEBUG3 _MMIO(0x101090) +#define DG1_DMC_DEBUG3 _MMIO(0x13415c) + +#endif /* __INTEL_DMC_REGS_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index d667657e3606..d55acc4a028a 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -29,6 +29,7 @@ #include <linux/i2c.h> #include <linux/notifier.h> #include <linux/slab.h> +#include <linux/string_helpers.h> #include <linux/timekeeping.h> #include <linux/types.h> @@ -59,7 +60,6 @@ #include "intel_dp_mst.h" #include "intel_dpio_phy.h" #include "intel_dpll.h" -#include "intel_drrs.h" #include "intel_fifo_underrun.h" #include "intel_hdcp.h" #include "intel_hdmi.h" @@ -67,6 +67,7 @@ #include "intel_lspcon.h" #include "intel_lvds.h" #include "intel_panel.h" +#include "intel_pch_display.h" #include "intel_pps.h" #include "intel_psr.h" #include "intel_tc.h" @@ -386,23 +387,13 @@ static int dg2_max_source_rate(struct intel_dp *intel_dp) return intel_dp_is_edp(intel_dp) ? 810000 : 1350000; } -static bool is_low_voltage_sku(struct drm_i915_private *i915, enum phy phy) -{ - u32 voltage; - - voltage = intel_de_read(i915, ICL_PORT_COMP_DW3(phy)) & VOLTAGE_INFO_MASK; - - return voltage == VOLTAGE_INFO_0_85V; -} - static int icl_max_source_rate(struct intel_dp *intel_dp) { struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); enum phy phy = intel_port_to_phy(dev_priv, dig_port->base.port); - if (intel_phy_is_combo(dev_priv, phy) && - (is_low_voltage_sku(dev_priv, phy) || !intel_dp_is_edp(intel_dp))) + if (intel_phy_is_combo(dev_priv, phy) && !intel_dp_is_edp(intel_dp)) return 540000; return 810000; @@ -410,23 +401,7 @@ static int icl_max_source_rate(struct intel_dp *intel_dp) static int ehl_max_source_rate(struct intel_dp *intel_dp) { - struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); - struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); - enum phy phy = intel_port_to_phy(dev_priv, dig_port->base.port); - - if (intel_dp_is_edp(intel_dp) || is_low_voltage_sku(dev_priv, phy)) - return 540000; - - return 810000; -} - -static int dg1_max_source_rate(struct intel_dp *intel_dp) -{ - struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); - struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); - enum phy phy = intel_port_to_phy(i915, dig_port->base.port); - - if (intel_phy_is_combo(i915, phy) && is_low_voltage_sku(i915, phy)) + if (intel_dp_is_edp(intel_dp)) return 540000; return 810000; @@ -469,7 +444,7 @@ intel_dp_set_source_rates(struct intel_dp *intel_dp) max_rate = dg2_max_source_rate(intel_dp); else if (IS_ALDERLAKE_P(dev_priv) || IS_ALDERLAKE_S(dev_priv) || IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv)) - max_rate = dg1_max_source_rate(intel_dp); + max_rate = 810000; else if (IS_JSL_EHL(dev_priv)) max_rate = ehl_max_source_rate(intel_dp); else @@ -580,8 +555,9 @@ static bool intel_dp_can_link_train_fallback_for_edp(struct intel_dp *intel_dp, int link_rate, u8 lane_count) { + /* FIXME figure out what we actually want here */ const struct drm_display_mode *fixed_mode = - intel_dp->attached_connector->panel.fixed_mode; + intel_panel_preferred_fixed_mode(intel_dp->attached_connector); int mode_rate, max_rate; mode_rate = intel_dp_link_required(fixed_mode->clock, 18); @@ -783,14 +759,12 @@ static u8 intel_dp_dsc_get_slice_count(struct intel_dp *intel_dp, } static enum intel_output_format -intel_dp_output_format(struct drm_connector *connector, - const struct drm_display_mode *mode) +intel_dp_output_format(struct intel_connector *connector, + bool ycbcr_420_output) { - struct intel_dp *intel_dp = intel_attached_dp(to_intel_connector(connector)); - const struct drm_display_info *info = &connector->display_info; + struct intel_dp *intel_dp = intel_attached_dp(connector); - if (!connector->ycbcr_420_allowed || - !drm_mode_is_420_only(info, mode)) + if (!connector->base.ycbcr_420_allowed || !ycbcr_420_output) return INTEL_OUTPUT_FORMAT_RGB; if (intel_dp->dfp.rgb_to_ycbcr && @@ -825,11 +799,12 @@ static int intel_dp_output_bpp(enum intel_output_format output_format, int bpp) } static int -intel_dp_mode_min_output_bpp(struct drm_connector *connector, +intel_dp_mode_min_output_bpp(struct intel_connector *connector, const struct drm_display_mode *mode) { + const struct drm_display_info *info = &connector->base.display_info; enum intel_output_format output_format = - intel_dp_output_format(connector, mode); + intel_dp_output_format(connector, drm_mode_is_420_only(info, mode)); return intel_dp_output_bpp(output_format, intel_dp_min_bpp(output_format)); } @@ -853,6 +828,43 @@ static bool intel_dp_hdisplay_bad(struct drm_i915_private *dev_priv, return hdisplay == 4096 && !HAS_DDI(dev_priv); } +static int intel_dp_max_tmds_clock(struct intel_dp *intel_dp) +{ + struct intel_connector *connector = intel_dp->attached_connector; + const struct drm_display_info *info = &connector->base.display_info; + int max_tmds_clock = intel_dp->dfp.max_tmds_clock; + + /* Only consider the sink's max TMDS clock if we know this is a HDMI DFP */ + if (max_tmds_clock && info->max_tmds_clock) + max_tmds_clock = min(max_tmds_clock, info->max_tmds_clock); + + return max_tmds_clock; +} + +static enum drm_mode_status +intel_dp_tmds_clock_valid(struct intel_dp *intel_dp, + int clock, int bpc, bool ycbcr420_output, + bool respect_downstream_limits) +{ + int tmds_clock, min_tmds_clock, max_tmds_clock; + + if (!respect_downstream_limits) + return MODE_OK; + + tmds_clock = intel_hdmi_tmds_clock(clock, bpc, ycbcr420_output); + + min_tmds_clock = intel_dp->dfp.min_tmds_clock; + max_tmds_clock = intel_dp_max_tmds_clock(intel_dp); + + if (min_tmds_clock && tmds_clock < min_tmds_clock) + return MODE_CLOCK_LOW; + + if (max_tmds_clock && tmds_clock > max_tmds_clock) + return MODE_CLOCK_HIGH; + + return MODE_OK; +} + static enum drm_mode_status intel_dp_mode_valid_downstream(struct intel_connector *connector, const struct drm_display_mode *mode, @@ -860,13 +872,14 @@ intel_dp_mode_valid_downstream(struct intel_connector *connector, { struct intel_dp *intel_dp = intel_attached_dp(connector); const struct drm_display_info *info = &connector->base.display_info; - int tmds_clock; + enum drm_mode_status status; + bool ycbcr_420_only; /* If PCON supports FRL MODE, check FRL bandwidth constraints */ if (intel_dp->dfp.pcon_max_frl_bw) { int target_bw; int max_frl_bw; - int bpp = intel_dp_mode_min_output_bpp(&connector->base, mode); + int bpp = intel_dp_mode_min_output_bpp(connector, mode); target_bw = bpp * target_clock; @@ -885,16 +898,23 @@ intel_dp_mode_valid_downstream(struct intel_connector *connector, target_clock > intel_dp->dfp.max_dotclock) return MODE_CLOCK_HIGH; + ycbcr_420_only = drm_mode_is_420_only(info, mode); + /* Assume 8bpc for the DP++/HDMI/DVI TMDS clock check */ - tmds_clock = intel_hdmi_tmds_clock(target_clock, 8, - drm_mode_is_420_only(info, mode)); + status = intel_dp_tmds_clock_valid(intel_dp, target_clock, + 8, ycbcr_420_only, true); - if (intel_dp->dfp.min_tmds_clock && - tmds_clock < intel_dp->dfp.min_tmds_clock) - return MODE_CLOCK_LOW; - if (intel_dp->dfp.max_tmds_clock && - tmds_clock > intel_dp->dfp.max_tmds_clock) - return MODE_CLOCK_HIGH; + if (status != MODE_OK) { + if (ycbcr_420_only || + !connector->base.ycbcr_420_allowed || + !drm_mode_is_420_also(info, mode)) + return status; + + status = intel_dp_tmds_clock_valid(intel_dp, target_clock, + 8, true, true); + if (status != MODE_OK) + return status; + } return MODE_OK; } @@ -911,13 +931,13 @@ static bool intel_dp_need_bigjoiner(struct intel_dp *intel_dp, } static enum drm_mode_status -intel_dp_mode_valid(struct drm_connector *connector, +intel_dp_mode_valid(struct drm_connector *_connector, struct drm_display_mode *mode) { - struct intel_dp *intel_dp = intel_attached_dp(to_intel_connector(connector)); - struct intel_connector *intel_connector = to_intel_connector(connector); - struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode; - struct drm_i915_private *dev_priv = to_i915(connector->dev); + struct intel_connector *connector = to_intel_connector(_connector); + struct intel_dp *intel_dp = intel_attached_dp(connector); + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + const struct drm_display_mode *fixed_mode; int target_clock = mode->clock; int max_rate, mode_rate, max_lanes, max_link_clock; int max_dotclk = dev_priv->max_dotclk_freq; @@ -932,8 +952,9 @@ intel_dp_mode_valid(struct drm_connector *connector, if (mode->flags & DRM_MODE_FLAG_DBLCLK) return MODE_H_ILLEGAL; + fixed_mode = intel_panel_fixed_mode(connector, mode); if (intel_dp_is_edp(intel_dp) && fixed_mode) { - status = intel_panel_mode_valid(intel_connector, mode); + status = intel_panel_mode_valid(connector, mode); if (status != MODE_OK) return status; @@ -1007,8 +1028,7 @@ intel_dp_mode_valid(struct drm_connector *connector, if (mode_rate > max_rate && !dsc) return MODE_CLOCK_HIGH; - status = intel_dp_mode_valid_downstream(intel_connector, - mode, target_clock); + status = intel_dp_mode_valid_downstream(connector, mode, target_clock); if (status != MODE_OK) return status; @@ -1130,44 +1150,50 @@ static bool intel_dp_supports_dsc(struct intel_dp *intel_dp, drm_dp_sink_supports_dsc(intel_dp->dsc_dpcd); } -static bool intel_dp_hdmi_ycbcr420(struct intel_dp *intel_dp, - const struct intel_crtc_state *crtc_state) +static bool intel_dp_is_ycbcr420(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state) { return crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420 || (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444 && intel_dp->dfp.ycbcr_444_to_420); } -static bool intel_dp_hdmi_tmds_clock_valid(struct intel_dp *intel_dp, - const struct intel_crtc_state *crtc_state, int bpc) +static int intel_dp_hdmi_compute_bpc(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state, + int bpc, bool respect_downstream_limits) { + bool ycbcr420_output = intel_dp_is_ycbcr420(intel_dp, crtc_state); int clock = crtc_state->hw.adjusted_mode.crtc_clock; - int tmds_clock = intel_hdmi_tmds_clock(clock, bpc, - intel_dp_hdmi_ycbcr420(intel_dp, crtc_state)); - if (intel_dp->dfp.min_tmds_clock && - tmds_clock < intel_dp->dfp.min_tmds_clock) - return false; - - if (intel_dp->dfp.max_tmds_clock && - tmds_clock > intel_dp->dfp.max_tmds_clock) - return false; + /* + * Current bpc could already be below 8bpc due to + * FDI bandwidth constraints or other limits. + * HDMI minimum is 8bpc however. + */ + bpc = max(bpc, 8); - return true; -} + /* + * We will never exceed downstream TMDS clock limits while + * attempting deep color. If the user insists on forcing an + * out of spec mode they will have to be satisfied with 8bpc. + */ + if (!respect_downstream_limits) + bpc = 8; -static bool intel_dp_hdmi_bpc_possible(struct intel_dp *intel_dp, - const struct intel_crtc_state *crtc_state, - int bpc) -{ + for (; bpc >= 8; bpc -= 2) { + if (intel_hdmi_bpc_possible(crtc_state, bpc, + intel_dp->has_hdmi_sink, ycbcr420_output) && + intel_dp_tmds_clock_valid(intel_dp, clock, bpc, ycbcr420_output, + respect_downstream_limits) == MODE_OK) + return bpc; + } - return intel_hdmi_bpc_possible(crtc_state, bpc, intel_dp->has_hdmi_sink, - intel_dp_hdmi_ycbcr420(intel_dp, crtc_state)) && - intel_dp_hdmi_tmds_clock_valid(intel_dp, crtc_state, bpc); + return -EINVAL; } static int intel_dp_max_bpp(struct intel_dp *intel_dp, - const struct intel_crtc_state *crtc_state) + const struct intel_crtc_state *crtc_state, + bool respect_downstream_limits) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); struct intel_connector *intel_connector = intel_dp->attached_connector; @@ -1179,10 +1205,14 @@ static int intel_dp_max_bpp(struct intel_dp *intel_dp, bpc = min_t(int, bpc, intel_dp->dfp.max_bpc); if (intel_dp->dfp.min_tmds_clock) { - for (; bpc >= 10; bpc -= 2) { - if (intel_dp_hdmi_bpc_possible(intel_dp, crtc_state, bpc)) - break; - } + int max_hdmi_bpc; + + max_hdmi_bpc = intel_dp_hdmi_compute_bpc(intel_dp, crtc_state, bpc, + respect_downstream_limits); + if (max_hdmi_bpc < 0) + return 0; + + bpc = min(bpc, max_hdmi_bpc); } bpp = bpc * 3; @@ -1424,13 +1454,13 @@ static int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, pipe_config->lane_count, adjusted_mode->crtc_clock, adjusted_mode->crtc_hdisplay, - pipe_config->bigjoiner, + pipe_config->bigjoiner_pipes, pipe_bpp); dsc_dp_slice_count = intel_dp_dsc_get_slice_count(intel_dp, adjusted_mode->crtc_clock, adjusted_mode->crtc_hdisplay, - pipe_config->bigjoiner); + pipe_config->bigjoiner_pipes); if (!dsc_max_output_bpp || !dsc_dp_slice_count) { drm_dbg_kms(&dev_priv->drm, "Compressed BPP/Slice Count not supported\n"); @@ -1464,7 +1494,7 @@ static int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, * then we need to use 2 VDSC instances. */ if (adjusted_mode->crtc_clock > dev_priv->max_cdclk_freq || - pipe_config->bigjoiner) { + pipe_config->bigjoiner_pipes) { if (pipe_config->dsc.slice_count < 2) { drm_dbg_kms(&dev_priv->drm, "Cannot split stream to use 2 VDSC instances\n"); @@ -1497,13 +1527,16 @@ static int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, static int intel_dp_compute_link_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, - struct drm_connector_state *conn_state) + struct drm_connector_state *conn_state, + bool respect_downstream_limits) { struct drm_i915_private *i915 = to_i915(encoder->base.dev); + struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc); const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; struct intel_dp *intel_dp = enc_to_intel_dp(encoder); struct link_config_limits limits; + bool joiner_needs_dsc = false; int ret; limits.min_rate = intel_dp_common_rate(intel_dp, 0); @@ -1513,7 +1546,7 @@ intel_dp_compute_link_config(struct intel_encoder *encoder, limits.max_lane_count = intel_dp_max_lane_count(intel_dp); limits.min_bpp = intel_dp_min_bpp(pipe_config->output_format); - limits.max_bpp = intel_dp_max_bpp(intel_dp, pipe_config); + limits.max_bpp = intel_dp_max_bpp(intel_dp, pipe_config, respect_downstream_limits); if (intel_dp->use_max_params) { /* @@ -1537,7 +1570,14 @@ intel_dp_compute_link_config(struct intel_encoder *encoder, if (intel_dp_need_bigjoiner(intel_dp, adjusted_mode->crtc_hdisplay, adjusted_mode->crtc_clock)) - pipe_config->bigjoiner = true; + pipe_config->bigjoiner_pipes = GENMASK(crtc->pipe + 1, crtc->pipe); + + /* + * Pipe joiner needs compression up to display 12 due to bandwidth + * limitation. DG2 onwards pipe joiner can be enabled without + * compression. + */ + joiner_needs_dsc = DISPLAY_VER(i915) < 13 && pipe_config->bigjoiner_pipes; /* * Optimize for slow and wide for everything, because there are some @@ -1545,13 +1585,10 @@ intel_dp_compute_link_config(struct intel_encoder *encoder, */ ret = intel_dp_compute_link_config_wide(intel_dp, pipe_config, &limits); - /* - * Pipe joiner needs compression upto display12 due to BW limitation. DG2 - * onwards pipe joiner can be enabled without compression. - */ - drm_dbg_kms(&i915->drm, "Force DSC en = %d\n", intel_dp->force_dsc_en); - if (ret || intel_dp->force_dsc_en || (DISPLAY_VER(i915) < 13 && - pipe_config->bigjoiner)) { + if (ret || joiner_needs_dsc || intel_dp->force_dsc_en) { + drm_dbg_kms(&i915->drm, "Try DSC (fallback=%s, joiner=%s, force=%s)\n", + str_yes_no(ret), str_yes_no(joiner_needs_dsc), + str_yes_no(intel_dp->force_dsc_en)); ret = intel_dp_dsc_compute_config(intel_dp, pipe_config, conn_state, &limits); if (ret < 0) @@ -1786,6 +1823,137 @@ intel_dp_compute_hdr_metadata_infoframe_sdp(struct intel_dp *intel_dp, intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_GAMUT_METADATA); } +static bool cpu_transcoder_has_drrs(struct drm_i915_private *i915, + enum transcoder cpu_transcoder) +{ + /* M1/N1 is double buffered */ + if (DISPLAY_VER(i915) >= 9 || IS_BROADWELL(i915)) + return true; + + return intel_cpu_transcoder_has_m2_n2(i915, cpu_transcoder); +} + +static bool can_enable_drrs(struct intel_connector *connector, + const struct intel_crtc_state *pipe_config, + const struct drm_display_mode *downclock_mode) +{ + struct drm_i915_private *i915 = to_i915(connector->base.dev); + + if (pipe_config->vrr.enable) + return false; + + /* + * DRRS and PSR can't be enable together, so giving preference to PSR + * as it allows more power-savings by complete shutting down display, + * so to guarantee this, intel_drrs_compute_config() must be called + * after intel_psr_compute_config(). + */ + if (pipe_config->has_psr) + return false; + + /* FIXME missing FDI M2/N2 etc. */ + if (pipe_config->has_pch_encoder) + return false; + + if (!cpu_transcoder_has_drrs(i915, pipe_config->cpu_transcoder)) + return false; + + return downclock_mode && + intel_panel_drrs_type(connector) == DRRS_TYPE_SEAMLESS; +} + +static void +intel_dp_drrs_compute_config(struct intel_connector *connector, + struct intel_crtc_state *pipe_config, + int output_bpp, bool constant_n) +{ + struct drm_i915_private *i915 = to_i915(connector->base.dev); + const struct drm_display_mode *downclock_mode = + intel_panel_downclock_mode(connector, &pipe_config->hw.adjusted_mode); + int pixel_clock; + + if (!can_enable_drrs(connector, pipe_config, downclock_mode)) { + if (intel_cpu_transcoder_has_m2_n2(i915, pipe_config->cpu_transcoder)) + intel_zero_m_n(&pipe_config->dp_m2_n2); + return; + } + + if (IS_IRONLAKE(i915) || IS_SANDYBRIDGE(i915) || IS_IVYBRIDGE(i915)) + pipe_config->msa_timing_delay = i915->vbt.edp.drrs_msa_timing_delay; + + pipe_config->has_drrs = true; + + pixel_clock = downclock_mode->clock; + if (pipe_config->splitter.enable) + pixel_clock /= pipe_config->splitter.link_count; + + intel_link_compute_m_n(output_bpp, pipe_config->lane_count, pixel_clock, + pipe_config->port_clock, &pipe_config->dp_m2_n2, + constant_n, pipe_config->fec_enable); + + /* FIXME: abstract this better */ + if (pipe_config->splitter.enable) + pipe_config->dp_m2_n2.data_m *= pipe_config->splitter.link_count; +} + +static bool intel_dp_has_audio(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + const struct drm_connector_state *conn_state) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + const struct intel_digital_connector_state *intel_conn_state = + to_intel_digital_connector_state(conn_state); + + if (!intel_dp_port_has_audio(i915, encoder->port)) + return false; + + if (intel_conn_state->force_audio == HDMI_AUDIO_AUTO) + return intel_dp->has_audio; + else + return intel_conn_state->force_audio == HDMI_AUDIO_ON; +} + +static int +intel_dp_compute_output_format(struct intel_encoder *encoder, + struct intel_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + bool respect_downstream_limits) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + struct intel_connector *connector = intel_dp->attached_connector; + const struct drm_display_info *info = &connector->base.display_info; + const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; + bool ycbcr_420_only; + int ret; + + ycbcr_420_only = drm_mode_is_420_only(info, adjusted_mode); + + crtc_state->output_format = intel_dp_output_format(connector, ycbcr_420_only); + + if (ycbcr_420_only && !intel_dp_is_ycbcr420(intel_dp, crtc_state)) { + drm_dbg_kms(&i915->drm, + "YCbCr 4:2:0 mode but YCbCr 4:2:0 output not possible. Falling back to RGB.\n"); + crtc_state->output_format = INTEL_OUTPUT_FORMAT_RGB; + } + + ret = intel_dp_compute_link_config(encoder, crtc_state, conn_state, + respect_downstream_limits); + if (ret) { + if (intel_dp_is_ycbcr420(intel_dp, crtc_state) || + !connector->base.ycbcr_420_allowed || + !drm_mode_is_420_also(info, adjusted_mode)) + return ret; + + crtc_state->output_format = intel_dp_output_format(connector, true); + ret = intel_dp_compute_link_config(encoder, crtc_state, conn_state, + respect_downstream_limits); + } + + return ret; +} + int intel_dp_compute_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, @@ -1794,38 +1962,19 @@ intel_dp_compute_config(struct intel_encoder *encoder, struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - enum port port = encoder->port; - struct intel_connector *intel_connector = intel_dp->attached_connector; - struct intel_digital_connector_state *intel_conn_state = - to_intel_digital_connector_state(conn_state); + const struct drm_display_mode *fixed_mode; + struct intel_connector *connector = intel_dp->attached_connector; bool constant_n = drm_dp_has_quirk(&intel_dp->desc, DP_DPCD_QUIRK_CONSTANT_N); int ret = 0, output_bpp; - if (HAS_PCH_SPLIT(dev_priv) && !HAS_DDI(dev_priv) && port != PORT_A) + if (HAS_PCH_SPLIT(dev_priv) && !HAS_DDI(dev_priv) && encoder->port != PORT_A) pipe_config->has_pch_encoder = true; - pipe_config->output_format = intel_dp_output_format(&intel_connector->base, - adjusted_mode); - - if (pipe_config->output_format == INTEL_OUTPUT_FORMAT_YCBCR420) { - ret = intel_panel_fitting(pipe_config, conn_state); - if (ret) - return ret; - } - - if (!intel_dp_port_has_audio(dev_priv, port)) - pipe_config->has_audio = false; - else if (intel_conn_state->force_audio == HDMI_AUDIO_AUTO) - pipe_config->has_audio = intel_dp->has_audio; - else - pipe_config->has_audio = intel_conn_state->force_audio == HDMI_AUDIO_ON; - - if (intel_dp_is_edp(intel_dp) && intel_connector->panel.fixed_mode) { - ret = intel_panel_compute_config(intel_connector, adjusted_mode); - if (ret) - return ret; + pipe_config->has_audio = intel_dp_has_audio(encoder, pipe_config, conn_state); - ret = intel_panel_fitting(pipe_config, conn_state); + fixed_mode = intel_panel_fixed_mode(connector, adjusted_mode); + if (intel_dp_is_edp(intel_dp) && fixed_mode) { + ret = intel_panel_compute_config(connector, adjusted_mode); if (ret) return ret; } @@ -1843,10 +1992,23 @@ intel_dp_compute_config(struct intel_encoder *encoder, if (intel_dp_hdisplay_bad(dev_priv, adjusted_mode->crtc_hdisplay)) return -EINVAL; - ret = intel_dp_compute_link_config(encoder, pipe_config, conn_state); - if (ret < 0) + /* + * Try to respect downstream TMDS clock limits first, if + * that fails assume the user might know something we don't. + */ + ret = intel_dp_compute_output_format(encoder, pipe_config, conn_state, true); + if (ret) + ret = intel_dp_compute_output_format(encoder, pipe_config, conn_state, false); + if (ret) return ret; + if ((intel_dp_is_edp(intel_dp) && fixed_mode) || + pipe_config->output_format == INTEL_OUTPUT_FORMAT_YCBCR420) { + ret = intel_panel_fitting(pipe_config, conn_state); + if (ret) + return ret; + } + pipe_config->limited_color_range = intel_dp_limited_color_range(pipe_config, conn_state); @@ -1892,8 +2054,8 @@ intel_dp_compute_config(struct intel_encoder *encoder, intel_vrr_compute_config(pipe_config, conn_state); intel_psr_compute_config(intel_dp, pipe_config, conn_state); - intel_drrs_compute_config(intel_dp, pipe_config, output_bpp, - constant_n); + intel_dp_drrs_compute_config(connector, pipe_config, + output_bpp, constant_n); intel_dp_compute_vsc_sdp(intel_dp, pipe_config, conn_state); intel_dp_compute_hdr_metadata_infoframe_sdp(intel_dp, pipe_config, conn_state); @@ -1976,7 +2138,7 @@ void intel_dp_sink_set_decompression_state(struct intel_dp *intel_dp, if (ret < 0) drm_dbg_kms(&i915->drm, "Failed to %s sink decompression state\n", - enabledisable(enable)); + str_enable_disable(enable)); } static void @@ -2452,7 +2614,7 @@ void intel_dp_configure_protocol_converter(struct intel_dp *intel_dp, if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_PROTOCOL_CONVERTER_CONTROL_0, tmp) != 1) drm_dbg_kms(&i915->drm, "Failed to %s protocol converter HDMI mode\n", - enabledisable(intel_dp->has_hdmi_sink)); + str_enable_disable(intel_dp->has_hdmi_sink)); tmp = crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444 && intel_dp->dfp.ycbcr_444_to_420 ? DP_CONVERSION_TO_YCBCR420_ENABLE : 0; @@ -2461,45 +2623,15 @@ void intel_dp_configure_protocol_converter(struct intel_dp *intel_dp, DP_PROTOCOL_CONVERTER_CONTROL_1, tmp) != 1) drm_dbg_kms(&i915->drm, "Failed to %s protocol converter YCbCr 4:2:0 conversion mode\n", - enabledisable(intel_dp->dfp.ycbcr_444_to_420)); - - tmp = 0; - if (intel_dp->dfp.rgb_to_ycbcr) { - bool bt2020, bt709; + str_enable_disable(intel_dp->dfp.ycbcr_444_to_420)); - /* - * FIXME: Currently if userspace selects BT2020 or BT709, but PCON supports only - * RGB->YCbCr for BT601 colorspace, we go ahead with BT601, as default. - * - */ - tmp = DP_CONVERSION_BT601_RGB_YCBCR_ENABLE; - - bt2020 = drm_dp_downstream_rgb_to_ycbcr_conversion(intel_dp->dpcd, - intel_dp->downstream_ports, - DP_DS_HDMI_BT2020_RGB_YCBCR_CONV); - bt709 = drm_dp_downstream_rgb_to_ycbcr_conversion(intel_dp->dpcd, - intel_dp->downstream_ports, - DP_DS_HDMI_BT709_RGB_YCBCR_CONV); - switch (crtc_state->infoframes.vsc.colorimetry) { - case DP_COLORIMETRY_BT2020_RGB: - case DP_COLORIMETRY_BT2020_YCC: - if (bt2020) - tmp = DP_CONVERSION_BT2020_RGB_YCBCR_ENABLE; - break; - case DP_COLORIMETRY_BT709_YCC: - case DP_COLORIMETRY_XVYCC_709: - if (bt709) - tmp = DP_CONVERSION_BT709_RGB_YCBCR_ENABLE; - break; - default: - break; - } - } + tmp = intel_dp->dfp.rgb_to_ycbcr ? + DP_CONVERSION_BT709_RGB_YCBCR_ENABLE : 0; if (drm_dp_pcon_convert_rgb_to_ycbcr(&intel_dp->aux, tmp) < 0) drm_dbg_kms(&i915->drm, "Failed to %s protocol converter RGB->YCbCr conversion mode\n", - enabledisable(tmp)); + str_enable_disable(tmp)); } @@ -2572,9 +2704,9 @@ static void intel_edp_mso_mode_fixup(struct intel_connector *connector, drm_mode_set_name(mode); drm_dbg_kms(&i915->drm, - "[CONNECTOR:%d:%s] using generated MSO mode: ", - connector->base.base.id, connector->base.name); - drm_mode_debug_printmodeline(mode); + "[CONNECTOR:%d:%s] using generated MSO mode: " DRM_MODE_FMT "\n", + connector->base.base.id, connector->base.name, + DRM_MODE_ARG(mode)); } static void intel_edp_mso_init(struct intel_dp *intel_dp) @@ -2787,8 +2919,9 @@ intel_dp_configure_mst(struct intel_dp *intel_dp) drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s] MST support: port: %s, sink: %s, modparam: %s\n", encoder->base.base.id, encoder->base.name, - yesno(intel_dp_mst_source_support(intel_dp)), yesno(sink_can_mst), - yesno(i915->params.enable_dp_mst)); + str_yes_no(intel_dp_mst_source_support(intel_dp)), + str_yes_no(sink_can_mst), + str_yes_no(i915->params.enable_dp_mst)); if (!intel_dp_mst_source_support(intel_dp)) return; @@ -4347,9 +4480,7 @@ intel_dp_update_420(struct intel_dp *intel_dp) intel_dp->downstream_ports); rgb_to_ycbcr = drm_dp_downstream_rgb_to_ycbcr_conversion(intel_dp->dpcd, intel_dp->downstream_ports, - DP_DS_HDMI_BT601_RGB_YCBCR_CONV | - DP_DS_HDMI_BT709_RGB_YCBCR_CONV | - DP_DS_HDMI_BT2020_RGB_YCBCR_CONV); + DP_DS_HDMI_BT709_RGB_YCBCR_CONV); if (DISPLAY_VER(i915) >= 11) { /* Let PCON convert from RGB->YCbCr if possible */ @@ -4375,21 +4506,28 @@ intel_dp_update_420(struct intel_dp *intel_dp) drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] RGB->YcbCr conversion? %s, YCbCr 4:2:0 allowed? %s, YCbCr 4:4:4->4:2:0 conversion? %s\n", connector->base.base.id, connector->base.name, - yesno(intel_dp->dfp.rgb_to_ycbcr), - yesno(connector->base.ycbcr_420_allowed), - yesno(intel_dp->dfp.ycbcr_444_to_420)); + str_yes_no(intel_dp->dfp.rgb_to_ycbcr), + str_yes_no(connector->base.ycbcr_420_allowed), + str_yes_no(intel_dp->dfp.ycbcr_444_to_420)); } static void intel_dp_set_edid(struct intel_dp *intel_dp) { + struct drm_i915_private *i915 = dp_to_i915(intel_dp); struct intel_connector *connector = intel_dp->attached_connector; struct edid *edid; + bool vrr_capable; intel_dp_unset_edid(intel_dp); edid = intel_dp_get_edid(intel_dp); connector->detect_edid = edid; + vrr_capable = intel_vrr_is_capable(&connector->base); + drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] VRR capable: %s\n", + connector->base.base.id, connector->base.name, str_yes_no(vrr_capable)); + drm_connector_set_vrr_capable_property(&connector->base, vrr_capable); + intel_dp_update_dfp(intel_dp, edid); intel_dp_update_420(intel_dp); @@ -4422,6 +4560,9 @@ intel_dp_unset_edid(struct intel_dp *intel_dp) intel_dp->dfp.ycbcr_444_to_420 = false; connector->base.ycbcr_420_allowed = false; + + drm_connector_set_vrr_capable_property(&connector->base, + false); } static int @@ -4572,26 +4713,12 @@ static int intel_dp_get_modes(struct drm_connector *connector) int num_modes = 0; edid = intel_connector->detect_edid; - if (edid) { + if (edid) num_modes = intel_connector_update_modes(connector, edid); - if (intel_vrr_is_capable(connector)) - drm_connector_set_vrr_capable_property(connector, - true); - } - /* Also add fixed mode, which may or may not be present in EDID */ - if (intel_dp_is_edp(intel_attached_dp(intel_connector)) && - intel_connector->panel.fixed_mode) { - struct drm_display_mode *mode; - - mode = drm_mode_duplicate(connector->dev, - intel_connector->panel.fixed_mode); - if (mode) { - drm_mode_probed_add(connector, mode); - num_modes++; - } - } + if (intel_dp_is_edp(intel_attached_dp(intel_connector))) + num_modes += intel_panel_get_modes(intel_connector); if (num_modes) return num_modes; @@ -4643,9 +4770,7 @@ intel_dp_connector_register(struct drm_connector *connector) if (lspcon_init(dig_port)) { lspcon_detect_hdr_capability(lspcon); if (lspcon->hdr_supported) - drm_object_attach_property(&connector->base, - connector->dev->mode_config.hdr_output_metadata_property, - 0); + drm_connector_attach_hdr_output_metadata_property(connector); } return ret; @@ -4914,6 +5039,25 @@ bool intel_dp_is_port_edp(struct drm_i915_private *dev_priv, enum port port) return intel_bios_is_port_edp(dev_priv, port); } +static bool +has_gamut_metadata_dip(struct drm_i915_private *i915, enum port port) +{ + if (intel_bios_is_lspcon_present(i915, port)) + return false; + + if (DISPLAY_VER(i915) >= 11) + return true; + + if (port == PORT_A) + return false; + + if (IS_HASWELL(i915) || IS_BROADWELL(i915) || + DISPLAY_VER(i915) >= 9) + return true; + + return false; +} + static void intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connector) { @@ -4940,10 +5084,8 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect intel_attach_dp_colorspace_property(connector); } - if (IS_GEMINILAKE(dev_priv) || DISPLAY_VER(dev_priv) >= 11) - drm_object_attach_property(&connector->base, - connector->dev->mode_config.hdr_output_metadata_property, - 0); + if (has_gamut_metadata_dip(dev_priv, port)) + drm_connector_attach_hdr_output_metadata_property(connector); if (intel_dp_is_edp(intel_dp)) { u32 allowed_scalers; @@ -4962,14 +5104,30 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect drm_connector_attach_vrr_capable_property(connector); } +static void +intel_edp_add_properties(struct intel_dp *intel_dp) +{ + struct intel_connector *connector = intel_dp->attached_connector; + struct drm_i915_private *i915 = to_i915(connector->base.dev); + const struct drm_display_mode *fixed_mode = + intel_panel_preferred_fixed_mode(connector); + + if (!fixed_mode) + return; + + drm_connector_set_panel_orientation_with_quirk(&connector->base, + i915->vbt.orientation, + fixed_mode->hdisplay, + fixed_mode->vdisplay); +} + static bool intel_edp_init_connector(struct intel_dp *intel_dp, struct intel_connector *intel_connector) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); struct drm_device *dev = &dev_priv->drm; struct drm_connector *connector = &intel_connector->base; - struct drm_display_mode *fixed_mode = NULL; - struct drm_display_mode *downclock_mode = NULL; + struct drm_display_mode *fixed_mode; bool has_dpcd; enum pipe pipe = INVALID_PIPE; struct edid *edid; @@ -5026,20 +5184,20 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, } intel_connector->edid = edid; - fixed_mode = intel_panel_edid_fixed_mode(intel_connector); - if (fixed_mode) - downclock_mode = intel_drrs_init(intel_connector, fixed_mode); + intel_panel_add_edid_fixed_modes(intel_connector, + dev_priv->vbt.drrs_type != DRRS_TYPE_NONE); /* MSO requires information from the EDID */ intel_edp_mso_init(intel_dp); /* multiply the mode clock and horizontal timings for MSO */ - intel_edp_mso_mode_fixup(intel_connector, fixed_mode); - intel_edp_mso_mode_fixup(intel_connector, downclock_mode); + list_for_each_entry(fixed_mode, &intel_connector->panel.fixed_modes, head) + intel_edp_mso_mode_fixup(intel_connector, fixed_mode); /* fallback to VBT if available for eDP */ - if (!fixed_mode) - fixed_mode = intel_panel_vbt_fixed_mode(intel_connector); + if (!intel_panel_preferred_fixed_mode(intel_connector)) + intel_panel_add_vbt_lfp_fixed_mode(intel_connector); + mutex_unlock(&dev->mode_config.mutex); if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { @@ -5061,16 +5219,13 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, pipe_name(pipe)); } - intel_panel_init(&intel_connector->panel, fixed_mode, downclock_mode); + intel_panel_init(intel_connector); + if (!(dev_priv->quirks & QUIRK_NO_PPS_BACKLIGHT_POWER_HOOK)) intel_connector->panel.backlight.power = intel_pps_backlight_power; intel_backlight_setup(intel_connector, pipe); - if (fixed_mode) { - drm_connector_set_panel_orientation_with_quirk(connector, - dev_priv->vbt.orientation, - fixed_mode->hdisplay, fixed_mode->vdisplay); - } + intel_edp_add_properties(intel_dp); return true; diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c index 5d98773efd1b..26f9e2b748e4 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c @@ -55,6 +55,7 @@ static u8 *intel_dp_lttpr_phy_caps(struct intel_dp *intel_dp, } static void intel_dp_read_lttpr_phy_caps(struct intel_dp *intel_dp, + const u8 dpcd[DP_RECEIVER_CAP_SIZE], enum drm_dp_phy dp_phy) { struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; @@ -63,7 +64,7 @@ static void intel_dp_read_lttpr_phy_caps(struct intel_dp *intel_dp, intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name)); - if (drm_dp_read_lttpr_phy_caps(&intel_dp->aux, dp_phy, phy_caps) < 0) { + if (drm_dp_read_lttpr_phy_caps(&intel_dp->aux, dpcd, dp_phy, phy_caps) < 0) { drm_dbg_kms(&dp_to_i915(intel_dp)->drm, "[ENCODER:%d:%s][%s] failed to read the PHY caps\n", encoder->base.base.id, encoder->base.name, phy_name); @@ -77,10 +78,12 @@ static void intel_dp_read_lttpr_phy_caps(struct intel_dp *intel_dp, phy_caps); } -static bool intel_dp_read_lttpr_common_caps(struct intel_dp *intel_dp) +static bool intel_dp_read_lttpr_common_caps(struct intel_dp *intel_dp, + const u8 dpcd[DP_RECEIVER_CAP_SIZE]) { struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; struct drm_i915_private *i915 = to_i915(encoder->base.dev); + int ret; if (intel_dp_is_edp(intel_dp)) return false; @@ -92,8 +95,9 @@ static bool intel_dp_read_lttpr_common_caps(struct intel_dp *intel_dp) if (DISPLAY_VER(i915) < 10 || IS_GEMINILAKE(i915)) return false; - if (drm_dp_read_lttpr_common_caps(&intel_dp->aux, - intel_dp->lttpr_common_caps) < 0) + ret = drm_dp_read_lttpr_common_caps(&intel_dp->aux, dpcd, + intel_dp->lttpr_common_caps); + if (ret < 0) goto reset_caps; drm_dbg_kms(&dp_to_i915(intel_dp)->drm, @@ -122,14 +126,14 @@ intel_dp_set_lttpr_transparent_mode(struct intel_dp *intel_dp, bool enable) return drm_dp_dpcd_write(&intel_dp->aux, DP_PHY_REPEATER_MODE, &val, 1) == 1; } -static int intel_dp_init_lttpr(struct intel_dp *intel_dp) +static int intel_dp_init_lttpr(struct intel_dp *intel_dp, const u8 dpcd[DP_RECEIVER_CAP_SIZE]) { struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; struct drm_i915_private *i915 = to_i915(encoder->base.dev); int lttpr_count; int i; - if (!intel_dp_read_lttpr_common_caps(intel_dp)) + if (!intel_dp_read_lttpr_common_caps(intel_dp, dpcd)) return 0; lttpr_count = drm_dp_lttpr_count(intel_dp->lttpr_common_caps); @@ -168,7 +172,7 @@ static int intel_dp_init_lttpr(struct intel_dp *intel_dp) } for (i = 0; i < lttpr_count; i++) - intel_dp_read_lttpr_phy_caps(intel_dp, DP_PHY_LTTPR(i)); + intel_dp_read_lttpr_phy_caps(intel_dp, dpcd, DP_PHY_LTTPR(i)); return lttpr_count; } @@ -193,9 +197,18 @@ static int intel_dp_init_lttpr(struct intel_dp *intel_dp) */ int intel_dp_init_lttpr_and_dprx_caps(struct intel_dp *intel_dp) { - int lttpr_count = intel_dp_init_lttpr(intel_dp); + u8 dpcd[DP_RECEIVER_CAP_SIZE]; + int lttpr_count; + + if (drm_dp_read_dpcd_caps(&intel_dp->aux, dpcd)) + return -EIO; - /* The DPTX shall read the DPRX caps after LTTPR detection. */ + lttpr_count = intel_dp_init_lttpr(intel_dp, dpcd); + + /* + * The DPTX shall read the DPRX caps after LTTPR detection, so re-read + * it here. + */ if (drm_dp_read_dpcd_caps(&intel_dp->aux, intel_dp->dpcd)) { intel_dp_reset_lttpr_common_caps(intel_dp); return -EIO; diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index e30e698aa684..061b277e5ce7 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -398,9 +398,8 @@ static void intel_mst_disable_dp(struct intel_atomic_state *state, if (ret) { drm_dbg_kms(&i915->drm, "failed to update payload %d\n", ret); } - if (old_crtc_state->has_audio) - intel_audio_codec_disable(encoder, - old_crtc_state, old_conn_state); + + intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); } static void intel_mst_post_disable_dp(struct intel_atomic_state *state, @@ -599,8 +598,7 @@ static void intel_mst_enable_dp(struct intel_atomic_state *state, intel_crtc_vblank_on(pipe_config); - if (pipe_config->has_audio) - intel_audio_codec_enable(encoder, pipe_config, conn_state); + intel_audio_codec_enable(encoder, pipe_config, conn_state); /* Enable hdcp if it's desired */ if (conn_state->content_protection == diff --git a/drivers/gpu/drm/i915/display/intel_dpll.c b/drivers/gpu/drm/i915/display/intel_dpll.c index 14f5ffe27d05..95b9d327ed4d 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll.c +++ b/drivers/gpu/drm/i915/display/intel_dpll.c @@ -4,6 +4,7 @@ */ #include <linux/kernel.h> +#include <linux/string_helpers.h> #include "intel_crtc.h" #include "intel_de.h" @@ -253,12 +254,12 @@ static const struct intel_limit ilk_limits_dual_lvds_100m = { static const struct intel_limit intel_limits_vlv = { /* - * These are the data rate limits (measured in fast clocks) + * These are based on the data rate limits (measured in fast clocks) * since those are the strictest limits we have. The fast * clock and actual rate limits are more relaxed, so checking * them would make no difference. */ - .dot = { .min = 25000 * 5, .max = 270000 * 5 }, + .dot = { .min = 25000, .max = 270000 }, .vco = { .min = 4000000, .max = 6000000 }, .n = { .min = 1, .max = 7 }, .m1 = { .min = 2, .max = 3 }, @@ -269,12 +270,12 @@ static const struct intel_limit intel_limits_vlv = { static const struct intel_limit intel_limits_chv = { /* - * These are the data rate limits (measured in fast clocks) + * These are based on the data rate limits (measured in fast clocks) * since those are the strictest limits we have. The fast * clock and actual rate limits are more relaxed, so checking * them would make no difference. */ - .dot = { .min = 25000 * 5, .max = 540000 * 5}, + .dot = { .min = 25000, .max = 540000 }, .vco = { .min = 4800000, .max = 6480000 }, .n = { .min = 1, .max = 1 }, .m1 = { .min = 2, .max = 2 }, @@ -284,8 +285,7 @@ static const struct intel_limit intel_limits_chv = { }; static const struct intel_limit intel_limits_bxt = { - /* FIXME: find real dot limits */ - .dot = { .min = 0, .max = INT_MAX }, + .dot = { .min = 25000, .max = 594000 }, .vco = { .min = 4800000, .max = 6700000 }, .n = { .min = 1, .max = 1 }, .m1 = { .min = 2, .max = 2 }, @@ -336,26 +336,26 @@ int i9xx_calc_dpll_params(int refclk, struct dpll *clock) int vlv_calc_dpll_params(int refclk, struct dpll *clock) { clock->m = clock->m1 * clock->m2; - clock->p = clock->p1 * clock->p2; + clock->p = clock->p1 * clock->p2 * 5; if (WARN_ON(clock->n == 0 || clock->p == 0)) return 0; clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n); clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); - return clock->dot / 5; + return clock->dot; } int chv_calc_dpll_params(int refclk, struct dpll *clock) { clock->m = clock->m1 * clock->m2; - clock->p = clock->p1 * clock->p2; + clock->p = clock->p1 * clock->p2 * 5; if (WARN_ON(clock->n == 0 || clock->p == 0)) return 0; clock->vco = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(refclk, clock->m), clock->n << 22); clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); - return clock->dot / 5; + return clock->dot; } /* @@ -424,8 +424,7 @@ i9xx_select_p2_div(const struct intel_limit *limit, /* * Returns a set of divisors for the desired target clock with the given - * refclk, or FALSE. The returned values represent the clock equation: - * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2. + * refclk, or FALSE. * * Target and reference clocks are specified in kHz. * @@ -483,8 +482,7 @@ i9xx_find_best_dpll(const struct intel_limit *limit, /* * Returns a set of divisors for the desired target clock with the given - * refclk, or FALSE. The returned values represent the clock equation: - * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2. + * refclk, or FALSE. * * Target and reference clocks are specified in kHz. * @@ -540,8 +538,7 @@ pnv_find_best_dpll(const struct intel_limit *limit, /* * Returns a set of divisors for the desired target clock with the given - * refclk, or FALSE. The returned values represent the clock equation: - * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2. + * refclk, or FALSE. * * Target and reference clocks are specified in kHz. * @@ -640,8 +637,7 @@ static bool vlv_PLL_is_optimal(struct drm_device *dev, int target_freq, /* * Returns a set of divisors for the desired target clock with the given - * refclk, or FALSE. The returned values represent the clock equation: - * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2. + * refclk, or FALSE. */ static bool vlv_find_best_dpll(const struct intel_limit *limit, @@ -658,8 +654,6 @@ vlv_find_best_dpll(const struct intel_limit *limit, int max_n = min(limit->n.max, refclk / 19200); bool found = false; - target *= 5; /* fast clock */ - memset(best_clock, 0, sizeof(*best_clock)); /* based on hardware requirement, prefer smaller n to precision */ @@ -667,7 +661,7 @@ vlv_find_best_dpll(const struct intel_limit *limit, for (clock.p1 = limit->p1.max; clock.p1 >= limit->p1.min; clock.p1--) { for (clock.p2 = limit->p2.p2_fast; clock.p2 >= limit->p2.p2_slow; clock.p2 -= clock.p2 > 10 ? 2 : 1) { - clock.p = clock.p1 * clock.p2; + clock.p = clock.p1 * clock.p2 * 5; /* based on hardware requirement, prefer bigger m1,m2 values */ for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) { unsigned int ppm; @@ -701,8 +695,7 @@ vlv_find_best_dpll(const struct intel_limit *limit, /* * Returns a set of divisors for the desired target clock with the given - * refclk, or FALSE. The returned values represent the clock equation: - * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2. + * refclk, or FALSE. */ static bool chv_find_best_dpll(const struct intel_limit *limit, @@ -728,7 +721,6 @@ chv_find_best_dpll(const struct intel_limit *limit, */ clock.n = 1; clock.m1 = 2; - target *= 5; /* fast clock */ for (clock.p1 = limit->p1.max; clock.p1 >= limit->p1.min; clock.p1--) { for (clock.p2 = limit->p2.p2_fast; @@ -736,7 +728,7 @@ chv_find_best_dpll(const struct intel_limit *limit, clock.p2 -= clock.p2 > 10 ? 2 : 1) { unsigned int error_ppm; - clock.p = clock.p1 * clock.p2; + clock.p = clock.p1 * clock.p2 * 5; m2 = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(target, clock.p * clock.n) << 22, refclk * clock.m1); @@ -1945,7 +1937,7 @@ static void assert_pll(struct drm_i915_private *dev_priv, cur_state = intel_de_read(dev_priv, DPLL(pipe)) & DPLL_VCO_ENABLE; I915_STATE_WARN(cur_state != state, "PLL state assertion failure (expected %s, current %s)\n", - onoff(state), onoff(cur_state)); + str_on_off(state), str_on_off(cur_state)); } void assert_pll_enabled(struct drm_i915_private *i915, enum pipe pipe) diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c index 569903d47aea..b7071da4b7e5 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c @@ -21,6 +21,8 @@ * DEALINGS IN THE SOFTWARE. */ +#include <linux/string_helpers.h> + #include "intel_de.h" #include "intel_display_types.h" #include "intel_dpio_phy.h" @@ -178,13 +180,14 @@ void assert_shared_dpll(struct drm_i915_private *dev_priv, struct intel_dpll_hw_state hw_state; if (drm_WARN(&dev_priv->drm, !pll, - "asserting DPLL %s with no DPLL\n", onoff(state))) + "asserting DPLL %s with no DPLL\n", str_on_off(state))) return; cur_state = intel_dpll_get_hw_state(dev_priv, pll, &hw_state); I915_STATE_WARN(cur_state != state, "%s assertion failure (expected %s, current %s)\n", - pll->info->name, onoff(state), onoff(cur_state)); + pll->info->name, str_on_off(state), + str_on_off(cur_state)); } static enum tc_port icl_pll_id_to_tc_port(enum intel_dpll_id id) @@ -832,7 +835,7 @@ hsw_ddi_calculate_wrpll(int clock /* in Hz */, { u64 freq2k; unsigned p, n2, r2; - struct hsw_wrpll_rnp best = { 0, 0, 0 }; + struct hsw_wrpll_rnp best = {}; unsigned budget; freq2k = clock / 100; @@ -1330,13 +1333,6 @@ struct skl_wrpll_context { unsigned int p; /* chosen divider */ }; -static void skl_wrpll_context_init(struct skl_wrpll_context *ctx) -{ - memset(ctx, 0, sizeof(*ctx)); - - ctx->min_deviation = U64_MAX; -} - /* DCO freq must be within +1%/-6% of the DCO central freq */ #define SKL_DCO_MAX_PDEVIATION 100 #define SKL_DCO_MAX_NDEVIATION 600 @@ -1502,28 +1498,28 @@ skl_ddi_calculate_wrpll(int clock /* in Hz */, int ref_clock, struct skl_wrpll_params *wrpll_params) { - u64 afe_clock = clock * 5; /* AFE Clock is 5x Pixel clock */ - u64 dco_central_freq[3] = { 8400000000ULL, - 9000000000ULL, - 9600000000ULL }; - static const int even_dividers[] = { 4, 6, 8, 10, 12, 14, 16, 18, 20, - 24, 28, 30, 32, 36, 40, 42, 44, - 48, 52, 54, 56, 60, 64, 66, 68, - 70, 72, 76, 78, 80, 84, 88, 90, - 92, 96, 98 }; - static const int odd_dividers[] = { 3, 5, 7, 9, 15, 21, 35 }; + static const u64 dco_central_freq[3] = { 8400000000ULL, + 9000000000ULL, + 9600000000ULL }; + static const u8 even_dividers[] = { 4, 6, 8, 10, 12, 14, 16, 18, 20, + 24, 28, 30, 32, 36, 40, 42, 44, + 48, 52, 54, 56, 60, 64, 66, 68, + 70, 72, 76, 78, 80, 84, 88, 90, + 92, 96, 98 }; + static const u8 odd_dividers[] = { 3, 5, 7, 9, 15, 21, 35 }; static const struct { - const int *list; + const u8 *list; int n_dividers; } dividers[] = { { even_dividers, ARRAY_SIZE(even_dividers) }, { odd_dividers, ARRAY_SIZE(odd_dividers) }, }; - struct skl_wrpll_context ctx; + struct skl_wrpll_context ctx = { + .min_deviation = U64_MAX, + }; unsigned int dco, d, i; unsigned int p0, p1, p2; - - skl_wrpll_context_init(&ctx); + u64 afe_clock = clock * 5; /* AFE Clock is 5x Pixel clock */ for (d = 0; d < ARRAY_SIZE(dividers); d++) { for (dco = 0; dco < ARRAY_SIZE(dco_central_freq); dco++) { @@ -1574,8 +1570,8 @@ skip_remaining_dividers: static bool skl_ddi_hdmi_pll_dividers(struct intel_crtc_state *crtc_state) { struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); + struct skl_wrpll_params wrpll_params = {}; u32 ctrl1, cfgcr1, cfgcr2; - struct skl_wrpll_params wrpll_params = { 0, }; /* * See comment in intel_dpll_hw_state to understand why we always use 0 @@ -1902,7 +1898,7 @@ static void bxt_ddi_pll_enable(struct drm_i915_private *dev_priv, /* Write M2 integer */ temp = intel_de_read(dev_priv, BXT_PORT_PLL(phy, ch, 0)); - temp &= ~PORT_PLL_M2_MASK; + temp &= ~PORT_PLL_M2_INT_MASK; temp |= pll->state.hw_state.pll0; intel_de_write(dev_priv, BXT_PORT_PLL(phy, ch, 0), temp); @@ -2038,7 +2034,7 @@ static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv, hw_state->ebb4 &= PORT_PLL_10BIT_CLK_ENABLE; hw_state->pll0 = intel_de_read(dev_priv, BXT_PORT_PLL(phy, ch, 0)); - hw_state->pll0 &= PORT_PLL_M2_MASK; + hw_state->pll0 &= PORT_PLL_M2_INT_MASK; hw_state->pll1 = intel_de_read(dev_priv, BXT_PORT_PLL(phy, ch, 1)); hw_state->pll1 &= PORT_PLL_N_MASK; @@ -2087,82 +2083,64 @@ out: return ret; } -/* bxt clock parameters */ -struct bxt_clk_div { - int clock; - u32 p1; - u32 p2; - u32 m2_int; - u32 m2_frac; - bool m2_frac_en; - u32 n; - - int vco; -}; - /* pre-calculated values for DP linkrates */ -static const struct bxt_clk_div bxt_dp_clk_val[] = { - {162000, 4, 2, 32, 1677722, 1, 1}, - {270000, 4, 1, 27, 0, 0, 1}, - {540000, 2, 1, 27, 0, 0, 1}, - {216000, 3, 2, 32, 1677722, 1, 1}, - {243000, 4, 1, 24, 1258291, 1, 1}, - {324000, 4, 1, 32, 1677722, 1, 1}, - {432000, 3, 1, 32, 1677722, 1, 1} +static const struct dpll bxt_dp_clk_val[] = { + /* m2 is .22 binary fixed point */ + { .dot = 162000, .p1 = 4, .p2 = 2, .n = 1, .m1 = 2, .m2 = 0x819999a /* 32.4 */ }, + { .dot = 270000, .p1 = 4, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x6c00000 /* 27.0 */ }, + { .dot = 540000, .p1 = 2, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x6c00000 /* 27.0 */ }, + { .dot = 216000, .p1 = 3, .p2 = 2, .n = 1, .m1 = 2, .m2 = 0x819999a /* 32.4 */ }, + { .dot = 243000, .p1 = 4, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x6133333 /* 24.3 */ }, + { .dot = 324000, .p1 = 4, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x819999a /* 32.4 */ }, + { .dot = 432000, .p1 = 3, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x819999a /* 32.4 */ }, }; static bool bxt_ddi_hdmi_pll_dividers(struct intel_crtc_state *crtc_state, - struct bxt_clk_div *clk_div) + struct dpll *clk_div) { struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - struct dpll best_clock; /* Calculate HDMI div */ /* * FIXME: tie the following calculation into * i9xx_crtc_compute_clock */ - if (!bxt_find_best_dpll(crtc_state, &best_clock)) { + if (!bxt_find_best_dpll(crtc_state, clk_div)) { drm_dbg(&i915->drm, "no PLL dividers found for clock %d pipe %c\n", crtc_state->port_clock, pipe_name(crtc->pipe)); return false; } - clk_div->p1 = best_clock.p1; - clk_div->p2 = best_clock.p2; - drm_WARN_ON(&i915->drm, best_clock.m1 != 2); - clk_div->n = best_clock.n; - clk_div->m2_int = best_clock.m2 >> 22; - clk_div->m2_frac = best_clock.m2 & ((1 << 22) - 1); - clk_div->m2_frac_en = clk_div->m2_frac != 0; - - clk_div->vco = best_clock.vco; + drm_WARN_ON(&i915->drm, clk_div->m1 != 2); return true; } static void bxt_ddi_dp_pll_dividers(struct intel_crtc_state *crtc_state, - struct bxt_clk_div *clk_div) + struct dpll *clk_div) { - int clock = crtc_state->port_clock; + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); int i; *clk_div = bxt_dp_clk_val[0]; for (i = 0; i < ARRAY_SIZE(bxt_dp_clk_val); ++i) { - if (bxt_dp_clk_val[i].clock == clock) { + if (crtc_state->port_clock == bxt_dp_clk_val[i].dot) { *clk_div = bxt_dp_clk_val[i]; break; } } - clk_div->vco = clock * 10 / 2 * clk_div->p1 * clk_div->p2; + chv_calc_dpll_params(i915->dpll.ref_clks.nssc, clk_div); + + drm_WARN_ON(&i915->drm, clk_div->vco == 0 || + clk_div->dot != crtc_state->port_clock); } static bool bxt_ddi_set_dpll_hw_state(struct intel_crtc_state *crtc_state, - const struct bxt_clk_div *clk_div) + const struct dpll *clk_div) { struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); struct intel_dpll_hw_state *dpll_hw_state = &crtc_state->dpll_hw_state; @@ -2206,23 +2184,23 @@ static bool bxt_ddi_set_dpll_hw_state(struct intel_crtc_state *crtc_state, lanestagger = 0x02; dpll_hw_state->ebb0 = PORT_PLL_P1(clk_div->p1) | PORT_PLL_P2(clk_div->p2); - dpll_hw_state->pll0 = clk_div->m2_int; + dpll_hw_state->pll0 = PORT_PLL_M2_INT(clk_div->m2 >> 22); dpll_hw_state->pll1 = PORT_PLL_N(clk_div->n); - dpll_hw_state->pll2 = clk_div->m2_frac; + dpll_hw_state->pll2 = PORT_PLL_M2_FRAC(clk_div->m2 & 0x3fffff); - if (clk_div->m2_frac_en) + if (clk_div->m2 & 0x3fffff) dpll_hw_state->pll3 = PORT_PLL_M2_FRAC_ENABLE; - dpll_hw_state->pll6 = prop_coef | PORT_PLL_INT_COEFF(int_coef); - dpll_hw_state->pll6 |= PORT_PLL_GAIN_CTL(gain_ctl); + dpll_hw_state->pll6 = PORT_PLL_PROP_COEFF(prop_coef) | + PORT_PLL_INT_COEFF(int_coef) | + PORT_PLL_GAIN_CTL(gain_ctl); - dpll_hw_state->pll8 = targ_cnt; + dpll_hw_state->pll8 = PORT_PLL_TARGET_CNT(targ_cnt); - dpll_hw_state->pll9 = 5 << PORT_PLL_LOCK_THRESHOLD_SHIFT; + dpll_hw_state->pll9 = PORT_PLL_LOCK_THRESHOLD(5); - dpll_hw_state->pll10 = - PORT_PLL_DCO_AMP(PORT_PLL_DCO_AMP_DEFAULT) - | PORT_PLL_DCO_AMP_OVR_EN_H; + dpll_hw_state->pll10 = PORT_PLL_DCO_AMP(15) | + PORT_PLL_DCO_AMP_OVR_EN_H; dpll_hw_state->ebb4 = PORT_PLL_10BIT_CLK_ENABLE; @@ -2234,7 +2212,7 @@ static bool bxt_ddi_set_dpll_hw_state(struct intel_crtc_state *crtc_state, static bool bxt_ddi_dp_set_dpll_hw_state(struct intel_crtc_state *crtc_state) { - struct bxt_clk_div clk_div = {}; + struct dpll clk_div = {}; bxt_ddi_dp_pll_dividers(crtc_state, &clk_div); @@ -2244,7 +2222,7 @@ bxt_ddi_dp_set_dpll_hw_state(struct intel_crtc_state *crtc_state) static bool bxt_ddi_hdmi_set_dpll_hw_state(struct intel_crtc_state *crtc_state) { - struct bxt_clk_div clk_div = {}; + struct dpll clk_div = {}; bxt_ddi_hdmi_pll_dividers(crtc_state, &clk_div); @@ -2258,12 +2236,12 @@ static int bxt_ddi_pll_get_freq(struct drm_i915_private *i915, struct dpll clock; clock.m1 = 2; - clock.m2 = (pll_state->pll0 & PORT_PLL_M2_MASK) << 22; + clock.m2 = REG_FIELD_GET(PORT_PLL_M2_INT_MASK, pll_state->pll0) << 22; if (pll_state->pll3 & PORT_PLL_M2_FRAC_ENABLE) - clock.m2 |= pll_state->pll2 & PORT_PLL_M2_FRAC_MASK; - clock.n = (pll_state->pll1 & PORT_PLL_N_MASK) >> PORT_PLL_N_SHIFT; - clock.p1 = (pll_state->ebb0 & PORT_PLL_P1_MASK) >> PORT_PLL_P1_SHIFT; - clock.p2 = (pll_state->ebb0 & PORT_PLL_P2_MASK) >> PORT_PLL_P2_SHIFT; + clock.m2 |= REG_FIELD_GET(PORT_PLL_M2_FRAC_MASK, pll_state->pll2); + clock.n = REG_FIELD_GET(PORT_PLL_N_MASK, pll_state->pll1); + clock.p1 = REG_FIELD_GET(PORT_PLL_P1_MASK, pll_state->ebb0); + clock.p2 = REG_FIELD_GET(PORT_PLL_P2_MASK, pll_state->ebb0); return chv_calc_dpll_params(i915->dpll.ref_clks.nssc, &clock); } @@ -2758,8 +2736,8 @@ static bool icl_mg_pll_find_divisors(int clock_khz, bool is_dp, bool use_ssc, struct intel_dpll_hw_state *state, bool is_dkl) { + static const u8 div1_vals[] = { 7, 5, 3, 2 }; u32 dco_min_freq, dco_max_freq; - int div1_vals[] = {7, 5, 3, 2}; unsigned int i; int div2; diff --git a/drivers/gpu/drm/i915/display/intel_dpt.c b/drivers/gpu/drm/i915/display/intel_dpt.c index 05dd7dba3a5c..15b2716172f7 100644 --- a/drivers/gpu/drm/i915/display/intel_dpt.c +++ b/drivers/gpu/drm/i915/display/intel_dpt.c @@ -249,7 +249,7 @@ intel_dpt_create(struct intel_framebuffer *fb) size = round_up(size * sizeof(gen8_pte_t), I915_GTT_PAGE_SIZE); if (HAS_LMEM(i915)) - dpt_obj = i915_gem_object_create_lmem(i915, size, 0); + dpt_obj = i915_gem_object_create_lmem(i915, size, I915_BO_ALLOC_CONTIGUOUS); else dpt_obj = i915_gem_object_create_stolen(i915, size); if (IS_ERR(dpt_obj)) diff --git a/drivers/gpu/drm/i915/display/intel_drrs.c b/drivers/gpu/drm/i915/display/intel_drrs.c index fa715b8ea310..166caf293f7b 100644 --- a/drivers/gpu/drm/i915/display/intel_drrs.c +++ b/drivers/gpu/drm/i915/display/intel_drrs.c @@ -47,74 +47,36 @@ * requested by userspace. */ -static bool can_enable_drrs(struct intel_connector *connector, - const struct intel_crtc_state *pipe_config) +const char *intel_drrs_type_str(enum drrs_type drrs_type) { - const struct drm_i915_private *i915 = to_i915(connector->base.dev); - - if (pipe_config->vrr.enable) - return false; - - /* - * DRRS and PSR can't be enable together, so giving preference to PSR - * as it allows more power-savings by complete shutting down display, - * so to guarantee this, intel_drrs_compute_config() must be called - * after intel_psr_compute_config(). - */ - if (pipe_config->has_psr) - return false; - - return connector->panel.downclock_mode && - i915->drrs.type == SEAMLESS_DRRS_SUPPORT; -} - -void -intel_drrs_compute_config(struct intel_dp *intel_dp, - struct intel_crtc_state *pipe_config, - int output_bpp, bool constant_n) -{ - struct intel_connector *connector = intel_dp->attached_connector; - struct drm_i915_private *i915 = to_i915(connector->base.dev); - int pixel_clock; - - if (!can_enable_drrs(connector, pipe_config)) { - if (intel_cpu_transcoder_has_m2_n2(i915, pipe_config->cpu_transcoder)) - intel_zero_m_n(&pipe_config->dp_m2_n2); - return; - } - - pipe_config->has_drrs = true; - - pixel_clock = connector->panel.downclock_mode->clock; - if (pipe_config->splitter.enable) - pixel_clock /= pipe_config->splitter.link_count; + static const char * const str[] = { + [DRRS_TYPE_NONE] = "none", + [DRRS_TYPE_STATIC] = "static", + [DRRS_TYPE_SEAMLESS] = "seamless", + }; - intel_link_compute_m_n(output_bpp, pipe_config->lane_count, pixel_clock, - pipe_config->port_clock, &pipe_config->dp_m2_n2, - constant_n, pipe_config->fec_enable); + if (drrs_type >= ARRAY_SIZE(str)) + return "<invalid>"; - /* FIXME: abstract this better */ - if (pipe_config->splitter.enable) - pipe_config->dp_m2_n2.data_m *= pipe_config->splitter.link_count; + return str[drrs_type]; } static void -intel_drrs_set_refresh_rate_pipeconf(const struct intel_crtc_state *crtc_state, - enum drrs_refresh_rate_type refresh_type) +intel_drrs_set_refresh_rate_pipeconf(struct intel_crtc *crtc, + enum drrs_refresh_rate refresh_rate) { - struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; + enum transcoder cpu_transcoder = crtc->drrs.cpu_transcoder; u32 val, bit; if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) - bit = PIPECONF_EDP_RR_MODE_SWITCH_VLV; + bit = PIPECONF_REFRESH_RATE_ALT_VLV; else - bit = PIPECONF_EDP_RR_MODE_SWITCH; + bit = PIPECONF_REFRESH_RATE_ALT_ILK; val = intel_de_read(dev_priv, PIPECONF(cpu_transcoder)); - if (refresh_type == DRRS_LOW_RR) + if (refresh_rate == DRRS_REFRESH_RATE_LOW) val |= bit; else val &= ~bit; @@ -123,244 +85,171 @@ intel_drrs_set_refresh_rate_pipeconf(const struct intel_crtc_state *crtc_state, } static void -intel_drrs_set_refresh_rate_m_n(const struct intel_crtc_state *crtc_state, - enum drrs_refresh_rate_type refresh_type) +intel_drrs_set_refresh_rate_m_n(struct intel_crtc *crtc, + enum drrs_refresh_rate refresh_rate) { - struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - - intel_cpu_transcoder_set_m1_n1(crtc, crtc_state->cpu_transcoder, - refresh_type == DRRS_LOW_RR ? - &crtc_state->dp_m2_n2 : &crtc_state->dp_m_n); + intel_cpu_transcoder_set_m1_n1(crtc, crtc->drrs.cpu_transcoder, + refresh_rate == DRRS_REFRESH_RATE_LOW ? + &crtc->drrs.m2_n2 : &crtc->drrs.m_n); } -static void intel_drrs_set_state(struct drm_i915_private *dev_priv, - const struct intel_crtc_state *crtc_state, - enum drrs_refresh_rate_type refresh_type) +bool intel_drrs_is_active(struct intel_crtc *crtc) { - struct intel_dp *intel_dp = dev_priv->drrs.dp; - struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - struct drm_display_mode *mode; - - if (!intel_dp) { - drm_dbg_kms(&dev_priv->drm, "DRRS not supported.\n"); - return; - } - - if (!crtc) { - drm_dbg_kms(&dev_priv->drm, - "DRRS: intel_crtc not initialized\n"); - return; - } - - if (dev_priv->drrs.type < SEAMLESS_DRRS_SUPPORT) { - drm_dbg_kms(&dev_priv->drm, "Only Seamless DRRS supported.\n"); - return; - } + return crtc->drrs.cpu_transcoder != INVALID_TRANSCODER; +} - if (refresh_type == dev_priv->drrs.refresh_rate_type) - return; +static void intel_drrs_set_state(struct intel_crtc *crtc, + enum drrs_refresh_rate refresh_rate) +{ + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - if (!crtc_state->hw.active) { - drm_dbg_kms(&dev_priv->drm, - "eDP encoder disabled. CRTC not Active\n"); + if (refresh_rate == crtc->drrs.refresh_rate) return; - } - if (DISPLAY_VER(dev_priv) >= 8 && !IS_CHERRYVIEW(dev_priv)) - intel_drrs_set_refresh_rate_m_n(crtc_state, refresh_type); - else if (DISPLAY_VER(dev_priv) > 6) - intel_drrs_set_refresh_rate_pipeconf(crtc_state, refresh_type); + if (intel_cpu_transcoder_has_m2_n2(dev_priv, crtc->drrs.cpu_transcoder)) + intel_drrs_set_refresh_rate_pipeconf(crtc, refresh_rate); + else + intel_drrs_set_refresh_rate_m_n(crtc, refresh_rate); - dev_priv->drrs.refresh_rate_type = refresh_type; + crtc->drrs.refresh_rate = refresh_rate; +} - if (refresh_type == DRRS_LOW_RR) - mode = intel_dp->attached_connector->panel.downclock_mode; - else - mode = intel_dp->attached_connector->panel.fixed_mode; - drm_dbg_kms(&dev_priv->drm, "eDP Refresh Rate set to : %dHz\n", - drm_mode_vrefresh(mode)); +static void intel_drrs_schedule_work(struct intel_crtc *crtc) +{ + mod_delayed_work(system_wq, &crtc->drrs.work, msecs_to_jiffies(1000)); } -static void -intel_drrs_enable_locked(struct intel_dp *intel_dp) +static unsigned int intel_drrs_frontbuffer_bits(const struct intel_crtc_state *crtc_state) { - struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + unsigned int frontbuffer_bits; + + frontbuffer_bits = INTEL_FRONTBUFFER_ALL_MASK(crtc->pipe); - dev_priv->drrs.busy_frontbuffer_bits = 0; - dev_priv->drrs.dp = intel_dp; + for_each_intel_crtc_in_pipe_mask(&i915->drm, crtc, + crtc_state->bigjoiner_pipes) + frontbuffer_bits |= INTEL_FRONTBUFFER_ALL_MASK(crtc->pipe); + + return frontbuffer_bits; } /** - * intel_drrs_enable - init drrs struct if supported - * @intel_dp: DP struct - * @crtc_state: A pointer to the active crtc state. + * intel_drrs_activate - activate DRRS + * @crtc_state: the crtc state * - * Initializes frontbuffer_bits and drrs.dp + * Activates DRRS on the crtc. */ -void intel_drrs_enable(struct intel_dp *intel_dp, - const struct intel_crtc_state *crtc_state) +void intel_drrs_activate(const struct intel_crtc_state *crtc_state) { - struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); if (!crtc_state->has_drrs) return; - drm_dbg_kms(&dev_priv->drm, "Enabling DRRS\n"); + if (!crtc_state->hw.active) + return; - mutex_lock(&dev_priv->drrs.mutex); + if (intel_crtc_is_bigjoiner_slave(crtc_state)) + return; - if (dev_priv->drrs.dp) { - drm_warn(&dev_priv->drm, "DRRS already enabled\n"); - goto unlock; - } + mutex_lock(&crtc->drrs.mutex); - intel_drrs_enable_locked(intel_dp); + crtc->drrs.cpu_transcoder = crtc_state->cpu_transcoder; + crtc->drrs.m_n = crtc_state->dp_m_n; + crtc->drrs.m2_n2 = crtc_state->dp_m2_n2; + crtc->drrs.frontbuffer_bits = intel_drrs_frontbuffer_bits(crtc_state); + crtc->drrs.busy_frontbuffer_bits = 0; -unlock: - mutex_unlock(&dev_priv->drrs.mutex); -} + intel_drrs_schedule_work(crtc); -static void -intel_drrs_disable_locked(struct intel_dp *intel_dp, - const struct intel_crtc_state *crtc_state) -{ - struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); - - intel_drrs_set_state(dev_priv, crtc_state, DRRS_HIGH_RR); - dev_priv->drrs.dp = NULL; + mutex_unlock(&crtc->drrs.mutex); } /** - * intel_drrs_disable - Disable DRRS - * @intel_dp: DP struct - * @old_crtc_state: Pointer to old crtc_state. + * intel_drrs_deactivate - deactivate DRRS + * @old_crtc_state: the old crtc state * + * Deactivates DRRS on the crtc. */ -void intel_drrs_disable(struct intel_dp *intel_dp, - const struct intel_crtc_state *old_crtc_state) +void intel_drrs_deactivate(const struct intel_crtc_state *old_crtc_state) { - struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc); if (!old_crtc_state->has_drrs) return; - mutex_lock(&dev_priv->drrs.mutex); - if (!dev_priv->drrs.dp) { - mutex_unlock(&dev_priv->drrs.mutex); + if (!old_crtc_state->hw.active) return; - } - - intel_drrs_disable_locked(intel_dp, old_crtc_state); - mutex_unlock(&dev_priv->drrs.mutex); - - cancel_delayed_work_sync(&dev_priv->drrs.work); -} - -/** - * intel_drrs_update - Update DRRS state - * @intel_dp: Intel DP - * @crtc_state: new CRTC state - * - * This function will update DRRS states, disabling or enabling DRRS when - * executing fastsets. For full modeset, intel_drrs_disable() and - * intel_drrs_enable() should be called instead. - */ -void -intel_drrs_update(struct intel_dp *intel_dp, - const struct intel_crtc_state *crtc_state) -{ - struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); - if (dev_priv->drrs.type != SEAMLESS_DRRS_SUPPORT) + if (intel_crtc_is_bigjoiner_slave(old_crtc_state)) return; - mutex_lock(&dev_priv->drrs.mutex); + mutex_lock(&crtc->drrs.mutex); - /* New state matches current one? */ - if (crtc_state->has_drrs == !!dev_priv->drrs.dp) - goto unlock; + if (intel_drrs_is_active(crtc)) + intel_drrs_set_state(crtc, DRRS_REFRESH_RATE_HIGH); - if (crtc_state->has_drrs) - intel_drrs_enable_locked(intel_dp); - else - intel_drrs_disable_locked(intel_dp, crtc_state); + crtc->drrs.cpu_transcoder = INVALID_TRANSCODER; + crtc->drrs.frontbuffer_bits = 0; + crtc->drrs.busy_frontbuffer_bits = 0; + + mutex_unlock(&crtc->drrs.mutex); -unlock: - mutex_unlock(&dev_priv->drrs.mutex); + cancel_delayed_work_sync(&crtc->drrs.work); } static void intel_drrs_downclock_work(struct work_struct *work) { - struct drm_i915_private *dev_priv = - container_of(work, typeof(*dev_priv), drrs.work.work); - struct intel_dp *intel_dp; - struct drm_crtc *crtc; - - mutex_lock(&dev_priv->drrs.mutex); - - intel_dp = dev_priv->drrs.dp; + struct intel_crtc *crtc = container_of(work, typeof(*crtc), drrs.work.work); - if (!intel_dp) - goto unlock; + mutex_lock(&crtc->drrs.mutex); - /* - * The delayed work can race with an invalidate hence we need to - * recheck. - */ + if (intel_drrs_is_active(crtc) && !crtc->drrs.busy_frontbuffer_bits) + intel_drrs_set_state(crtc, DRRS_REFRESH_RATE_LOW); - if (dev_priv->drrs.busy_frontbuffer_bits) - goto unlock; - - crtc = dp_to_dig_port(intel_dp)->base.base.crtc; - intel_drrs_set_state(dev_priv, to_intel_crtc(crtc)->config, DRRS_LOW_RR); - -unlock: - mutex_unlock(&dev_priv->drrs.mutex); + mutex_unlock(&crtc->drrs.mutex); } static void intel_drrs_frontbuffer_update(struct drm_i915_private *dev_priv, - unsigned int frontbuffer_bits, + unsigned int all_frontbuffer_bits, bool invalidate) { - struct intel_dp *intel_dp; - struct drm_crtc *crtc; - enum pipe pipe; + struct intel_crtc *crtc; - if (dev_priv->drrs.type == DRRS_NOT_SUPPORTED) + if (dev_priv->vbt.drrs_type != DRRS_TYPE_SEAMLESS) return; - cancel_delayed_work(&dev_priv->drrs.work); + for_each_intel_crtc(&dev_priv->drm, crtc) { + unsigned int frontbuffer_bits; - mutex_lock(&dev_priv->drrs.mutex); + mutex_lock(&crtc->drrs.mutex); - intel_dp = dev_priv->drrs.dp; - if (!intel_dp) { - mutex_unlock(&dev_priv->drrs.mutex); - return; - } + frontbuffer_bits = all_frontbuffer_bits & crtc->drrs.frontbuffer_bits; + if (!frontbuffer_bits) { + mutex_unlock(&crtc->drrs.mutex); + continue; + } - crtc = dp_to_dig_port(intel_dp)->base.base.crtc; - pipe = to_intel_crtc(crtc)->pipe; + if (invalidate) + crtc->drrs.busy_frontbuffer_bits |= frontbuffer_bits; + else + crtc->drrs.busy_frontbuffer_bits &= ~frontbuffer_bits; - frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe); - if (invalidate) - dev_priv->drrs.busy_frontbuffer_bits |= frontbuffer_bits; - else - dev_priv->drrs.busy_frontbuffer_bits &= ~frontbuffer_bits; - - /* flush/invalidate means busy screen hence upclock */ - if (frontbuffer_bits) - intel_drrs_set_state(dev_priv, to_intel_crtc(crtc)->config, - DRRS_HIGH_RR); - - /* - * flush also means no more activity hence schedule downclock, if all - * other fbs are quiescent too - */ - if (!invalidate && !dev_priv->drrs.busy_frontbuffer_bits) - schedule_delayed_work(&dev_priv->drrs.work, - msecs_to_jiffies(1000)); - mutex_unlock(&dev_priv->drrs.mutex); + /* flush/invalidate means busy screen hence upclock */ + intel_drrs_set_state(crtc, DRRS_REFRESH_RATE_HIGH); + + /* + * flush also means no more activity hence schedule downclock, if all + * other fbs are quiescent too + */ + if (!crtc->drrs.busy_frontbuffer_bits) + intel_drrs_schedule_work(crtc); + else + cancel_delayed_work(&crtc->drrs.work); + + mutex_unlock(&crtc->drrs.mutex); + } } /** @@ -397,68 +286,17 @@ void intel_drrs_flush(struct drm_i915_private *dev_priv, intel_drrs_frontbuffer_update(dev_priv, frontbuffer_bits, false); } -void intel_drrs_page_flip(struct intel_atomic_state *state, - struct intel_crtc *crtc) -{ - struct drm_i915_private *dev_priv = to_i915(state->base.dev); - unsigned int frontbuffer_bits = INTEL_FRONTBUFFER_ALL_MASK(crtc->pipe); - - intel_drrs_frontbuffer_update(dev_priv, frontbuffer_bits, false); -} - /** - * intel_drrs_init - Init basic DRRS work and mutex. - * @connector: eDP connector - * @fixed_mode: preferred mode of panel + * intel_crtc_drrs_init - Init DRRS for CRTC + * @crtc: crtc * - * This function is called only once at driver load to initialize basic + * This function is called only once at driver load to initialize basic * DRRS stuff. * - * Returns: - * Downclock mode if panel supports it, else return NULL. - * DRRS support is determined by the presence of downclock mode (apart - * from VBT setting). */ -struct drm_display_mode * -intel_drrs_init(struct intel_connector *connector, - struct drm_display_mode *fixed_mode) +void intel_crtc_drrs_init(struct intel_crtc *crtc) { - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - struct intel_encoder *encoder = connector->encoder; - struct drm_display_mode *downclock_mode = NULL; - - INIT_DELAYED_WORK(&dev_priv->drrs.work, intel_drrs_downclock_work); - mutex_init(&dev_priv->drrs.mutex); - - if (DISPLAY_VER(dev_priv) <= 6) { - drm_dbg_kms(&dev_priv->drm, - "DRRS supported for Gen7 and above\n"); - return NULL; - } - - if ((DISPLAY_VER(dev_priv) < 8 && !HAS_GMCH(dev_priv)) && - encoder->port != PORT_A) { - drm_dbg_kms(&dev_priv->drm, - "DRRS only supported on eDP port A\n"); - return NULL; - } - - if (dev_priv->vbt.drrs_type != SEAMLESS_DRRS_SUPPORT) { - drm_dbg_kms(&dev_priv->drm, "VBT doesn't support DRRS\n"); - return NULL; - } - - downclock_mode = intel_panel_edid_downclock_mode(connector, fixed_mode); - if (!downclock_mode) { - drm_dbg_kms(&dev_priv->drm, - "Downclock mode is not found. DRRS not supported\n"); - return NULL; - } - - dev_priv->drrs.type = dev_priv->vbt.drrs_type; - - dev_priv->drrs.refresh_rate_type = DRRS_HIGH_RR; - drm_dbg_kms(&dev_priv->drm, - "seamless DRRS supported for eDP panel.\n"); - return downclock_mode; + INIT_DELAYED_WORK(&crtc->drrs.work, intel_drrs_downclock_work); + mutex_init(&crtc->drrs.mutex); + crtc->drrs.cpu_transcoder = INVALID_TRANSCODER; } diff --git a/drivers/gpu/drm/i915/display/intel_drrs.h b/drivers/gpu/drm/i915/display/intel_drrs.h index 9ec9c447211a..3ad1be1ad9c1 100644 --- a/drivers/gpu/drm/i915/display/intel_drrs.h +++ b/drivers/gpu/drm/i915/display/intel_drrs.h @@ -8,29 +8,21 @@ #include <linux/types.h> +enum drrs_type; struct drm_i915_private; struct intel_atomic_state; struct intel_crtc; struct intel_crtc_state; struct intel_connector; -struct intel_dp; -void intel_drrs_enable(struct intel_dp *intel_dp, - const struct intel_crtc_state *crtc_state); -void intel_drrs_disable(struct intel_dp *intel_dp, - const struct intel_crtc_state *crtc_state); -void intel_drrs_update(struct intel_dp *intel_dp, - const struct intel_crtc_state *crtc_state); +const char *intel_drrs_type_str(enum drrs_type drrs_type); +bool intel_drrs_is_active(struct intel_crtc *crtc); +void intel_drrs_activate(const struct intel_crtc_state *crtc_state); +void intel_drrs_deactivate(const struct intel_crtc_state *crtc_state); void intel_drrs_invalidate(struct drm_i915_private *dev_priv, unsigned int frontbuffer_bits); void intel_drrs_flush(struct drm_i915_private *dev_priv, unsigned int frontbuffer_bits); -void intel_drrs_page_flip(struct intel_atomic_state *state, - struct intel_crtc *crtc); -void intel_drrs_compute_config(struct intel_dp *intel_dp, - struct intel_crtc_state *pipe_config, - int output_bpp, bool constant_n); -struct drm_display_mode *intel_drrs_init(struct intel_connector *connector, - struct drm_display_mode *fixed_mode); +void intel_crtc_drrs_init(struct intel_crtc *crtc); #endif /* __INTEL_DRRS_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_dsb.c b/drivers/gpu/drm/i915/display/intel_dsb.c index b34a67309976..c4affcb216fd 100644 --- a/drivers/gpu/drm/i915/display/intel_dsb.c +++ b/drivers/gpu/drm/i915/display/intel_dsb.c @@ -283,14 +283,12 @@ void intel_dsb_prepare(struct intel_crtc_state *crtc_state) obj = i915_gem_object_create_internal(i915, DSB_BUF_SIZE); if (IS_ERR(obj)) { - drm_err(&i915->drm, "Gem object creation failed\n"); kfree(dsb); goto out; } vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, 0); if (IS_ERR(vma)) { - drm_err(&i915->drm, "Vma creation failed\n"); i915_gem_object_put(obj); kfree(dsb); goto out; @@ -298,7 +296,6 @@ void intel_dsb_prepare(struct intel_crtc_state *crtc_state) buf = i915_gem_object_pin_map_unlocked(vma->obj, I915_MAP_WC); if (IS_ERR(buf)) { - drm_err(&i915->drm, "Command buffer creation failed\n"); i915_vma_unpin_and_release(&vma, I915_VMA_RELEASE_MAP); kfree(dsb); goto out; @@ -311,6 +308,10 @@ void intel_dsb_prepare(struct intel_crtc_state *crtc_state) dsb->ins_start_offset = 0; crtc_state->dsb = dsb; out: + if (!crtc_state->dsb) + drm_info(&i915->drm, + "DSB queue setup failed, will fallback to MMIO for display HW programming\n"); + intel_runtime_pm_put(&i915->runtime_pm, wakeref); } diff --git a/drivers/gpu/drm/i915/display/intel_dsi.c b/drivers/gpu/drm/i915/display/intel_dsi.c index a50422e03a7e..389a8c24cdc1 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi.c +++ b/drivers/gpu/drm/i915/display/intel_dsi.c @@ -34,26 +34,7 @@ int intel_dsi_tlpx_ns(const struct intel_dsi *intel_dsi) int intel_dsi_get_modes(struct drm_connector *connector) { - struct drm_i915_private *i915 = to_i915(connector->dev); - struct intel_connector *intel_connector = to_intel_connector(connector); - struct drm_display_mode *mode; - - drm_dbg_kms(&i915->drm, "\n"); - - if (!intel_connector->panel.fixed_mode) { - drm_dbg_kms(&i915->drm, "no fixed mode\n"); - return 0; - } - - mode = drm_mode_duplicate(connector->dev, - intel_connector->panel.fixed_mode); - if (!mode) { - drm_dbg_kms(&i915->drm, "drm_mode_duplicate failed\n"); - return 0; - } - - drm_mode_probed_add(connector, mode); - return 1; + return intel_panel_get_modes(to_intel_connector(connector)); } enum drm_mode_status intel_dsi_mode_valid(struct drm_connector *connector, @@ -61,7 +42,8 @@ enum drm_mode_status intel_dsi_mode_valid(struct drm_connector *connector, { struct drm_i915_private *dev_priv = to_i915(connector->dev); struct intel_connector *intel_connector = to_intel_connector(connector); - const struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode; + const struct drm_display_mode *fixed_mode = + intel_panel_fixed_mode(intel_connector, mode); int max_dotclk = to_i915(connector->dev)->max_dotclk_freq; enum drm_mode_status status; diff --git a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c index 6b4a27372c82..f370e9c4350d 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c +++ b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c @@ -30,6 +30,7 @@ #include <linux/pinctrl/consumer.h> #include <linux/pinctrl/machine.h> #include <linux/slab.h> +#include <linux/string_helpers.h> #include <asm/unaligned.h> @@ -686,9 +687,9 @@ void intel_dsi_log_params(struct intel_dsi *intel_dsi) intel_dsi->burst_mode_ratio); drm_dbg_kms(&i915->drm, "Reset timer %d\n", intel_dsi->rst_timer_val); drm_dbg_kms(&i915->drm, "Eot %s\n", - enableddisabled(intel_dsi->eotp_pkt)); + str_enabled_disabled(intel_dsi->eotp_pkt)); drm_dbg_kms(&i915->drm, "Clockstop %s\n", - enableddisabled(!intel_dsi->clock_stop)); + str_enabled_disabled(!intel_dsi->clock_stop)); drm_dbg_kms(&i915->drm, "Mode %s\n", intel_dsi->operation_mode ? "command" : "video"); if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) @@ -715,7 +716,7 @@ void intel_dsi_log_params(struct intel_dsi *intel_dsi) drm_dbg_kms(&i915->drm, "HS to LP Clock Count 0x%x\n", intel_dsi->clk_hs_to_lp_count); drm_dbg_kms(&i915->drm, "BTA %s\n", - enableddisabled(!(intel_dsi->video_frmt_cfg_bits & DISABLE_VIDEO_BTA))); + str_enabled_disabled(!(intel_dsi->video_frmt_cfg_bits & DISABLE_VIDEO_BTA))); } bool intel_dsi_vbt_init(struct intel_dsi *intel_dsi, u16 panel_id) diff --git a/drivers/gpu/drm/i915/display/intel_dvo.c b/drivers/gpu/drm/i915/display/intel_dvo.c index 2eeb209afc64..5572e43026e4 100644 --- a/drivers/gpu/drm/i915/display/intel_dvo.c +++ b/drivers/gpu/drm/i915/display/intel_dvo.c @@ -226,7 +226,7 @@ intel_dvo_mode_valid(struct drm_connector *connector, struct intel_connector *intel_connector = to_intel_connector(connector); struct intel_dvo *intel_dvo = intel_attached_dvo(intel_connector); const struct drm_display_mode *fixed_mode = - intel_connector->panel.fixed_mode; + intel_panel_fixed_mode(intel_connector, mode); int max_dotclk = to_i915(connector->dev)->max_dotclk_freq; int target_clock = mode->clock; @@ -257,9 +257,9 @@ static int intel_dvo_compute_config(struct intel_encoder *encoder, { struct intel_dvo *intel_dvo = enc_to_dvo(encoder); struct intel_connector *connector = to_intel_connector(conn_state->connector); - const struct drm_display_mode *fixed_mode = - intel_dvo->attached_connector->panel.fixed_mode; struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; + const struct drm_display_mode *fixed_mode = + intel_panel_fixed_mode(intel_dvo->attached_connector, adjusted_mode); /* * If we have timings from the BIOS for the panel, put them in @@ -333,8 +333,6 @@ intel_dvo_detect(struct drm_connector *connector, bool force) static int intel_dvo_get_modes(struct drm_connector *connector) { struct drm_i915_private *dev_priv = to_i915(connector->dev); - const struct drm_display_mode *fixed_mode = - to_intel_connector(connector)->panel.fixed_mode; int num_modes; /* @@ -348,17 +346,7 @@ static int intel_dvo_get_modes(struct drm_connector *connector) if (num_modes) return num_modes; - if (fixed_mode) { - struct drm_display_mode *mode; - - mode = drm_mode_duplicate(connector->dev, fixed_mode); - if (mode) { - drm_mode_probed_add(connector, mode); - num_modes++; - } - } - - return num_modes; + return intel_panel_get_modes(to_intel_connector(connector)); } static const struct drm_connector_funcs intel_dvo_connector_funcs = { @@ -390,27 +378,6 @@ static const struct drm_encoder_funcs intel_dvo_enc_funcs = { .destroy = intel_dvo_enc_destroy, }; -/* - * Attempts to get a fixed panel timing for LVDS (currently only the i830). - * - * Other chips with DVO LVDS will need to extend this to deal with the LVDS - * chip being on DVOB/C and having multiple pipes. - */ -static struct drm_display_mode * -intel_dvo_get_current_mode(struct intel_encoder *encoder) -{ - struct drm_display_mode *mode; - - mode = intel_encoder_current_mode(encoder); - if (mode) { - DRM_DEBUG_KMS("using current (BIOS) mode: "); - drm_mode_debug_printmodeline(mode); - mode->type |= DRM_MODE_TYPE_PREFERRED; - } - - return mode; -} - static enum port intel_dvo_port(i915_reg_t dvo_reg) { if (i915_mmio_reg_equal(dvo_reg, DVOA)) @@ -561,9 +528,11 @@ void intel_dvo_init(struct drm_i915_private *dev_priv) * headers, likely), so for now, just get the current * mode being output through DVO. */ - intel_panel_init(&intel_connector->panel, - intel_dvo_get_current_mode(intel_encoder), - NULL); + intel_panel_add_encoder_fixed_mode(intel_connector, + intel_encoder); + + intel_panel_init(intel_connector); + intel_dvo->panel_wants_dither = true; } diff --git a/drivers/gpu/drm/i915/display/intel_fb.c b/drivers/gpu/drm/i915/display/intel_fb.c index 23cfe2e5ce2a..e94923e9dbb1 100644 --- a/drivers/gpu/drm/i915/display/intel_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fb.c @@ -107,6 +107,21 @@ static const struct drm_format_info gen12_ccs_cc_formats[] = { .hsub = 1, .vsub = 1, .has_alpha = true }, }; +static const struct drm_format_info gen12_flat_ccs_cc_formats[] = { + { .format = DRM_FORMAT_XRGB8888, .depth = 24, .num_planes = 2, + .char_per_block = { 4, 0 }, .block_w = { 1, 2 }, .block_h = { 1, 1 }, + .hsub = 1, .vsub = 1, }, + { .format = DRM_FORMAT_XBGR8888, .depth = 24, .num_planes = 2, + .char_per_block = { 4, 0 }, .block_w = { 1, 2 }, .block_h = { 1, 1 }, + .hsub = 1, .vsub = 1, }, + { .format = DRM_FORMAT_ARGB8888, .depth = 32, .num_planes = 2, + .char_per_block = { 4, 0 }, .block_w = { 1, 2 }, .block_h = { 1, 1 }, + .hsub = 1, .vsub = 1, .has_alpha = true }, + { .format = DRM_FORMAT_ABGR8888, .depth = 32, .num_planes = 2, + .char_per_block = { 4, 0 }, .block_w = { 1, 2 }, .block_h = { 1, 1 }, + .hsub = 1, .vsub = 1, .has_alpha = true }, +}; + struct intel_modifier_desc { u64 modifier; struct { @@ -135,11 +150,32 @@ struct intel_modifier_desc { INTEL_PLANE_CAP_CCS_MC) #define INTEL_PLANE_CAP_TILING_MASK (INTEL_PLANE_CAP_TILING_X | \ INTEL_PLANE_CAP_TILING_Y | \ - INTEL_PLANE_CAP_TILING_Yf) + INTEL_PLANE_CAP_TILING_Yf | \ + INTEL_PLANE_CAP_TILING_4) #define INTEL_PLANE_CAP_TILING_NONE 0 static const struct intel_modifier_desc intel_modifiers[] = { { + .modifier = I915_FORMAT_MOD_4_TILED_DG2_MC_CCS, + .display_ver = { 13, 13 }, + .plane_caps = INTEL_PLANE_CAP_TILING_4 | INTEL_PLANE_CAP_CCS_MC, + }, { + .modifier = I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC, + .display_ver = { 13, 13 }, + .plane_caps = INTEL_PLANE_CAP_TILING_4 | INTEL_PLANE_CAP_CCS_RC_CC, + + .ccs.cc_planes = BIT(1), + + FORMAT_OVERRIDE(gen12_flat_ccs_cc_formats), + }, { + .modifier = I915_FORMAT_MOD_4_TILED_DG2_RC_CCS, + .display_ver = { 13, 13 }, + .plane_caps = INTEL_PLANE_CAP_TILING_4 | INTEL_PLANE_CAP_CCS_RC, + }, { + .modifier = I915_FORMAT_MOD_4_TILED, + .display_ver = { 13, 13 }, + .plane_caps = INTEL_PLANE_CAP_TILING_4, + }, { .modifier = I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS, .display_ver = { 12, 13 }, .plane_caps = INTEL_PLANE_CAP_TILING_Y | INTEL_PLANE_CAP_CCS_MC, @@ -380,17 +416,13 @@ bool intel_fb_plane_supports_modifier(struct intel_plane *plane, u64 modifier) static bool format_is_yuv_semiplanar(const struct intel_modifier_desc *md, const struct drm_format_info *info) { - int yuv_planes; - if (!info->is_yuv) return false; - if (plane_caps_contain_any(md->plane_caps, INTEL_PLANE_CAP_CCS_MASK)) - yuv_planes = 4; + if (hweight8(md->ccs.planar_aux_planes) == 2) + return info->num_planes == 4; else - yuv_planes = 2; - - return info->num_planes == yuv_planes; + return info->num_planes == 2; } /** @@ -515,12 +547,13 @@ static unsigned int gen12_ccs_aux_stride(struct intel_framebuffer *fb, int ccs_p int skl_main_to_aux_plane(const struct drm_framebuffer *fb, int main_plane) { + const struct intel_modifier_desc *md = lookup_modifier(fb->modifier); struct drm_i915_private *i915 = to_i915(fb->dev); - if (intel_fb_is_ccs_modifier(fb->modifier)) + if (md->ccs.packed_aux_planes | md->ccs.planar_aux_planes) return main_to_ccs_plane(fb, main_plane); else if (DISPLAY_VER(i915) < 11 && - intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier)) + format_is_yuv_semiplanar(md, fb->format)) return 1; else return 0; @@ -545,6 +578,15 @@ intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane) return 128; else return 512; + case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS: + case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC: + case I915_FORMAT_MOD_4_TILED_DG2_MC_CCS: + case I915_FORMAT_MOD_4_TILED: + /* + * Each 4K tile consists of 64B(8*8) subtiles, with + * same shape as Y Tile(i.e 4*16B OWords) + */ + return 128; case I915_FORMAT_MOD_Y_TILED_CCS: if (intel_fb_is_ccs_aux_plane(fb, color_plane)) return 128; @@ -650,6 +692,7 @@ static unsigned int intel_fb_modifier_to_tiling(u64 fb_modifier) return I915_TILING_Y; case INTEL_PLANE_CAP_TILING_X: return I915_TILING_X; + case INTEL_PLANE_CAP_TILING_4: case INTEL_PLANE_CAP_TILING_Yf: case INTEL_PLANE_CAP_TILING_NONE: return I915_TILING_NONE; @@ -737,8 +780,13 @@ unsigned int intel_surf_alignment(const struct drm_framebuffer *fb, case I915_FORMAT_MOD_Y_TILED_CCS: case I915_FORMAT_MOD_Yf_TILED_CCS: case I915_FORMAT_MOD_Y_TILED: + case I915_FORMAT_MOD_4_TILED: case I915_FORMAT_MOD_Yf_TILED: return 1 * 1024 * 1024; + case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS: + case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC: + case I915_FORMAT_MOD_4_TILED_DG2_MC_CCS: + return 16 * 1024; default: MISSING_CASE(fb->modifier); return 0; diff --git a/drivers/gpu/drm/i915/display/intel_fb.h b/drivers/gpu/drm/i915/display/intel_fb.h index ba9df8986c1e..12386f13a4e0 100644 --- a/drivers/gpu/drm/i915/display/intel_fb.h +++ b/drivers/gpu/drm/i915/display/intel_fb.h @@ -27,6 +27,7 @@ struct intel_plane_state; #define INTEL_PLANE_CAP_TILING_X BIT(3) #define INTEL_PLANE_CAP_TILING_Y BIT(4) #define INTEL_PLANE_CAP_TILING_Yf BIT(5) +#define INTEL_PLANE_CAP_TILING_4 BIT(6) bool intel_fb_is_ccs_modifier(u64 modifier); bool intel_fb_is_rc_ccs_cc_modifier(u64 modifier); diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c index 87f4af3fd523..670835318a1f 100644 --- a/drivers/gpu/drm/i915/display/intel_fbc.c +++ b/drivers/gpu/drm/i915/display/intel_fbc.c @@ -38,9 +38,12 @@ * forcibly disable it to allow proper screen updates. */ +#include <linux/string_helpers.h> + #include <drm/drm_fourcc.h> #include "i915_drv.h" +#include "i915_utils.h" #include "i915_vgpu.h" #include "intel_cdclk.h" #include "intel_de.h" @@ -87,7 +90,6 @@ struct intel_fbc { * with stolen_lock. */ struct mutex lock; - unsigned int possible_framebuffer_bits; unsigned int busy_bits; struct drm_mm_node compressed_fb; @@ -665,6 +667,10 @@ static bool intel_fbc_is_compressing(struct intel_fbc *fbc) static void intel_fbc_nuke(struct intel_fbc *fbc) { + struct drm_i915_private *i915 = fbc->i915; + + drm_WARN_ON(&i915->drm, fbc->flip_pending); + trace_intel_fbc_nuke(fbc->state.plane); fbc->funcs->nuke(fbc); @@ -946,6 +952,7 @@ static bool tiling_is_valid(const struct intel_plane_state *plane_state) case I915_FORMAT_MOD_Y_TILED: case I915_FORMAT_MOD_Yf_TILED: return DISPLAY_VER(i915) >= 9; + case I915_FORMAT_MOD_4_TILED: case I915_FORMAT_MOD_X_TILED: return true; default: @@ -966,6 +973,7 @@ static void intel_fbc_update_state(struct intel_atomic_state *state, struct intel_fbc_state *fbc_state = &fbc->state; WARN_ON(plane_state->no_fbc_reason); + WARN_ON(fbc_state->plane && fbc_state->plane != plane); fbc_state->plane = plane; @@ -1270,6 +1278,8 @@ static void __intel_fbc_disable(struct intel_fbc *fbc) __intel_fbc_cleanup_cfb(fbc); fbc->state.plane = NULL; + fbc->flip_pending = false; + fbc->busy_bits = 0; } static void __intel_fbc_post_update(struct intel_fbc *fbc) @@ -1313,7 +1323,7 @@ static unsigned int intel_fbc_get_frontbuffer_bit(struct intel_fbc *fbc) if (fbc->state.plane) return fbc->state.plane->frontbuffer_bit; else - return fbc->possible_framebuffer_bits; + return 0; } static void __intel_fbc_invalidate(struct intel_fbc *fbc, @@ -1325,11 +1335,14 @@ static void __intel_fbc_invalidate(struct intel_fbc *fbc, mutex_lock(&fbc->lock); - fbc->busy_bits |= intel_fbc_get_frontbuffer_bit(fbc) & frontbuffer_bits; + frontbuffer_bits &= intel_fbc_get_frontbuffer_bit(fbc); + if (!frontbuffer_bits) + goto out; - if (fbc->state.plane && fbc->busy_bits) - intel_fbc_deactivate(fbc, "frontbuffer write"); + fbc->busy_bits |= frontbuffer_bits; + intel_fbc_deactivate(fbc, "frontbuffer write"); +out: mutex_unlock(&fbc->lock); } @@ -1351,18 +1364,22 @@ static void __intel_fbc_flush(struct intel_fbc *fbc, { mutex_lock(&fbc->lock); + frontbuffer_bits &= intel_fbc_get_frontbuffer_bit(fbc); + if (!frontbuffer_bits) + goto out; + fbc->busy_bits &= ~frontbuffer_bits; if (origin == ORIGIN_FLIP || origin == ORIGIN_CURSOR_UPDATE) goto out; - if (!fbc->busy_bits && fbc->state.plane && - (frontbuffer_bits & intel_fbc_get_frontbuffer_bit(fbc))) { - if (fbc->active) - intel_fbc_nuke(fbc); - else if (!fbc->flip_pending) - __intel_fbc_post_update(fbc); - } + if (fbc->busy_bits || fbc->flip_pending) + goto out; + + if (fbc->active) + intel_fbc_nuke(fbc); + else + intel_fbc_activate(fbc); out: mutex_unlock(&fbc->lock); @@ -1500,25 +1517,6 @@ void intel_fbc_update(struct intel_atomic_state *state, } } -/** - * intel_fbc_global_disable - globally disable FBC - * @i915: i915 device instance - * - * This function disables FBC regardless of which CRTC is associated with it. - */ -void intel_fbc_global_disable(struct drm_i915_private *i915) -{ - struct intel_fbc *fbc; - enum intel_fbc_id fbc_id; - - for_each_intel_fbc(i915, fbc, fbc_id) { - mutex_lock(&fbc->lock); - if (fbc->state.plane) - __intel_fbc_disable(fbc); - mutex_unlock(&fbc->lock); - } -} - static void intel_fbc_underrun_work_fn(struct work_struct *work) { struct intel_fbc *fbc = container_of(work, typeof(*fbc), underrun_work); @@ -1640,7 +1638,7 @@ static int intel_sanitize_fbc_option(struct drm_i915_private *i915) static bool need_fbc_vtd_wa(struct drm_i915_private *i915) { /* WaFbcTurnOffFbcWhenHyperVisorIsUsed:skl,bxt */ - if (intel_vtd_active(i915) && + if (i915_vtd_active(i915) && (IS_SKYLAKE(i915) || IS_BROXTON(i915))) { drm_info(&i915->drm, "Disabling framebuffer compression (FBC) to prevent screen flicker with VT-d enabled\n"); @@ -1652,11 +1650,7 @@ static bool need_fbc_vtd_wa(struct drm_i915_private *i915) void intel_fbc_add_plane(struct intel_fbc *fbc, struct intel_plane *plane) { - if (!fbc) - return; - plane->fbc = fbc; - fbc->possible_framebuffer_bits |= plane->frontbuffer_bit; } static struct intel_fbc *intel_fbc_create(struct drm_i915_private *i915, @@ -1709,22 +1703,26 @@ void intel_fbc_init(struct drm_i915_private *i915) drm_dbg_kms(&i915->drm, "Sanitized enable_fbc value: %d\n", i915->params.enable_fbc); - for_each_fbc_id(i915, fbc_id) { - struct intel_fbc *fbc; + for_each_fbc_id(i915, fbc_id) + i915->fbc[fbc_id] = intel_fbc_create(i915, fbc_id); +} - fbc = intel_fbc_create(i915, fbc_id); - if (!fbc) - continue; +/** + * intel_fbc_sanitize - Sanitize FBC + * @i915: the i915 device + * + * Make sure FBC is initially disabled since we have no + * idea eg. into which parts of stolen it might be scribbling + * into. + */ +void intel_fbc_sanitize(struct drm_i915_private *i915) +{ + struct intel_fbc *fbc; + enum intel_fbc_id fbc_id; - /* - * We still don't have any sort of hardware state readout - * for FBC, so deactivate it in case the BIOS activated it - * to make sure software matches the hardware state. - */ + for_each_intel_fbc(i915, fbc, fbc_id) { if (intel_fbc_hw_is_active(fbc)) intel_fbc_hw_deactivate(fbc); - - i915->fbc[fbc->id] = fbc; } } @@ -1743,7 +1741,7 @@ static int intel_fbc_debugfs_status_show(struct seq_file *m, void *unused) if (fbc->active) { seq_puts(m, "FBC enabled\n"); seq_printf(m, "Compressing: %s\n", - yesno(intel_fbc_is_compressing(fbc))); + str_yes_no(intel_fbc_is_compressing(fbc))); } else { seq_printf(m, "FBC disabled: %s\n", fbc->no_fbc_reason); } diff --git a/drivers/gpu/drm/i915/display/intel_fbc.h b/drivers/gpu/drm/i915/display/intel_fbc.h index 8c5a7339a27f..db60143295ec 100644 --- a/drivers/gpu/drm/i915/display/intel_fbc.h +++ b/drivers/gpu/drm/i915/display/intel_fbc.h @@ -30,10 +30,10 @@ void intel_fbc_post_update(struct intel_atomic_state *state, struct intel_crtc *crtc); void intel_fbc_init(struct drm_i915_private *dev_priv); void intel_fbc_cleanup(struct drm_i915_private *dev_priv); +void intel_fbc_sanitize(struct drm_i915_private *dev_priv); void intel_fbc_update(struct intel_atomic_state *state, struct intel_crtc *crtc); void intel_fbc_disable(struct intel_crtc *crtc); -void intel_fbc_global_disable(struct drm_i915_private *dev_priv); void intel_fbc_invalidate(struct drm_i915_private *dev_priv, unsigned int frontbuffer_bits, enum fb_op_origin origin); diff --git a/drivers/gpu/drm/i915/display/intel_fdi.c b/drivers/gpu/drm/i915/display/intel_fdi.c index 4e4b43669b14..67d2484afbaa 100644 --- a/drivers/gpu/drm/i915/display/intel_fdi.c +++ b/drivers/gpu/drm/i915/display/intel_fdi.c @@ -3,6 +3,8 @@ * Copyright © 2020 Intel Corporation */ +#include <linux/string_helpers.h> + #include "intel_atomic.h" #include "intel_crtc.h" #include "intel_ddi.h" @@ -34,7 +36,7 @@ static void assert_fdi_tx(struct drm_i915_private *dev_priv, } I915_STATE_WARN(cur_state != state, "FDI TX state assertion failure (expected %s, current %s)\n", - onoff(state), onoff(cur_state)); + str_on_off(state), str_on_off(cur_state)); } void assert_fdi_tx_enabled(struct drm_i915_private *i915, enum pipe pipe) @@ -55,7 +57,7 @@ static void assert_fdi_rx(struct drm_i915_private *dev_priv, cur_state = intel_de_read(dev_priv, FDI_RX_CTL(pipe)) & FDI_RX_ENABLE; I915_STATE_WARN(cur_state != state, "FDI RX state assertion failure (expected %s, current %s)\n", - onoff(state), onoff(cur_state)); + str_on_off(state), str_on_off(cur_state)); } void assert_fdi_rx_enabled(struct drm_i915_private *i915, enum pipe pipe) @@ -93,7 +95,7 @@ static void assert_fdi_rx_pll(struct drm_i915_private *i915, cur_state = intel_de_read(i915, FDI_RX_CTL(pipe)) & FDI_RX_PLL_ENABLE; I915_STATE_WARN(cur_state != state, "FDI RX PLL assertion failure (expected %s, current %s)\n", - onoff(state), onoff(cur_state)); + str_on_off(state), str_on_off(cur_state)); } void assert_fdi_rx_pll_enabled(struct drm_i915_private *i915, enum pipe pipe) diff --git a/drivers/gpu/drm/i915/display/intel_gmbus.c b/drivers/gpu/drm/i915/display/intel_gmbus.c index 2fad03250661..21281a7bdc17 100644 --- a/drivers/gpu/drm/i915/display/intel_gmbus.c +++ b/drivers/gpu/drm/i915/display/intel_gmbus.c @@ -38,6 +38,16 @@ #include "intel_display_types.h" #include "intel_gmbus.h" +struct intel_gmbus { + struct i2c_adapter adapter; +#define GMBUS_FORCE_BIT_RETRY (1U << 31) + u32 force_bit; + u32 reg0; + i915_reg_t gpio_reg; + struct i2c_algo_bit_data bit_algo; + struct drm_i915_private *dev_priv; +}; + struct gmbus_pin { const char *name; enum i915_gpio gpio; @@ -106,51 +116,47 @@ static const struct gmbus_pin gmbus_pins_dg2[] = { [GMBUS_PIN_9_TC1_ICP] = { "tc1", GPIOJ }, }; -/* pin is expected to be valid */ -static const struct gmbus_pin *get_gmbus_pin(struct drm_i915_private *dev_priv, +static const struct gmbus_pin *get_gmbus_pin(struct drm_i915_private *i915, unsigned int pin) { - if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG2) - return &gmbus_pins_dg2[pin]; - else if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG1) - return &gmbus_pins_dg1[pin]; - else if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) - return &gmbus_pins_icp[pin]; - else if (HAS_PCH_CNP(dev_priv)) - return &gmbus_pins_cnp[pin]; - else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) - return &gmbus_pins_bxt[pin]; - else if (DISPLAY_VER(dev_priv) == 9) - return &gmbus_pins_skl[pin]; - else if (IS_BROADWELL(dev_priv)) - return &gmbus_pins_bdw[pin]; - else - return &gmbus_pins[pin]; -} - -bool intel_gmbus_is_valid_pin(struct drm_i915_private *dev_priv, - unsigned int pin) -{ - unsigned int size; + const struct gmbus_pin *pins; + size_t size; - if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG2) + if (INTEL_PCH_TYPE(i915) >= PCH_DG2) { + pins = gmbus_pins_dg2; size = ARRAY_SIZE(gmbus_pins_dg2); - else if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG1) + } else if (INTEL_PCH_TYPE(i915) >= PCH_DG1) { + pins = gmbus_pins_dg1; size = ARRAY_SIZE(gmbus_pins_dg1); - else if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) + } else if (INTEL_PCH_TYPE(i915) >= PCH_ICP) { + pins = gmbus_pins_icp; size = ARRAY_SIZE(gmbus_pins_icp); - else if (HAS_PCH_CNP(dev_priv)) + } else if (HAS_PCH_CNP(i915)) { + pins = gmbus_pins_cnp; size = ARRAY_SIZE(gmbus_pins_cnp); - else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) + } else if (IS_GEMINILAKE(i915) || IS_BROXTON(i915)) { + pins = gmbus_pins_bxt; size = ARRAY_SIZE(gmbus_pins_bxt); - else if (DISPLAY_VER(dev_priv) == 9) + } else if (DISPLAY_VER(i915) == 9) { + pins = gmbus_pins_skl; size = ARRAY_SIZE(gmbus_pins_skl); - else if (IS_BROADWELL(dev_priv)) + } else if (IS_BROADWELL(i915)) { + pins = gmbus_pins_bdw; size = ARRAY_SIZE(gmbus_pins_bdw); - else + } else { + pins = gmbus_pins; size = ARRAY_SIZE(gmbus_pins); + } + + if (pin >= size || !pins[pin].name) + return NULL; + + return &pins[pin]; +} - return pin < size && get_gmbus_pin(dev_priv, pin)->name; +bool intel_gmbus_is_valid_pin(struct drm_i915_private *i915, unsigned int pin) +{ + return get_gmbus_pin(i915, pin); } /* Intel GPIO access functions */ @@ -294,9 +300,7 @@ static void set_data(void *data, int state_high) static int intel_gpio_pre_xfer(struct i2c_adapter *adapter) { - struct intel_gmbus *bus = container_of(adapter, - struct intel_gmbus, - adapter); + struct intel_gmbus *bus = to_intel_gmbus(adapter); struct drm_i915_private *dev_priv = bus->dev_priv; intel_gmbus_reset(dev_priv); @@ -313,9 +317,7 @@ intel_gpio_pre_xfer(struct i2c_adapter *adapter) static void intel_gpio_post_xfer(struct i2c_adapter *adapter) { - struct intel_gmbus *bus = container_of(adapter, - struct intel_gmbus, - adapter); + struct intel_gmbus *bus = to_intel_gmbus(adapter); struct drm_i915_private *dev_priv = bus->dev_priv; set_data(bus, 1); @@ -326,14 +328,13 @@ intel_gpio_post_xfer(struct i2c_adapter *adapter) } static void -intel_gpio_setup(struct intel_gmbus *bus, unsigned int pin) +intel_gpio_setup(struct intel_gmbus *bus, i915_reg_t gpio_reg) { - struct drm_i915_private *dev_priv = bus->dev_priv; struct i2c_algo_bit_data *algo; algo = &bus->bit_algo; - bus->gpio_reg = GPIO(get_gmbus_pin(dev_priv, pin)->gpio); + bus->gpio_reg = gpio_reg; bus->adapter.algo_data = algo; algo->setsda = set_data; algo->setscl = set_clock; @@ -614,9 +615,7 @@ static int do_gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num, u32 gmbus0_source) { - struct intel_gmbus *bus = container_of(adapter, - struct intel_gmbus, - adapter); + struct intel_gmbus *bus = to_intel_gmbus(adapter); struct drm_i915_private *dev_priv = bus->dev_priv; int i = 0, inc, try = 0; int ret = 0; @@ -746,8 +745,7 @@ out: static int gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) { - struct intel_gmbus *bus = - container_of(adapter, struct intel_gmbus, adapter); + struct intel_gmbus *bus = to_intel_gmbus(adapter); struct drm_i915_private *dev_priv = bus->dev_priv; intel_wakeref_t wakeref; int ret; @@ -771,8 +769,7 @@ gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) int intel_gmbus_output_aksv(struct i2c_adapter *adapter) { - struct intel_gmbus *bus = - container_of(adapter, struct intel_gmbus, adapter); + struct intel_gmbus *bus = to_intel_gmbus(adapter); struct drm_i915_private *dev_priv = bus->dev_priv; u8 cmd = DRM_HDCP_DDC_AKSV; u8 buf[DRM_HDCP_KSV_LEN] = { 0 }; @@ -863,7 +860,6 @@ static const struct i2c_lock_operations gmbus_lock_ops = { int intel_gmbus_setup(struct drm_i915_private *dev_priv) { struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); - struct intel_gmbus *bus; unsigned int pin; int ret; @@ -880,17 +876,24 @@ int intel_gmbus_setup(struct drm_i915_private *dev_priv) init_waitqueue_head(&dev_priv->gmbus_wait_queue); for (pin = 0; pin < ARRAY_SIZE(dev_priv->gmbus); pin++) { - if (!intel_gmbus_is_valid_pin(dev_priv, pin)) + const struct gmbus_pin *gmbus_pin; + struct intel_gmbus *bus; + + gmbus_pin = get_gmbus_pin(dev_priv, pin); + if (!gmbus_pin) continue; - bus = &dev_priv->gmbus[pin]; + bus = kzalloc(sizeof(*bus), GFP_KERNEL); + if (!bus) { + ret = -ENOMEM; + goto err; + } bus->adapter.owner = THIS_MODULE; bus->adapter.class = I2C_CLASS_DDC; snprintf(bus->adapter.name, sizeof(bus->adapter.name), - "i915 gmbus %s", - get_gmbus_pin(dev_priv, pin)->name); + "i915 gmbus %s", gmbus_pin->name); bus->adapter.dev.parent = &pdev->dev; bus->dev_priv = dev_priv; @@ -911,11 +914,15 @@ int intel_gmbus_setup(struct drm_i915_private *dev_priv) if (IS_I830(dev_priv)) bus->force_bit = 1; - intel_gpio_setup(bus, pin); + intel_gpio_setup(bus, GPIO(gmbus_pin->gpio)); ret = i2c_add_adapter(&bus->adapter); - if (ret) + if (ret) { + kfree(bus); goto err; + } + + dev_priv->gmbus[pin] = bus; } intel_gmbus_reset(dev_priv); @@ -923,24 +930,19 @@ int intel_gmbus_setup(struct drm_i915_private *dev_priv) return 0; err: - while (pin--) { - if (!intel_gmbus_is_valid_pin(dev_priv, pin)) - continue; + intel_gmbus_teardown(dev_priv); - bus = &dev_priv->gmbus[pin]; - i2c_del_adapter(&bus->adapter); - } return ret; } struct i2c_adapter *intel_gmbus_get_adapter(struct drm_i915_private *dev_priv, unsigned int pin) { - if (drm_WARN_ON(&dev_priv->drm, - !intel_gmbus_is_valid_pin(dev_priv, pin))) + if (drm_WARN_ON(&dev_priv->drm, pin >= ARRAY_SIZE(dev_priv->gmbus) || + !dev_priv->gmbus[pin])) return NULL; - return &dev_priv->gmbus[pin].adapter; + return &dev_priv->gmbus[pin]->adapter; } void intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit) @@ -968,14 +970,18 @@ bool intel_gmbus_is_forced_bit(struct i2c_adapter *adapter) void intel_gmbus_teardown(struct drm_i915_private *dev_priv) { - struct intel_gmbus *bus; unsigned int pin; for (pin = 0; pin < ARRAY_SIZE(dev_priv->gmbus); pin++) { - if (!intel_gmbus_is_valid_pin(dev_priv, pin)) + struct intel_gmbus *bus; + + bus = dev_priv->gmbus[pin]; + if (!bus) continue; - bus = &dev_priv->gmbus[pin]; i2c_del_adapter(&bus->adapter); + + kfree(bus); + dev_priv->gmbus[pin] = NULL; } } diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c index e1ecf38db0ef..4de4c174a987 100644 --- a/drivers/gpu/drm/i915/display/intel_hdcp.c +++ b/drivers/gpu/drm/i915/display/intel_hdcp.c @@ -20,6 +20,7 @@ #include "intel_connector.h" #include "intel_de.h" #include "intel_display_power.h" +#include "intel_display_power_well.h" #include "intel_display_types.h" #include "intel_hdcp.h" #include "intel_pcode.h" diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index 6512f014cad4..a4a6f8bd2841 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -30,6 +30,7 @@ #include <linux/hdmi.h> #include <linux/i2c.h> #include <linux/slab.h> +#include <linux/string_helpers.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> @@ -2637,7 +2638,7 @@ bool intel_hdmi_handle_sink_scrambling(struct intel_encoder *encoder, drm_dbg_kms(&dev_priv->drm, "[CONNECTOR:%d:%s] scrambling=%s, TMDS bit clock ratio=1/%d\n", connector->base.id, connector->name, - yesno(scrambling), high_tmds_clock_ratio ? 40 : 10); + str_yes_no(scrambling), high_tmds_clock_ratio ? 40 : 10); /* Set TMDS bit clock ratio to 1/40 or 1/10, and enable/disable scrambling */ return drm_scdc_set_high_tmds_clock_ratio(adapter, diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c index 9fced37bed70..e8478161f8b9 100644 --- a/drivers/gpu/drm/i915/display/intel_lvds.c +++ b/drivers/gpu/drm/i915/display/intel_lvds.c @@ -389,7 +389,8 @@ intel_lvds_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { struct intel_connector *intel_connector = to_intel_connector(connector); - struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode; + const struct drm_display_mode *fixed_mode = + intel_panel_fixed_mode(intel_connector, mode); int max_pixclk = to_i915(connector->dev)->max_dotclk_freq; enum drm_mode_status status; @@ -475,19 +476,12 @@ static int intel_lvds_compute_config(struct intel_encoder *intel_encoder, static int intel_lvds_get_modes(struct drm_connector *connector) { struct intel_connector *intel_connector = to_intel_connector(connector); - struct drm_device *dev = connector->dev; - struct drm_display_mode *mode; /* use cached edid if we have one */ if (!IS_ERR_OR_NULL(intel_connector->edid)) return drm_add_edid_modes(connector, intel_connector->edid); - mode = drm_mode_duplicate(dev, intel_connector->panel.fixed_mode); - if (mode == NULL) - return 0; - - drm_mode_probed_add(connector, mode); - return 1; + return intel_panel_get_modes(intel_connector); } static const struct drm_connector_helper_funcs intel_lvds_connector_helper_funcs = { @@ -786,16 +780,18 @@ bool intel_is_dual_link_lvds(struct drm_i915_private *dev_priv) static bool compute_is_dual_link_lvds(struct intel_lvds_encoder *lvds_encoder) { - struct drm_device *dev = lvds_encoder->base.base.dev; + struct drm_i915_private *dev_priv = to_i915(lvds_encoder->base.base.dev); + struct intel_connector *connector = lvds_encoder->attached_connector; + const struct drm_display_mode *fixed_mode = + intel_panel_preferred_fixed_mode(connector); unsigned int val; - struct drm_i915_private *dev_priv = to_i915(dev); /* use the module option value if specified */ if (dev_priv->params.lvds_channel_mode > 0) return dev_priv->params.lvds_channel_mode == 2; /* single channel LVDS is limited to 112 MHz */ - if (lvds_encoder->attached_connector->panel.fixed_mode->clock > 112999) + if (fixed_mode->clock > 112999) return true; if (dmi_check_system(intel_dual_link_lvds)) @@ -833,8 +829,6 @@ void intel_lvds_init(struct drm_i915_private *dev_priv) struct intel_connector *intel_connector; struct drm_connector *connector; struct drm_encoder *encoder; - struct drm_display_mode *fixed_mode = NULL; - struct drm_display_mode *downclock_mode = NULL; struct edid *edid; i915_reg_t lvds_reg; u32 lvds; @@ -973,35 +967,30 @@ void intel_lvds_init(struct drm_i915_private *dev_priv) } intel_connector->edid = edid; - fixed_mode = intel_panel_edid_fixed_mode(intel_connector); - if (fixed_mode) - goto out; + /* Try EDID first */ + intel_panel_add_edid_fixed_modes(intel_connector, + dev_priv->vbt.drrs_type != DRRS_TYPE_NONE); /* Failed to get EDID, what about VBT? */ - fixed_mode = intel_panel_vbt_fixed_mode(intel_connector); - if (fixed_mode) - goto out; + if (!intel_panel_preferred_fixed_mode(intel_connector)) + intel_panel_add_vbt_lfp_fixed_mode(intel_connector); /* - * If we didn't get EDID, try checking if the panel is already turned - * on. If so, assume that whatever is currently programmed is the - * correct mode. + * If we didn't get a fixed mode from EDID or VBT, try checking + * if the panel is already turned on. If so, assume that + * whatever is currently programmed is the correct mode. */ - fixed_mode = intel_encoder_current_mode(intel_encoder); - if (fixed_mode) { - drm_dbg_kms(&dev_priv->drm, "using current (BIOS) mode: "); - drm_mode_debug_printmodeline(fixed_mode); - fixed_mode->type |= DRM_MODE_TYPE_PREFERRED; - } + if (!intel_panel_preferred_fixed_mode(intel_connector)) + intel_panel_add_encoder_fixed_mode(intel_connector, intel_encoder); + + mutex_unlock(&dev->mode_config.mutex); /* If we still don't have a mode after all that, give up. */ - if (!fixed_mode) + if (!intel_panel_preferred_fixed_mode(intel_connector)) goto failed; -out: - mutex_unlock(&dev->mode_config.mutex); + intel_panel_init(intel_connector); - intel_panel_init(&intel_connector->panel, fixed_mode, downclock_mode); intel_backlight_setup(intel_connector, INVALID_PIPE); lvds_encoder->is_dual_link = compute_is_dual_link_lvds(lvds_encoder); @@ -1013,8 +1002,6 @@ out: return; failed: - mutex_unlock(&dev->mode_config.mutex); - drm_dbg_kms(&dev_priv->drm, "No LVDS modes found, disabling.\n"); drm_connector_cleanup(connector); drm_encoder_cleanup(encoder); diff --git a/drivers/gpu/drm/i915/display/intel_overlay.c b/drivers/gpu/drm/i915/display/intel_overlay.c index 76845d34ad0c..ee46561b5ae8 100644 --- a/drivers/gpu/drm/i915/display/intel_overlay.c +++ b/drivers/gpu/drm/i915/display/intel_overlay.c @@ -958,19 +958,21 @@ static void update_pfit_vscale_ratio(struct intel_overlay *overlay) static int check_overlay_dst(struct intel_overlay *overlay, struct drm_intel_overlay_put_image *rec) { - const struct intel_crtc_state *pipe_config = + const struct intel_crtc_state *crtc_state = overlay->crtc->config; + struct drm_rect req, clipped; - if (rec->dst_height == 0 || rec->dst_width == 0) - return -EINVAL; + drm_rect_init(&req, rec->dst_x, rec->dst_y, + rec->dst_width, rec->dst_height); - if (rec->dst_x < pipe_config->pipe_src_w && - rec->dst_x + rec->dst_width <= pipe_config->pipe_src_w && - rec->dst_y < pipe_config->pipe_src_h && - rec->dst_y + rec->dst_height <= pipe_config->pipe_src_h) - return 0; - else + clipped = req; + drm_rect_intersect(&clipped, &crtc_state->pipe_src); + + if (!drm_rect_visible(&clipped) || + !drm_rect_equals(&clipped, &req)) return -EINVAL; + + return 0; } static int check_overlay_scaling(struct drm_intel_overlay_put_image *rec) @@ -1160,7 +1162,7 @@ int intel_overlay_put_image_ioctl(struct drm_device *dev, void *data, crtc->overlay = overlay; /* line too wide, i.e. one-line-mode */ - if (crtc->config->pipe_src_w > 1024 && + if (drm_rect_width(&crtc->config->pipe_src) > 1024 && crtc->config->gmch_pfit.control & PFIT_ENABLE) { overlay->pfit_active = true; update_pfit_vscale_ratio(overlay); diff --git a/drivers/gpu/drm/i915/display/intel_panel.c b/drivers/gpu/drm/i915/display/intel_panel.c index a0c8e43db5eb..03398feb6676 100644 --- a/drivers/gpu/drm/i915/display/intel_panel.c +++ b/drivers/gpu/drm/i915/display/intel_panel.c @@ -35,6 +35,7 @@ #include "intel_connector.h" #include "intel_de.h" #include "intel_display_types.h" +#include "intel_drrs.h" #include "intel_panel.h" bool intel_panel_use_ssc(struct drm_i915_private *i915) @@ -45,10 +46,83 @@ bool intel_panel_use_ssc(struct drm_i915_private *i915) && !(i915->quirks & QUIRK_LVDS_SSC_DISABLE); } +const struct drm_display_mode * +intel_panel_preferred_fixed_mode(struct intel_connector *connector) +{ + return list_first_entry_or_null(&connector->panel.fixed_modes, + struct drm_display_mode, head); +} + +const struct drm_display_mode * +intel_panel_fixed_mode(struct intel_connector *connector, + const struct drm_display_mode *mode) +{ + const struct drm_display_mode *fixed_mode, *best_mode = NULL; + int vrefresh = drm_mode_vrefresh(mode); + + /* pick the fixed_mode that is closest in terms of vrefresh */ + list_for_each_entry(fixed_mode, &connector->panel.fixed_modes, head) { + if (!best_mode || + abs(drm_mode_vrefresh(fixed_mode) - vrefresh) < + abs(drm_mode_vrefresh(best_mode) - vrefresh)) + best_mode = fixed_mode; + } + + return best_mode; +} + +const struct drm_display_mode * +intel_panel_downclock_mode(struct intel_connector *connector, + const struct drm_display_mode *adjusted_mode) +{ + const struct drm_display_mode *fixed_mode, *best_mode = NULL; + int vrefresh = drm_mode_vrefresh(adjusted_mode); + + /* pick the fixed_mode with the lowest refresh rate */ + list_for_each_entry(fixed_mode, &connector->panel.fixed_modes, head) { + if (drm_mode_vrefresh(fixed_mode) < vrefresh) { + vrefresh = drm_mode_vrefresh(fixed_mode); + best_mode = fixed_mode; + } + } + + return best_mode; +} + +int intel_panel_get_modes(struct intel_connector *connector) +{ + const struct drm_display_mode *fixed_mode; + int num_modes = 0; + + list_for_each_entry(fixed_mode, &connector->panel.fixed_modes, head) { + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(connector->base.dev, fixed_mode); + if (mode) { + drm_mode_probed_add(&connector->base, mode); + num_modes++; + } + } + + return num_modes; +} + +enum drrs_type intel_panel_drrs_type(struct intel_connector *connector) +{ + struct drm_i915_private *i915 = to_i915(connector->base.dev); + + if (list_empty(&connector->panel.fixed_modes) || + list_is_singular(&connector->panel.fixed_modes)) + return DRRS_TYPE_NONE; + + return i915->vbt.drrs_type; +} + int intel_panel_compute_config(struct intel_connector *connector, struct drm_display_mode *adjusted_mode) { - const struct drm_display_mode *fixed_mode = connector->panel.fixed_mode; + const struct drm_display_mode *fixed_mode = + intel_panel_fixed_mode(connector, adjusted_mode); if (!fixed_mode) return 0; @@ -75,128 +149,142 @@ int intel_panel_compute_config(struct intel_connector *connector, return 0; } -static bool is_downclock_mode(const struct drm_display_mode *downclock_mode, - const struct drm_display_mode *fixed_mode) +static bool is_alt_fixed_mode(const struct drm_display_mode *mode, + const struct drm_display_mode *preferred_mode) { - return drm_mode_match(downclock_mode, fixed_mode, + return drm_mode_match(mode, preferred_mode, DRM_MODE_MATCH_TIMINGS | DRM_MODE_MATCH_FLAGS | DRM_MODE_MATCH_3D_FLAGS) && - downclock_mode->clock < fixed_mode->clock; + mode->clock != preferred_mode->clock; } -struct drm_display_mode * -intel_panel_edid_downclock_mode(struct intel_connector *connector, - const struct drm_display_mode *fixed_mode) +static void intel_panel_add_edid_alt_fixed_modes(struct intel_connector *connector) { struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - const struct drm_display_mode *scan, *best_mode = NULL; - struct drm_display_mode *downclock_mode; - int best_clock = fixed_mode->clock; + const struct drm_display_mode *preferred_mode = + intel_panel_preferred_fixed_mode(connector); + struct drm_display_mode *mode, *next; - list_for_each_entry(scan, &connector->base.probed_modes, head) { - /* - * If one mode has the same resolution with the fixed_panel - * mode while they have the different refresh rate, it means - * that the reduced downclock is found. In such - * case we can set the different FPx0/1 to dynamically select - * between low and high frequency. - */ - if (is_downclock_mode(scan, fixed_mode) && - scan->clock < best_clock) { - /* - * The downclock is already found. But we - * expect to find the lower downclock. - */ - best_clock = scan->clock; - best_mode = scan; - } - } - - if (!best_mode) - return NULL; - - downclock_mode = drm_mode_duplicate(&dev_priv->drm, best_mode); - if (!downclock_mode) - return NULL; + list_for_each_entry_safe(mode, next, &connector->base.probed_modes, head) { + if (!is_alt_fixed_mode(mode, preferred_mode)) + continue; - drm_dbg_kms(&dev_priv->drm, - "[CONNECTOR:%d:%s] using downclock mode from EDID: ", - connector->base.base.id, connector->base.name); - drm_mode_debug_printmodeline(downclock_mode); + drm_dbg_kms(&dev_priv->drm, + "[CONNECTOR:%d:%s] using alternate EDID fixed mode: " DRM_MODE_FMT "\n", + connector->base.base.id, connector->base.name, + DRM_MODE_ARG(mode)); - return downclock_mode; + list_move_tail(&mode->head, &connector->panel.fixed_modes); + } } -struct drm_display_mode * -intel_panel_edid_fixed_mode(struct intel_connector *connector) +static void intel_panel_add_edid_preferred_mode(struct intel_connector *connector) { struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - const struct drm_display_mode *scan; - struct drm_display_mode *fixed_mode; + struct drm_display_mode *scan, *fixed_mode = NULL; if (list_empty(&connector->base.probed_modes)) - return NULL; + return; - /* prefer fixed mode from EDID if available */ + /* make sure the preferred mode is first */ list_for_each_entry(scan, &connector->base.probed_modes, head) { - if ((scan->type & DRM_MODE_TYPE_PREFERRED) == 0) - continue; + if (scan->type & DRM_MODE_TYPE_PREFERRED) { + fixed_mode = scan; + break; + } + } - fixed_mode = drm_mode_duplicate(&dev_priv->drm, scan); - if (!fixed_mode) - return NULL; + if (!fixed_mode) + fixed_mode = list_first_entry(&connector->base.probed_modes, + typeof(*fixed_mode), head); - drm_dbg_kms(&dev_priv->drm, - "[CONNECTOR:%d:%s] using preferred mode from EDID: ", - connector->base.base.id, connector->base.name); - drm_mode_debug_printmodeline(fixed_mode); + drm_dbg_kms(&dev_priv->drm, + "[CONNECTOR:%d:%s] using %s EDID fixed mode: " DRM_MODE_FMT "\n", + connector->base.base.id, connector->base.name, + fixed_mode->type & DRM_MODE_TYPE_PREFERRED ? "preferred" : "first", + DRM_MODE_ARG(fixed_mode)); + + fixed_mode->type |= DRM_MODE_TYPE_PREFERRED; - return fixed_mode; + list_move_tail(&fixed_mode->head, &connector->panel.fixed_modes); +} + +static void intel_panel_destroy_probed_modes(struct intel_connector *connector) +{ + struct drm_i915_private *i915 = to_i915(connector->base.dev); + struct drm_display_mode *mode, *next; + + list_for_each_entry_safe(mode, next, &connector->base.probed_modes, head) { + list_del(&mode->head); + drm_mode_destroy(&i915->drm, mode); } +} - scan = list_first_entry(&connector->base.probed_modes, - typeof(*scan), head); +void intel_panel_add_edid_fixed_modes(struct intel_connector *connector, bool has_drrs) +{ + intel_panel_add_edid_preferred_mode(connector); + if (intel_panel_preferred_fixed_mode(connector) && has_drrs) + intel_panel_add_edid_alt_fixed_modes(connector); + intel_panel_destroy_probed_modes(connector); +} + +static void intel_panel_add_fixed_mode(struct intel_connector *connector, + struct drm_display_mode *fixed_mode, + const char *type) +{ + struct drm_i915_private *i915 = to_i915(connector->base.dev); + struct drm_display_info *info = &connector->base.display_info; - fixed_mode = drm_mode_duplicate(&dev_priv->drm, scan); if (!fixed_mode) - return NULL; + return; - fixed_mode->type |= DRM_MODE_TYPE_PREFERRED; + fixed_mode->type |= DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER; - drm_dbg_kms(&dev_priv->drm, - "[CONNECTOR:%d:%s] using first mode from EDID: ", - connector->base.base.id, connector->base.name); - drm_mode_debug_printmodeline(fixed_mode); + info->width_mm = fixed_mode->width_mm; + info->height_mm = fixed_mode->height_mm; - return fixed_mode; + drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] using %s fixed mode: " DRM_MODE_FMT "\n", + connector->base.base.id, connector->base.name, type, + DRM_MODE_ARG(fixed_mode)); + + list_add_tail(&fixed_mode->head, &connector->panel.fixed_modes); } -struct drm_display_mode * -intel_panel_vbt_fixed_mode(struct intel_connector *connector) +void intel_panel_add_vbt_lfp_fixed_mode(struct intel_connector *connector) { - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - struct drm_display_info *info = &connector->base.display_info; - struct drm_display_mode *fixed_mode; + struct drm_i915_private *i915 = to_i915(connector->base.dev); + const struct drm_display_mode *mode; - if (!dev_priv->vbt.lfp_lvds_vbt_mode) - return NULL; + mode = i915->vbt.lfp_lvds_vbt_mode; + if (!mode) + return; - fixed_mode = drm_mode_duplicate(&dev_priv->drm, - dev_priv->vbt.lfp_lvds_vbt_mode); - if (!fixed_mode) - return NULL; + intel_panel_add_fixed_mode(connector, + drm_mode_duplicate(&i915->drm, mode), + "VBT LFP"); +} - fixed_mode->type |= DRM_MODE_TYPE_PREFERRED; +void intel_panel_add_vbt_sdvo_fixed_mode(struct intel_connector *connector) +{ + struct drm_i915_private *i915 = to_i915(connector->base.dev); + const struct drm_display_mode *mode; - drm_dbg_kms(&dev_priv->drm, "[CONNECTOR:%d:%s] using mode from VBT: ", - connector->base.base.id, connector->base.name); - drm_mode_debug_printmodeline(fixed_mode); + mode = i915->vbt.sdvo_lvds_vbt_mode; + if (!mode) + return; - info->width_mm = fixed_mode->width_mm; - info->height_mm = fixed_mode->height_mm; + intel_panel_add_fixed_mode(connector, + drm_mode_duplicate(&i915->drm, mode), + "VBT SDVO"); +} - return fixed_mode; +void intel_panel_add_encoder_fixed_mode(struct intel_connector *connector, + struct intel_encoder *encoder) +{ + intel_panel_add_fixed_mode(connector, + intel_encoder_current_mode(encoder), + "current (BIOS)"); } /* adjusted_mode has been preset to be the panel's fixed mode */ @@ -205,18 +293,20 @@ static int pch_panel_fitting(struct intel_crtc_state *crtc_state, { const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; + int pipe_src_w = drm_rect_width(&crtc_state->pipe_src); + int pipe_src_h = drm_rect_height(&crtc_state->pipe_src); int x, y, width, height; /* Native modes don't need fitting */ - if (adjusted_mode->crtc_hdisplay == crtc_state->pipe_src_w && - adjusted_mode->crtc_vdisplay == crtc_state->pipe_src_h && + if (adjusted_mode->crtc_hdisplay == pipe_src_w && + adjusted_mode->crtc_vdisplay == pipe_src_h && crtc_state->output_format != INTEL_OUTPUT_FORMAT_YCBCR420) return 0; switch (conn_state->scaling_mode) { case DRM_MODE_SCALE_CENTER: - width = crtc_state->pipe_src_w; - height = crtc_state->pipe_src_h; + width = pipe_src_w; + height = pipe_src_h; x = (adjusted_mode->crtc_hdisplay - width + 1)/2; y = (adjusted_mode->crtc_vdisplay - height + 1)/2; break; @@ -224,19 +314,17 @@ static int pch_panel_fitting(struct intel_crtc_state *crtc_state, case DRM_MODE_SCALE_ASPECT: /* Scale but preserve the aspect ratio */ { - u32 scaled_width = adjusted_mode->crtc_hdisplay - * crtc_state->pipe_src_h; - u32 scaled_height = crtc_state->pipe_src_w - * adjusted_mode->crtc_vdisplay; + u32 scaled_width = adjusted_mode->crtc_hdisplay * pipe_src_h; + u32 scaled_height = pipe_src_w * adjusted_mode->crtc_vdisplay; if (scaled_width > scaled_height) { /* pillar */ - width = scaled_height / crtc_state->pipe_src_h; + width = scaled_height / pipe_src_h; if (width & 1) width++; x = (adjusted_mode->crtc_hdisplay - width + 1) / 2; y = 0; height = adjusted_mode->crtc_vdisplay; } else if (scaled_width < scaled_height) { /* letter */ - height = scaled_width / crtc_state->pipe_src_w; + height = scaled_width / pipe_src_w; if (height & 1) height++; y = (adjusted_mode->crtc_vdisplay - height + 1) / 2; @@ -251,8 +339,8 @@ static int pch_panel_fitting(struct intel_crtc_state *crtc_state, break; case DRM_MODE_SCALE_NONE: - WARN_ON(adjusted_mode->crtc_hdisplay != crtc_state->pipe_src_w); - WARN_ON(adjusted_mode->crtc_vdisplay != crtc_state->pipe_src_h); + WARN_ON(adjusted_mode->crtc_hdisplay != pipe_src_w); + WARN_ON(adjusted_mode->crtc_vdisplay != pipe_src_h); fallthrough; case DRM_MODE_SCALE_FULLSCREEN: x = y = 0; @@ -333,10 +421,10 @@ static void i965_scale_aspect(struct intel_crtc_state *crtc_state, { const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; - u32 scaled_width = adjusted_mode->crtc_hdisplay * - crtc_state->pipe_src_h; - u32 scaled_height = crtc_state->pipe_src_w * - adjusted_mode->crtc_vdisplay; + int pipe_src_w = drm_rect_width(&crtc_state->pipe_src); + int pipe_src_h = drm_rect_height(&crtc_state->pipe_src); + u32 scaled_width = adjusted_mode->crtc_hdisplay * pipe_src_h; + u32 scaled_height = pipe_src_w * adjusted_mode->crtc_vdisplay; /* 965+ is easy, it does everything in hw */ if (scaled_width > scaled_height) @@ -345,7 +433,7 @@ static void i965_scale_aspect(struct intel_crtc_state *crtc_state, else if (scaled_width < scaled_height) *pfit_control |= PFIT_ENABLE | PFIT_SCALING_LETTER; - else if (adjusted_mode->crtc_hdisplay != crtc_state->pipe_src_w) + else if (adjusted_mode->crtc_hdisplay != pipe_src_w) *pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO; } @@ -354,10 +442,10 @@ static void i9xx_scale_aspect(struct intel_crtc_state *crtc_state, u32 *border) { struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; - u32 scaled_width = adjusted_mode->crtc_hdisplay * - crtc_state->pipe_src_h; - u32 scaled_height = crtc_state->pipe_src_w * - adjusted_mode->crtc_vdisplay; + int pipe_src_w = drm_rect_width(&crtc_state->pipe_src); + int pipe_src_h = drm_rect_height(&crtc_state->pipe_src); + u32 scaled_width = adjusted_mode->crtc_hdisplay * pipe_src_h; + u32 scaled_height = pipe_src_w * adjusted_mode->crtc_vdisplay; u32 bits; /* @@ -367,12 +455,11 @@ static void i9xx_scale_aspect(struct intel_crtc_state *crtc_state, */ if (scaled_width > scaled_height) { /* pillar */ centre_horizontally(adjusted_mode, - scaled_height / - crtc_state->pipe_src_h); + scaled_height / pipe_src_h); *border = LVDS_BORDER_ENABLE; - if (crtc_state->pipe_src_h != adjusted_mode->crtc_vdisplay) { - bits = panel_fitter_scaling(crtc_state->pipe_src_h, + if (pipe_src_h != adjusted_mode->crtc_vdisplay) { + bits = panel_fitter_scaling(pipe_src_h, adjusted_mode->crtc_vdisplay); *pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | @@ -383,12 +470,11 @@ static void i9xx_scale_aspect(struct intel_crtc_state *crtc_state, } } else if (scaled_width < scaled_height) { /* letter */ centre_vertically(adjusted_mode, - scaled_width / - crtc_state->pipe_src_w); + scaled_width / pipe_src_w); *border = LVDS_BORDER_ENABLE; - if (crtc_state->pipe_src_w != adjusted_mode->crtc_hdisplay) { - bits = panel_fitter_scaling(crtc_state->pipe_src_w, + if (pipe_src_w != adjusted_mode->crtc_hdisplay) { + bits = panel_fitter_scaling(pipe_src_w, adjusted_mode->crtc_hdisplay); *pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | @@ -413,10 +499,12 @@ static int gmch_panel_fitting(struct intel_crtc_state *crtc_state, struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0; struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; + int pipe_src_w = drm_rect_width(&crtc_state->pipe_src); + int pipe_src_h = drm_rect_height(&crtc_state->pipe_src); /* Native modes don't need fitting */ - if (adjusted_mode->crtc_hdisplay == crtc_state->pipe_src_w && - adjusted_mode->crtc_vdisplay == crtc_state->pipe_src_h) + if (adjusted_mode->crtc_hdisplay == pipe_src_w && + adjusted_mode->crtc_vdisplay == pipe_src_h) goto out; switch (conn_state->scaling_mode) { @@ -425,8 +513,8 @@ static int gmch_panel_fitting(struct intel_crtc_state *crtc_state, * For centered modes, we have to calculate border widths & * heights and modify the values programmed into the CRTC. */ - centre_horizontally(adjusted_mode, crtc_state->pipe_src_w); - centre_vertically(adjusted_mode, crtc_state->pipe_src_h); + centre_horizontally(adjusted_mode, pipe_src_w); + centre_vertically(adjusted_mode, pipe_src_h); border = LVDS_BORDER_ENABLE; break; case DRM_MODE_SCALE_ASPECT: @@ -442,8 +530,8 @@ static int gmch_panel_fitting(struct intel_crtc_state *crtc_state, * Full scaling, even if it changes the aspect ratio. * Fortunately this is all done for us in hw. */ - if (crtc_state->pipe_src_h != adjusted_mode->crtc_vdisplay || - crtc_state->pipe_src_w != adjusted_mode->crtc_hdisplay) { + if (pipe_src_h != adjusted_mode->crtc_vdisplay || + pipe_src_w != adjusted_mode->crtc_hdisplay) { pfit_control |= PFIT_ENABLE; if (DISPLAY_VER(dev_priv) >= 4) pfit_control |= PFIT_SCALING_AUTO; @@ -508,7 +596,8 @@ enum drm_mode_status intel_panel_mode_valid(struct intel_connector *connector, const struct drm_display_mode *mode) { - const struct drm_display_mode *fixed_mode = connector->panel.fixed_mode; + const struct drm_display_mode *fixed_mode = + intel_panel_fixed_mode(connector, mode); if (!fixed_mode) return MODE_OK; @@ -525,29 +614,29 @@ intel_panel_mode_valid(struct intel_connector *connector, return MODE_OK; } -int intel_panel_init(struct intel_panel *panel, - struct drm_display_mode *fixed_mode, - struct drm_display_mode *downclock_mode) +int intel_panel_init(struct intel_connector *connector) { + struct intel_panel *panel = &connector->panel; + intel_backlight_init_funcs(panel); - panel->fixed_mode = fixed_mode; - panel->downclock_mode = downclock_mode; + drm_dbg_kms(connector->base.dev, + "[CONNECTOR:%d:%s] DRRS type: %s\n", + connector->base.base.id, connector->base.name, + intel_drrs_type_str(intel_panel_drrs_type(connector))); return 0; } -void intel_panel_fini(struct intel_panel *panel) +void intel_panel_fini(struct intel_connector *connector) { - struct intel_connector *intel_connector = - container_of(panel, struct intel_connector, panel); + struct intel_panel *panel = &connector->panel; + struct drm_display_mode *fixed_mode, *next; intel_backlight_destroy(panel); - if (panel->fixed_mode) - drm_mode_destroy(intel_connector->base.dev, panel->fixed_mode); - - if (panel->downclock_mode) - drm_mode_destroy(intel_connector->base.dev, - panel->downclock_mode); + list_for_each_entry_safe(fixed_mode, next, &panel->fixed_modes, head) { + list_del(&fixed_mode->head); + drm_mode_destroy(connector->base.dev, fixed_mode); + } } diff --git a/drivers/gpu/drm/i915/display/intel_panel.h b/drivers/gpu/drm/i915/display/intel_panel.h index d50b3f7e9e58..2e32bb728beb 100644 --- a/drivers/gpu/drm/i915/display/intel_panel.h +++ b/drivers/gpu/drm/i915/display/intel_panel.h @@ -9,23 +9,30 @@ #include <linux/types.h> enum drm_connector_status; +enum drrs_type; struct drm_connector; struct drm_connector_state; struct drm_display_mode; struct drm_i915_private; struct intel_connector; struct intel_crtc_state; -struct intel_panel; +struct intel_encoder; -int intel_panel_init(struct intel_panel *panel, - struct drm_display_mode *fixed_mode, - struct drm_display_mode *downclock_mode); -void intel_panel_fini(struct intel_panel *panel); +int intel_panel_init(struct intel_connector *connector); +void intel_panel_fini(struct intel_connector *connector); enum drm_connector_status intel_panel_detect(struct drm_connector *connector, bool force); bool intel_panel_use_ssc(struct drm_i915_private *i915); -void intel_panel_fixed_mode(const struct drm_display_mode *fixed_mode, - struct drm_display_mode *adjusted_mode); +const struct drm_display_mode * +intel_panel_preferred_fixed_mode(struct intel_connector *connector); +const struct drm_display_mode * +intel_panel_fixed_mode(struct intel_connector *connector, + const struct drm_display_mode *mode); +const struct drm_display_mode * +intel_panel_downclock_mode(struct intel_connector *connector, + const struct drm_display_mode *adjusted_mode); +int intel_panel_get_modes(struct intel_connector *connector); +enum drrs_type intel_panel_drrs_type(struct intel_connector *connector); enum drm_mode_status intel_panel_mode_valid(struct intel_connector *connector, const struct drm_display_mode *mode); @@ -33,12 +40,10 @@ int intel_panel_fitting(struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state); int intel_panel_compute_config(struct intel_connector *connector, struct drm_display_mode *adjusted_mode); -struct drm_display_mode * -intel_panel_edid_downclock_mode(struct intel_connector *connector, - const struct drm_display_mode *fixed_mode); -struct drm_display_mode * -intel_panel_edid_fixed_mode(struct intel_connector *connector); -struct drm_display_mode * -intel_panel_vbt_fixed_mode(struct intel_connector *connector); +void intel_panel_add_edid_fixed_modes(struct intel_connector *connector, bool has_drrs); +void intel_panel_add_vbt_lfp_fixed_mode(struct intel_connector *connector); +void intel_panel_add_vbt_sdvo_fixed_mode(struct intel_connector *connector); +void intel_panel_add_encoder_fixed_mode(struct intel_connector *connector, + struct intel_encoder *encoder); #endif /* __INTEL_PANEL_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_pch_display.c b/drivers/gpu/drm/i915/display/intel_pch_display.c index 9192769e3337..837152dca063 100644 --- a/drivers/gpu/drm/i915/display/intel_pch_display.c +++ b/drivers/gpu/drm/i915/display/intel_pch_display.c @@ -14,6 +14,23 @@ #include "intel_pps.h" #include "intel_sdvo.h" +bool intel_has_pch_trancoder(struct drm_i915_private *i915, + enum pipe pch_transcoder) +{ + return HAS_PCH_IBX(i915) || HAS_PCH_CPT(i915) || + (HAS_PCH_LPT_H(i915) && pch_transcoder == PIPE_A); +} + +enum pipe intel_crtc_pch_transcoder(struct intel_crtc *crtc) +{ + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + + if (HAS_PCH_LPT(i915)) + return PIPE_A; + else + return crtc->pipe; +} + static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv, enum pipe pipe, enum port port, i915_reg_t dp_reg) @@ -88,6 +105,67 @@ static void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv, pipe_name(pipe)); } +static void ibx_sanitize_pch_hdmi_port(struct drm_i915_private *dev_priv, + enum port port, i915_reg_t hdmi_reg) +{ + u32 val = intel_de_read(dev_priv, hdmi_reg); + + if (val & SDVO_ENABLE || + (val & SDVO_PIPE_SEL_MASK) == SDVO_PIPE_SEL(PIPE_A)) + return; + + drm_dbg_kms(&dev_priv->drm, + "Sanitizing transcoder select for HDMI %c\n", + port_name(port)); + + val &= ~SDVO_PIPE_SEL_MASK; + val |= SDVO_PIPE_SEL(PIPE_A); + + intel_de_write(dev_priv, hdmi_reg, val); +} + +static void ibx_sanitize_pch_dp_port(struct drm_i915_private *dev_priv, + enum port port, i915_reg_t dp_reg) +{ + u32 val = intel_de_read(dev_priv, dp_reg); + + if (val & DP_PORT_EN || + (val & DP_PIPE_SEL_MASK) == DP_PIPE_SEL(PIPE_A)) + return; + + drm_dbg_kms(&dev_priv->drm, + "Sanitizing transcoder select for DP %c\n", + port_name(port)); + + val &= ~DP_PIPE_SEL_MASK; + val |= DP_PIPE_SEL(PIPE_A); + + intel_de_write(dev_priv, dp_reg, val); +} + +static void ibx_sanitize_pch_ports(struct drm_i915_private *dev_priv) +{ + /* + * The BIOS may select transcoder B on some of the PCH + * ports even it doesn't enable the port. This would trip + * assert_pch_dp_disabled() and assert_pch_hdmi_disabled(). + * Sanitize the transcoder select bits to prevent that. We + * assume that the BIOS never actually enabled the port, + * because if it did we'd actually have to toggle the port + * on and back off to make the transcoder A select stick + * (see. intel_dp_link_down(), intel_disable_hdmi(), + * intel_disable_sdvo()). + */ + ibx_sanitize_pch_dp_port(dev_priv, PORT_B, PCH_DP_B); + ibx_sanitize_pch_dp_port(dev_priv, PORT_C, PCH_DP_C); + ibx_sanitize_pch_dp_port(dev_priv, PORT_D, PCH_DP_D); + + /* PCH SDVOB multiplex with HDMIB */ + ibx_sanitize_pch_hdmi_port(dev_priv, PORT_B, PCH_HDMIB); + ibx_sanitize_pch_hdmi_port(dev_priv, PORT_C, PCH_HDMIC); + ibx_sanitize_pch_hdmi_port(dev_priv, PORT_D, PCH_HDMID); +} + static void intel_pch_transcoder_set_m1_n1(struct intel_crtc *crtc, const struct intel_link_m_n *m_n) { @@ -181,7 +259,7 @@ static void ilk_enable_pch_transcoder(const struct intel_crtc_state *crtc_state) val |= TRANS_CHICKEN2_TIMING_OVERRIDE; /* Configure frame start delay to match the CPU */ val &= ~TRANS_CHICKEN2_FRAME_START_DELAY_MASK; - val |= TRANS_CHICKEN2_FRAME_START_DELAY(dev_priv->framestart_delay - 1); + val |= TRANS_CHICKEN2_FRAME_START_DELAY(crtc_state->framestart_delay - 1); intel_de_write(dev_priv, reg, val); } @@ -192,7 +270,7 @@ static void ilk_enable_pch_transcoder(const struct intel_crtc_state *crtc_state) if (HAS_PCH_IBX(dev_priv)) { /* Configure frame start delay to match the CPU */ val &= ~TRANS_FRAME_START_DELAY_MASK; - val |= TRANS_FRAME_START_DELAY(dev_priv->framestart_delay - 1); + val |= TRANS_FRAME_START_DELAY(crtc_state->framestart_delay - 1); /* * Make the BPC in transcoder be consistent with @@ -466,9 +544,11 @@ void ilk_pch_get_config(struct intel_crtc_state *crtc_state) ilk_pch_clock_get(crtc_state); } -static void lpt_enable_pch_transcoder(struct drm_i915_private *dev_priv, - enum transcoder cpu_transcoder) +static void lpt_enable_pch_transcoder(const struct intel_crtc_state *crtc_state) { + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; u32 val, pipeconf_val; /* FDI must be feeding us bits for PCH ports */ @@ -480,7 +560,7 @@ static void lpt_enable_pch_transcoder(struct drm_i915_private *dev_priv, val |= TRANS_CHICKEN2_TIMING_OVERRIDE; /* Configure frame start delay to match the CPU */ val &= ~TRANS_CHICKEN2_FRAME_START_DELAY_MASK; - val |= TRANS_CHICKEN2_FRAME_START_DELAY(dev_priv->framestart_delay - 1); + val |= TRANS_CHICKEN2_FRAME_START_DELAY(crtc_state->framestart_delay - 1); intel_de_write(dev_priv, TRANS_CHICKEN2(PIPE_A), val); val = TRANS_ENABLE; @@ -521,7 +601,6 @@ void lpt_pch_enable(struct intel_atomic_state *state, struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); const struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc); - enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; assert_pch_transcoder_disabled(dev_priv, PIPE_A); @@ -530,7 +609,7 @@ void lpt_pch_enable(struct intel_atomic_state *state, /* Set transcoder timing. */ ilk_pch_transcoder_set_timings(crtc_state, PIPE_A); - lpt_enable_pch_transcoder(dev_priv, cpu_transcoder); + lpt_enable_pch_transcoder(crtc_state); } void lpt_pch_disable(struct intel_atomic_state *state, @@ -563,3 +642,9 @@ void lpt_pch_get_config(struct intel_crtc_state *crtc_state) crtc_state->hw.adjusted_mode.crtc_clock = lpt_get_iclkip(dev_priv); } + +void intel_pch_sanitize(struct drm_i915_private *i915) +{ + if (HAS_PCH_IBX(i915)) + ibx_sanitize_pch_ports(i915); +} diff --git a/drivers/gpu/drm/i915/display/intel_pch_display.h b/drivers/gpu/drm/i915/display/intel_pch_display.h index 749473d99320..41a63413cb3d 100644 --- a/drivers/gpu/drm/i915/display/intel_pch_display.h +++ b/drivers/gpu/drm/i915/display/intel_pch_display.h @@ -6,11 +6,19 @@ #ifndef _INTEL_PCH_DISPLAY_H_ #define _INTEL_PCH_DISPLAY_H_ +#include <linux/types.h> + +enum pipe; +struct drm_i915_private; struct intel_atomic_state; struct intel_crtc; struct intel_crtc_state; struct intel_link_m_n; +bool intel_has_pch_trancoder(struct drm_i915_private *i915, + enum pipe pch_transcoder); +enum pipe intel_crtc_pch_transcoder(struct intel_crtc *crtc); + void ilk_pch_pre_enable(struct intel_atomic_state *state, struct intel_crtc *crtc); void ilk_pch_enable(struct intel_atomic_state *state, @@ -32,4 +40,6 @@ void intel_pch_transcoder_get_m1_n1(struct intel_crtc *crtc, void intel_pch_transcoder_get_m2_n2(struct intel_crtc *crtc, struct intel_link_m_n *m_n); +void intel_pch_sanitize(struct drm_i915_private *i915); + #endif diff --git a/drivers/gpu/drm/i915/display/intel_plane_initial.c b/drivers/gpu/drm/i915/display/intel_plane_initial.c index d7b1de4cc205..e207d12286b5 100644 --- a/drivers/gpu/drm/i915/display/intel_plane_initial.c +++ b/drivers/gpu/drm/i915/display/intel_plane_initial.c @@ -127,6 +127,7 @@ intel_alloc_initial_plane_obj(struct intel_crtc *crtc, case DRM_FORMAT_MOD_LINEAR: case I915_FORMAT_MOD_X_TILED: case I915_FORMAT_MOD_Y_TILED: + case I915_FORMAT_MOD_4_TILED: break; default: drm_dbg(&dev_priv->drm, diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index bff8c2d73cdf..5a55010a9b2f 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -100,11 +100,15 @@ static bool psr_global_enabled(struct intel_dp *intel_dp) static bool psr2_global_enabled(struct intel_dp *intel_dp) { + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + switch (intel_dp->psr.debug & I915_PSR_DEBUG_MODE_MASK) { case I915_PSR_DEBUG_DISABLE: case I915_PSR_DEBUG_FORCE_PSR1: return false; default: + if (i915->params.enable_psr == 1) + return false; return true; } } @@ -1217,6 +1221,7 @@ static void intel_psr_enable_locked(struct intel_dp *intel_dp, intel_dp->psr.dc3co_exit_delay = val; intel_dp->psr.dc3co_exitline = crtc_state->dc3co_exitline; intel_dp->psr.psr2_sel_fetch_enabled = crtc_state->enable_psr2_sel_fetch; + intel_dp->psr.psr2_sel_fetch_cff_enabled = false; intel_dp->psr.req_psr2_sdp_prior_scanline = crtc_state->req_psr2_sdp_prior_scanline; @@ -1432,28 +1437,42 @@ unlock: mutex_unlock(&psr->lock); } -static inline u32 man_trk_ctl_single_full_frame_bit_get(struct drm_i915_private *dev_priv) +static u32 man_trk_ctl_enable_bit_get(struct drm_i915_private *dev_priv) +{ + return IS_ALDERLAKE_P(dev_priv) ? 0 : PSR2_MAN_TRK_CTL_ENABLE; +} + +static u32 man_trk_ctl_single_full_frame_bit_get(struct drm_i915_private *dev_priv) { return IS_ALDERLAKE_P(dev_priv) ? ADLP_PSR2_MAN_TRK_CTL_SF_SINGLE_FULL_FRAME : PSR2_MAN_TRK_CTL_SF_SINGLE_FULL_FRAME; } -static inline u32 man_trk_ctl_partial_frame_bit_get(struct drm_i915_private *dev_priv) +static u32 man_trk_ctl_partial_frame_bit_get(struct drm_i915_private *dev_priv) { return IS_ALDERLAKE_P(dev_priv) ? ADLP_PSR2_MAN_TRK_CTL_SF_PARTIAL_FRAME_UPDATE : PSR2_MAN_TRK_CTL_SF_PARTIAL_FRAME_UPDATE; } +static u32 man_trk_ctl_continuos_full_frame(struct drm_i915_private *dev_priv) +{ + return IS_ALDERLAKE_P(dev_priv) ? + ADLP_PSR2_MAN_TRK_CTL_SF_CONTINUOS_FULL_FRAME : + PSR2_MAN_TRK_CTL_SF_CONTINUOS_FULL_FRAME; +} + static void psr_force_hw_tracking_exit(struct intel_dp *intel_dp) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); if (intel_dp->psr.psr2_sel_fetch_enabled) - intel_de_rmw(dev_priv, - PSR2_MAN_TRK_CTL(intel_dp->psr.transcoder), 0, - man_trk_ctl_single_full_frame_bit_get(dev_priv)); + intel_de_write(dev_priv, + PSR2_MAN_TRK_CTL(intel_dp->psr.transcoder), + man_trk_ctl_enable_bit_get(dev_priv) | + man_trk_ctl_partial_frame_bit_get(dev_priv) | + man_trk_ctl_single_full_frame_bit_get(dev_priv)); /* * Display WA #0884: skl+ @@ -1537,10 +1556,21 @@ void intel_psr2_program_plane_sel_fetch(struct intel_plane *plane, void intel_psr2_program_trans_man_trk_ctl(const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); + struct intel_encoder *encoder; if (!crtc_state->enable_psr2_sel_fetch) return; + for_each_intel_encoder_mask_with_psr(&dev_priv->drm, encoder, + crtc_state->uapi.encoder_mask) { + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + + lockdep_assert_held(&intel_dp->psr.lock); + if (intel_dp->psr.psr2_sel_fetch_cff_enabled) + return; + break; + } + intel_de_write(dev_priv, PSR2_MAN_TRK_CTL(crtc_state->cpu_transcoder), crtc_state->psr2_man_track_ctl); } @@ -1550,10 +1580,7 @@ static void psr2_man_trk_ctl_calc(struct intel_crtc_state *crtc_state, { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - u32 val = 0; - - if (!IS_ALDERLAKE_P(dev_priv)) - val = PSR2_MAN_TRK_CTL_ENABLE; + u32 val = man_trk_ctl_enable_bit_get(dev_priv); /* SF partial frame enable has to be set even on full update */ val |= man_trk_ctl_partial_frame_bit_get(dev_priv); @@ -1911,13 +1938,13 @@ static int _psr1_ready_for_pipe_update_locked(struct intel_dp *intel_dp) } /** - * intel_psr_wait_for_idle - wait for PSR be ready for a pipe update + * intel_psr_wait_for_idle_locked - wait for PSR be ready for a pipe update * @new_crtc_state: new CRTC state * * This function is expected to be called from pipe_update_start() where it is * not expected to race with PSR enable or disable. */ -void intel_psr_wait_for_idle(const struct intel_crtc_state *new_crtc_state) +void intel_psr_wait_for_idle_locked(const struct intel_crtc_state *new_crtc_state) { struct drm_i915_private *dev_priv = to_i915(new_crtc_state->uapi.crtc->dev); struct intel_encoder *encoder; @@ -1930,12 +1957,10 @@ void intel_psr_wait_for_idle(const struct intel_crtc_state *new_crtc_state) struct intel_dp *intel_dp = enc_to_intel_dp(encoder); int ret; - mutex_lock(&intel_dp->psr.lock); + lockdep_assert_held(&intel_dp->psr.lock); - if (!intel_dp->psr.enabled) { - mutex_unlock(&intel_dp->psr.lock); + if (!intel_dp->psr.enabled) continue; - } if (intel_dp->psr.psr2_enabled) ret = _psr2_ready_for_pipe_update_locked(intel_dp); @@ -1944,8 +1969,6 @@ void intel_psr_wait_for_idle(const struct intel_crtc_state *new_crtc_state) if (ret) drm_err(&dev_priv->drm, "PSR wait timed out, atomic update may fail\n"); - - mutex_unlock(&intel_dp->psr.lock); } } @@ -2122,6 +2145,27 @@ unlock: mutex_unlock(&intel_dp->psr.lock); } +static void _psr_invalidate_handle(struct intel_dp *intel_dp) +{ + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + + if (intel_dp->psr.psr2_sel_fetch_enabled) { + u32 val; + + if (intel_dp->psr.psr2_sel_fetch_cff_enabled) + return; + + val = man_trk_ctl_enable_bit_get(dev_priv) | + man_trk_ctl_partial_frame_bit_get(dev_priv) | + man_trk_ctl_continuos_full_frame(dev_priv); + intel_de_write(dev_priv, PSR2_MAN_TRK_CTL(intel_dp->psr.transcoder), val); + intel_de_write(dev_priv, CURSURFLIVE(intel_dp->psr.pipe), 0); + intel_dp->psr.psr2_sel_fetch_cff_enabled = true; + } else { + intel_psr_exit(intel_dp); + } +} + /** * intel_psr_invalidate - Invalidade PSR * @dev_priv: i915 device @@ -2158,7 +2202,7 @@ void intel_psr_invalidate(struct drm_i915_private *dev_priv, intel_dp->psr.busy_frontbuffer_bits |= pipe_frontbuffer_bits; if (pipe_frontbuffer_bits) - intel_psr_exit(intel_dp); + _psr_invalidate_handle(intel_dp); mutex_unlock(&intel_dp->psr.lock); } @@ -2190,6 +2234,42 @@ tgl_dc3co_flush_locked(struct intel_dp *intel_dp, unsigned int frontbuffer_bits, intel_dp->psr.dc3co_exit_delay); } +static void _psr_flush_handle(struct intel_dp *intel_dp) +{ + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + + if (intel_dp->psr.psr2_sel_fetch_enabled) { + if (intel_dp->psr.psr2_sel_fetch_cff_enabled) { + /* can we turn CFF off? */ + if (intel_dp->psr.busy_frontbuffer_bits == 0) { + u32 val = man_trk_ctl_enable_bit_get(dev_priv) | + man_trk_ctl_partial_frame_bit_get(dev_priv) | + man_trk_ctl_single_full_frame_bit_get(dev_priv); + + /* + * turn continuous full frame off and do a single + * full frame + */ + intel_de_write(dev_priv, PSR2_MAN_TRK_CTL(intel_dp->psr.transcoder), + val); + intel_de_write(dev_priv, CURSURFLIVE(intel_dp->psr.pipe), 0); + intel_dp->psr.psr2_sel_fetch_cff_enabled = false; + } + } else { + /* + * continuous full frame is disabled, only a single full + * frame is required + */ + psr_force_hw_tracking_exit(intel_dp); + } + } else { + psr_force_hw_tracking_exit(intel_dp); + + if (!intel_dp->psr.active && !intel_dp->psr.busy_frontbuffer_bits) + schedule_work(&intel_dp->psr.work); + } +} + /** * intel_psr_flush - Flush PSR * @dev_priv: i915 device @@ -2227,25 +2307,22 @@ void intel_psr_flush(struct drm_i915_private *dev_priv, * we have to ensure that the PSR is not activated until * intel_psr_resume() is called. */ - if (intel_dp->psr.paused) { - mutex_unlock(&intel_dp->psr.lock); - continue; - } + if (intel_dp->psr.paused) + goto unlock; if (origin == ORIGIN_FLIP || (origin == ORIGIN_CURSOR_UPDATE && !intel_dp->psr.psr2_sel_fetch_enabled)) { tgl_dc3co_flush_locked(intel_dp, frontbuffer_bits, origin); - mutex_unlock(&intel_dp->psr.lock); - continue; + goto unlock; } - /* By definition flush = invalidate + flush */ - if (pipe_frontbuffer_bits) - psr_force_hw_tracking_exit(intel_dp); + if (pipe_frontbuffer_bits == 0) + goto unlock; - if (!intel_dp->psr.active && !intel_dp->psr.busy_frontbuffer_bits) - schedule_work(&intel_dp->psr.work); + /* By definition flush = invalidate + flush */ + _psr_flush_handle(intel_dp); +unlock: mutex_unlock(&intel_dp->psr.lock); } } @@ -2436,3 +2513,51 @@ bool intel_psr_enabled(struct intel_dp *intel_dp) return ret; } + +/** + * intel_psr_lock - grab PSR lock + * @crtc_state: the crtc state + * + * This is initially meant to be used by around CRTC update, when + * vblank sensitive registers are updated and we need grab the lock + * before it to avoid vblank evasion. + */ +void intel_psr_lock(const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); + struct intel_encoder *encoder; + + if (!crtc_state->has_psr) + return; + + for_each_intel_encoder_mask_with_psr(&i915->drm, encoder, + crtc_state->uapi.encoder_mask) { + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + + mutex_lock(&intel_dp->psr.lock); + break; + } +} + +/** + * intel_psr_unlock - release PSR lock + * @crtc_state: the crtc state + * + * Release the PSR lock that was held during pipe update. + */ +void intel_psr_unlock(const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); + struct intel_encoder *encoder; + + if (!crtc_state->has_psr) + return; + + for_each_intel_encoder_mask_with_psr(&i915->drm, encoder, + crtc_state->uapi.encoder_mask) { + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + + mutex_unlock(&intel_dp->psr.lock); + break; + } +} diff --git a/drivers/gpu/drm/i915/display/intel_psr.h b/drivers/gpu/drm/i915/display/intel_psr.h index f6526d9ccfdc..2ac3a46cccc5 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.h +++ b/drivers/gpu/drm/i915/display/intel_psr.h @@ -41,7 +41,7 @@ void intel_psr_get_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config); void intel_psr_irq_handler(struct intel_dp *intel_dp, u32 psr_iir); void intel_psr_short_pulse(struct intel_dp *intel_dp); -void intel_psr_wait_for_idle(const struct intel_crtc_state *new_crtc_state); +void intel_psr_wait_for_idle_locked(const struct intel_crtc_state *new_crtc_state); bool intel_psr_enabled(struct intel_dp *intel_dp); int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, struct intel_crtc *crtc); @@ -55,4 +55,7 @@ void intel_psr2_disable_plane_sel_fetch(struct intel_plane *plane, void intel_psr_pause(struct intel_dp *intel_dp); void intel_psr_resume(struct intel_dp *intel_dp); +void intel_psr_lock(const struct intel_crtc_state *crtc_state); +void intel_psr_unlock(const struct intel_crtc_state *crtc_state); + #endif /* __INTEL_PSR_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c index 76e1188b01d4..ab88d8b783e6 100644 --- a/drivers/gpu/drm/i915/display/intel_sdvo.c +++ b/drivers/gpu/drm/i915/display/intel_sdvo.c @@ -283,7 +283,7 @@ static bool intel_sdvo_read_byte(struct intel_sdvo *intel_sdvo, u8 addr, u8 *ch) static const struct { u8 cmd; const char *name; -} __attribute__ ((packed)) sdvo_cmd_names[] = { +} __packed sdvo_cmd_names[] = { SDVO_CMD_NAME_ENTRY(RESET), SDVO_CMD_NAME_ENTRY(GET_DEVICE_CAPS), SDVO_CMD_NAME_ENTRY(GET_FIRMWARE_REV), @@ -783,24 +783,22 @@ static bool intel_sdvo_get_input_timing(struct intel_sdvo *intel_sdvo, static bool intel_sdvo_create_preferred_input_timing(struct intel_sdvo *intel_sdvo, struct intel_sdvo_connector *intel_sdvo_connector, - u16 clock, - u16 width, - u16 height) + const struct drm_display_mode *mode) { struct intel_sdvo_preferred_input_timing_args args; memset(&args, 0, sizeof(args)); - args.clock = clock; - args.width = width; - args.height = height; + args.clock = mode->clock / 10; + args.width = mode->hdisplay; + args.height = mode->vdisplay; args.interlace = 0; if (IS_LVDS(intel_sdvo_connector)) { const struct drm_display_mode *fixed_mode = - intel_sdvo_connector->base.panel.fixed_mode; + intel_panel_fixed_mode(&intel_sdvo_connector->base, mode); - if (fixed_mode->hdisplay != width || - fixed_mode->vdisplay != height) + if (fixed_mode->hdisplay != args.width || + fixed_mode->vdisplay != args.height) args.scaled = 1; } @@ -1236,9 +1234,7 @@ intel_sdvo_get_preferred_input_mode(struct intel_sdvo *intel_sdvo, if (!intel_sdvo_create_preferred_input_timing(intel_sdvo, intel_sdvo_connector, - mode->clock / 10, - mode->hdisplay, - mode->vdisplay)) + mode)) return false; if (!intel_sdvo_get_preferred_input_timing(intel_sdvo, @@ -1335,6 +1331,8 @@ static int intel_sdvo_compute_config(struct intel_encoder *encoder, adjusted_mode); pipe_config->sdvo_tv_clock = true; } else if (IS_LVDS(intel_sdvo_connector)) { + const struct drm_display_mode *fixed_mode = + intel_panel_fixed_mode(&intel_sdvo_connector->base, mode); int ret; ret = intel_panel_compute_config(&intel_sdvo_connector->base, @@ -1342,8 +1340,7 @@ static int intel_sdvo_compute_config(struct intel_encoder *encoder, if (ret) return ret; - if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, - intel_sdvo_connector->base.panel.fixed_mode)) + if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, fixed_mode)) return -EINVAL; (void) intel_sdvo_get_preferred_input_mode(intel_sdvo, @@ -1465,7 +1462,7 @@ static void intel_sdvo_pre_enable(struct intel_atomic_state *state, const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; const struct intel_sdvo_connector_state *sdvo_state = to_intel_sdvo_connector_state(conn_state); - const struct intel_sdvo_connector *intel_sdvo_connector = + struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(conn_state->connector); const struct drm_display_mode *mode = &crtc_state->hw.mode; struct intel_sdvo *intel_sdvo = to_sdvo(intel_encoder); @@ -1496,11 +1493,14 @@ static void intel_sdvo_pre_enable(struct intel_atomic_state *state, return; /* lvds has a special fixed output timing. */ - if (IS_LVDS(intel_sdvo_connector)) - intel_sdvo_get_dtd_from_mode(&output_dtd, - intel_sdvo_connector->base.panel.fixed_mode); - else + if (IS_LVDS(intel_sdvo_connector)) { + const struct drm_display_mode *fixed_mode = + intel_panel_fixed_mode(&intel_sdvo_connector->base, mode); + + intel_sdvo_get_dtd_from_mode(&output_dtd, fixed_mode); + } else { intel_sdvo_get_dtd_from_mode(&output_dtd, mode); + } if (!intel_sdvo_set_output_timing(intel_sdvo, &output_dtd)) drm_info(&dev_priv->drm, "Setting output timings on %s failed\n", @@ -2291,33 +2291,12 @@ static int intel_sdvo_get_lvds_modes(struct drm_connector *connector) { struct intel_sdvo *intel_sdvo = intel_attached_sdvo(to_intel_connector(connector)); struct drm_i915_private *dev_priv = to_i915(connector->dev); - struct drm_display_mode *newmode; int num_modes = 0; drm_dbg_kms(&dev_priv->drm, "[CONNECTOR:%d:%s]\n", connector->base.id, connector->name); - /* - * Fetch modes from VBT. For SDVO prefer the VBT mode since some - * SDVO->LVDS transcoders can't cope with the EDID mode. - */ - if (dev_priv->vbt.sdvo_lvds_vbt_mode != NULL) { - newmode = drm_mode_duplicate(connector->dev, - dev_priv->vbt.sdvo_lvds_vbt_mode); - if (newmode != NULL) { - /* Guarantee the mode is preferred */ - newmode->type = (DRM_MODE_TYPE_PREFERRED | - DRM_MODE_TYPE_DRIVER); - drm_mode_probed_add(connector, newmode); - num_modes++; - } - } - - /* - * Attempt to get the mode list from DDC. - * Assume that the preferred modes are - * arranged in priority order. - */ + num_modes += intel_panel_get_modes(to_intel_connector(connector)); num_modes += intel_ddc_get_modes(connector, &intel_sdvo->ddc); return num_modes; @@ -2747,6 +2726,8 @@ static struct intel_sdvo_connector *intel_sdvo_connector_alloc(void) __drm_atomic_helper_connector_reset(&sdvo_connector->base.base, &conn_state->base.base); + INIT_LIST_HEAD(&sdvo_connector->base.panel.fixed_modes); + return sdvo_connector; } @@ -2890,7 +2871,6 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device) struct drm_connector *connector; struct intel_connector *intel_connector; struct intel_sdvo_connector *intel_sdvo_connector; - struct drm_display_mode *mode; DRM_DEBUG_KMS("initialising LVDS device %d\n", device); @@ -2919,20 +2899,20 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device) if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector)) goto err; - intel_sdvo_get_lvds_modes(connector); - - list_for_each_entry(mode, &connector->probed_modes, head) { - if (mode->type & DRM_MODE_TYPE_PREFERRED) { - struct drm_display_mode *fixed_mode = - drm_mode_duplicate(connector->dev, mode); + /* + * Fetch modes from VBT. For SDVO prefer the VBT mode since some + * SDVO->LVDS transcoders can't cope with the EDID mode. + */ + intel_panel_add_vbt_sdvo_fixed_mode(intel_connector); - intel_panel_init(&intel_connector->panel, - fixed_mode, NULL); - break; - } + if (!intel_panel_preferred_fixed_mode(intel_connector)) { + intel_ddc_get_modes(connector, &intel_sdvo->ddc); + intel_panel_add_edid_fixed_modes(intel_connector, false); } - if (!intel_connector->panel.fixed_mode) + intel_panel_init(intel_connector); + + if (!intel_panel_preferred_fixed_mode(intel_connector)) goto err; return true; diff --git a/drivers/gpu/drm/i915/display/intel_snps_phy.c b/drivers/gpu/drm/i915/display/intel_snps_phy.c index 7e6245b97fed..0dd4775e8195 100644 --- a/drivers/gpu/drm/i915/display/intel_snps_phy.c +++ b/drivers/gpu/drm/i915/display/intel_snps_phy.c @@ -32,10 +32,14 @@ void intel_snps_phy_wait_for_calibration(struct drm_i915_private *i915) if (!intel_phy_is_snps(i915, phy)) continue; + /* + * If calibration does not complete successfully, we'll remember + * which phy was affected and skip setup of the corresponding + * output later. + */ if (intel_de_wait_for_clear(i915, DG2_PHY_MISC(phy), DG2_PHY_DP_TX_ACK_MASK, 25)) - drm_err(&i915->drm, "SNPS PHY %c failed to calibrate after 25ms.\n", - phy_name(phy)); + i915->snps_phy_failed_calibration |= BIT(phy); } } diff --git a/drivers/gpu/drm/i915/display/intel_sprite.c b/drivers/gpu/drm/i915/display/intel_sprite.c index 2d71294aaceb..7c0df80612d0 100644 --- a/drivers/gpu/drm/i915/display/intel_sprite.c +++ b/drivers/gpu/drm/i915/display/intel_sprite.c @@ -30,6 +30,8 @@ * support. */ +#include <linux/string_helpers.h> + #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_color_mgmt.h> @@ -96,13 +98,13 @@ int intel_plane_check_src_coordinates(struct intel_plane_state *plane_state) if (src_x % hsub || src_w % hsub) { drm_dbg_kms(&i915->drm, "src x/w (%u, %u) must be a multiple of %u (rotated: %s)\n", - src_x, src_w, hsub, yesno(rotated)); + src_x, src_w, hsub, str_yes_no(rotated)); return -EINVAL; } if (src_y % vsub || src_h % vsub) { drm_dbg_kms(&i915->drm, "src y/h (%u, %u) must be a multiple of %u (rotated: %s)\n", - src_y, src_h, vsub, yesno(rotated)); + src_y, src_h, vsub, str_yes_no(rotated)); return -EINVAL; } @@ -430,9 +432,6 @@ vlv_sprite_update_noarm(struct intel_plane *plane, int crtc_y = plane_state->uapi.dst.y1; u32 crtc_w = drm_rect_width(&plane_state->uapi.dst); u32 crtc_h = drm_rect_height(&plane_state->uapi.dst); - unsigned long irqflags; - - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); intel_de_write_fw(dev_priv, SPSTRIDE(pipe, plane_id), plane_state->view.color_plane[0].mapping_stride); @@ -440,8 +439,6 @@ vlv_sprite_update_noarm(struct intel_plane *plane, SP_POS_Y(crtc_y) | SP_POS_X(crtc_x)); intel_de_write_fw(dev_priv, SPSIZE(pipe, plane_id), SP_HEIGHT(crtc_h - 1) | SP_WIDTH(crtc_w - 1)); - - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } static void @@ -457,14 +454,11 @@ vlv_sprite_update_arm(struct intel_plane *plane, u32 x = plane_state->view.color_plane[0].x; u32 y = plane_state->view.color_plane[0].y; u32 sprctl, linear_offset; - unsigned long irqflags; sprctl = plane_state->ctl | vlv_sprite_ctl_crtc(crtc_state); linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0); - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); - if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B) chv_sprite_update_csc(plane_state); @@ -494,8 +488,6 @@ vlv_sprite_update_arm(struct intel_plane *plane, vlv_sprite_update_clrc(plane_state); vlv_sprite_update_gamma(plane_state); - - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } static void @@ -505,14 +497,9 @@ vlv_sprite_disable_arm(struct intel_plane *plane, struct drm_i915_private *dev_priv = to_i915(plane->base.dev); enum pipe pipe = plane->pipe; enum plane_id plane_id = plane->id; - unsigned long irqflags; - - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); intel_de_write_fw(dev_priv, SPCNTR(pipe, plane_id), 0); intel_de_write_fw(dev_priv, SPSURF(pipe, plane_id), 0); - - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } static bool @@ -862,15 +849,12 @@ ivb_sprite_update_noarm(struct intel_plane *plane, u32 src_w = drm_rect_width(&plane_state->uapi.src) >> 16; u32 src_h = drm_rect_height(&plane_state->uapi.src) >> 16; u32 sprscale = 0; - unsigned long irqflags; if (crtc_w != src_w || crtc_h != src_h) sprscale = SPRITE_SCALE_ENABLE | SPRITE_SRC_WIDTH(src_w - 1) | SPRITE_SRC_HEIGHT(src_h - 1); - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); - intel_de_write_fw(dev_priv, SPRSTRIDE(pipe), plane_state->view.color_plane[0].mapping_stride); intel_de_write_fw(dev_priv, SPRPOS(pipe), @@ -879,8 +863,6 @@ ivb_sprite_update_noarm(struct intel_plane *plane, SPRITE_HEIGHT(crtc_h - 1) | SPRITE_WIDTH(crtc_w - 1)); if (IS_IVYBRIDGE(dev_priv)) intel_de_write_fw(dev_priv, SPRSCALE(pipe), sprscale); - - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } static void @@ -895,14 +877,11 @@ ivb_sprite_update_arm(struct intel_plane *plane, u32 x = plane_state->view.color_plane[0].x; u32 y = plane_state->view.color_plane[0].y; u32 sprctl, linear_offset; - unsigned long irqflags; sprctl = plane_state->ctl | ivb_sprite_ctl_crtc(crtc_state); linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0); - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); - if (key->flags) { intel_de_write_fw(dev_priv, SPRKEYVAL(pipe), key->min_value); intel_de_write_fw(dev_priv, SPRKEYMSK(pipe), @@ -931,8 +910,6 @@ ivb_sprite_update_arm(struct intel_plane *plane, intel_plane_ggtt_offset(plane_state) + sprsurf_offset); ivb_sprite_update_gamma(plane_state); - - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } static void @@ -941,17 +918,12 @@ ivb_sprite_disable_arm(struct intel_plane *plane, { struct drm_i915_private *dev_priv = to_i915(plane->base.dev); enum pipe pipe = plane->pipe; - unsigned long irqflags; - - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); intel_de_write_fw(dev_priv, SPRCTL(pipe), 0); /* Disable the scaler */ if (IS_IVYBRIDGE(dev_priv)) intel_de_write_fw(dev_priv, SPRSCALE(pipe), 0); intel_de_write_fw(dev_priv, SPRSURF(pipe), 0); - - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } static bool @@ -1204,15 +1176,12 @@ g4x_sprite_update_noarm(struct intel_plane *plane, u32 src_w = drm_rect_width(&plane_state->uapi.src) >> 16; u32 src_h = drm_rect_height(&plane_state->uapi.src) >> 16; u32 dvsscale = 0; - unsigned long irqflags; if (crtc_w != src_w || crtc_h != src_h) dvsscale = DVS_SCALE_ENABLE | DVS_SRC_WIDTH(src_w - 1) | DVS_SRC_HEIGHT(src_h - 1); - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); - intel_de_write_fw(dev_priv, DVSSTRIDE(pipe), plane_state->view.color_plane[0].mapping_stride); intel_de_write_fw(dev_priv, DVSPOS(pipe), @@ -1220,8 +1189,6 @@ g4x_sprite_update_noarm(struct intel_plane *plane, intel_de_write_fw(dev_priv, DVSSIZE(pipe), DVS_HEIGHT(crtc_h - 1) | DVS_WIDTH(crtc_w - 1)); intel_de_write_fw(dev_priv, DVSSCALE(pipe), dvsscale); - - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } static void @@ -1236,14 +1203,11 @@ g4x_sprite_update_arm(struct intel_plane *plane, u32 x = plane_state->view.color_plane[0].x; u32 y = plane_state->view.color_plane[0].y; u32 dvscntr, linear_offset; - unsigned long irqflags; dvscntr = plane_state->ctl | g4x_sprite_ctl_crtc(crtc_state); linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0); - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); - if (key->flags) { intel_de_write_fw(dev_priv, DVSKEYVAL(pipe), key->min_value); intel_de_write_fw(dev_priv, DVSKEYMSK(pipe), @@ -1267,8 +1231,6 @@ g4x_sprite_update_arm(struct intel_plane *plane, g4x_sprite_update_gamma(plane_state); else ilk_sprite_update_gamma(plane_state); - - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } static void @@ -1277,16 +1239,11 @@ g4x_sprite_disable_arm(struct intel_plane *plane, { struct drm_i915_private *dev_priv = to_i915(plane->base.dev); enum pipe pipe = plane->pipe; - unsigned long irqflags; - - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); intel_de_write_fw(dev_priv, DVSCNTR(pipe), 0); /* Disable the scaler */ intel_de_write_fw(dev_priv, DVSSCALE(pipe), 0); intel_de_write_fw(dev_priv, DVSSURF(pipe), 0); - - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } static bool diff --git a/drivers/gpu/drm/i915/display/intel_tv.c b/drivers/gpu/drm/i915/display/intel_tv.c index 8a39989b87ad..9379f3463344 100644 --- a/drivers/gpu/drm/i915/display/intel_tv.c +++ b/drivers/gpu/drm/i915/display/intel_tv.c @@ -1145,8 +1145,8 @@ intel_tv_get_config(struct intel_encoder *encoder, intel_tv_mode_to_mode(&mode, &tv_mode); - drm_dbg_kms(&dev_priv->drm, "TV mode:\n"); - drm_mode_debug_printmodeline(&mode); + drm_dbg_kms(&dev_priv->drm, "TV mode: " DRM_MODE_FMT "\n", + DRM_MODE_ARG(&mode)); intel_tv_scale_mode_horiz(&mode, hdisplay, xpos, mode.hdisplay - xsize - xpos); @@ -1250,8 +1250,8 @@ intel_tv_compute_config(struct intel_encoder *encoder, tv_conn_state->bypass_vfilter = false; } - drm_dbg_kms(&dev_priv->drm, "TV mode:\n"); - drm_mode_debug_printmodeline(adjusted_mode); + drm_dbg_kms(&dev_priv->drm, "TV mode: " DRM_MODE_FMT "\n", + DRM_MODE_ARG(adjusted_mode)); /* * The pipe scanline counter behaviour looks as follows when @@ -1806,8 +1806,8 @@ intel_tv_get_modes(struct drm_connector *connector) */ intel_tv_mode_to_mode(mode, tv_mode); if (count == 0) { - drm_dbg_kms(&dev_priv->drm, "TV mode:\n"); - drm_mode_debug_printmodeline(mode); + drm_dbg_kms(&dev_priv->drm, "TV mode: " DRM_MODE_FMT "\n", + DRM_MODE_ARG(mode)); } intel_tv_scale_mode_horiz(mode, input->w, 0, 0); intel_tv_scale_mode_vert(mode, input->h, 0, 0); diff --git a/drivers/gpu/drm/i915/display/intel_vbt_defs.h b/drivers/gpu/drm/i915/display/intel_vbt_defs.h index b9397d9363c5..e4a11c3e3f3e 100644 --- a/drivers/gpu/drm/i915/display/intel_vbt_defs.h +++ b/drivers/gpu/drm/i915/display/intel_vbt_defs.h @@ -289,6 +289,9 @@ struct bdb_general_features { #define HDMI_MAX_DATA_RATE_PLATFORM 0 /* 204 */ #define HDMI_MAX_DATA_RATE_297 1 /* 204 */ #define HDMI_MAX_DATA_RATE_165 2 /* 204 */ +#define HDMI_MAX_DATA_RATE_594 3 /* 249 */ +#define HDMI_MAX_DATA_RATE_340 4 /* 249 */ +#define HDMI_MAX_DATA_RATE_300 5 /* 249 */ #define LEGACY_CHILD_DEVICE_CONFIG_SIZE 33 @@ -719,20 +722,22 @@ struct bdb_lvds_options { /* * Block 41 - LFP Data Table Pointers */ +struct lvds_lfp_data_ptr_table { + u16 offset; /* offsets are from start of bdb */ + u8 table_size; +} __packed; /* LFP pointer table contains entries to the struct below */ struct lvds_lfp_data_ptr { - u16 fp_timing_offset; /* offsets are from start of bdb */ - u8 fp_table_size; - u16 dvo_timing_offset; - u8 dvo_table_size; - u16 panel_pnp_id_offset; - u8 pnp_table_size; + struct lvds_lfp_data_ptr_table fp_timing; + struct lvds_lfp_data_ptr_table dvo_timing; + struct lvds_lfp_data_ptr_table panel_pnp_id; } __packed; struct bdb_lvds_lfp_data_ptrs { u8 lvds_entries; /* followed by one or more lvds_data_ptr structs */ struct lvds_lfp_data_ptr ptr[16]; + struct lvds_lfp_data_ptr_table panel_name; /* 156-163? */ } __packed; /* @@ -774,6 +779,10 @@ struct bdb_lvds_lfp_data { struct lvds_lfp_data_entry data[16]; } __packed; +struct lvds_lfp_panel_name { + u8 name[13]; +} __packed; + /* * Block 43 - LFP Backlight Control Data Block */ diff --git a/drivers/gpu/drm/i915/display/intel_vdsc.c b/drivers/gpu/drm/i915/display/intel_vdsc.c index 545eff5bf158..e59c29ab1300 100644 --- a/drivers/gpu/drm/i915/display/intel_vdsc.c +++ b/drivers/gpu/drm/i915/display/intel_vdsc.c @@ -378,10 +378,18 @@ calculate_rc_params(struct rc_parameters *rc, { int bpc = vdsc_cfg->bits_per_component; int bpp = vdsc_cfg->bits_per_pixel >> 4; - int ofs_und6[] = { 0, -2, -2, -4, -6, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12 }; - int ofs_und8[] = { 2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -10, -12, -12, -12 }; - int ofs_und12[] = { 2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -10, -12, -12, -12 }; - int ofs_und15[] = { 10, 8, 6, 4, 2, 0, -2, -4, -6, -8, -10, -10, -12, -12, -12 }; + static const s8 ofs_und6[] = { + 0, -2, -2, -4, -6, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12 + }; + static const s8 ofs_und8[] = { + 2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -10, -12, -12, -12 + }; + static const s8 ofs_und12[] = { + 2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -10, -12, -12, -12 + }; + static const s8 ofs_und15[] = { + 10, 8, 6, 4, 2, 0, -2, -4, -6, -8, -10, -10, -12, -12, -12 + }; int qp_bpc_modifier = (bpc - 8) * 2; u32 res, buf_i, bpp_i; @@ -579,7 +587,7 @@ static void intel_dsc_pps_configure(const struct intel_crtc_state *crtc_state) u8 num_vdsc_instances = (crtc_state->dsc.dsc_split) ? 2 : 1; int i = 0; - if (crtc_state->bigjoiner) + if (crtc_state->bigjoiner_pipes) num_vdsc_instances *= 2; /* Populate PICTURE_PARAMETER_SET_0 registers */ @@ -1113,7 +1121,7 @@ void intel_uncompressed_joiner_enable(const struct intel_crtc_state *crtc_state) struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); u32 dss_ctl1_val = 0; - if (crtc_state->bigjoiner && !crtc_state->dsc.compression_enable) { + if (crtc_state->bigjoiner_pipes && !crtc_state->dsc.compression_enable) { if (intel_crtc_is_bigjoiner_slave(crtc_state)) dss_ctl1_val |= UNCOMPRESSED_JOINER_SLAVE; else @@ -1140,7 +1148,7 @@ void intel_dsc_enable(const struct intel_crtc_state *crtc_state) dss_ctl2_val |= RIGHT_BRANCH_VDSC_ENABLE; dss_ctl1_val |= JOINER_ENABLE; } - if (crtc_state->bigjoiner) { + if (crtc_state->bigjoiner_pipes) { dss_ctl1_val |= BIG_JOINER_ENABLE; if (!intel_crtc_is_bigjoiner_slave(crtc_state)) dss_ctl1_val |= MASTER_BIG_JOINER_ENABLE; @@ -1156,7 +1164,7 @@ void intel_dsc_disable(const struct intel_crtc_state *old_crtc_state) /* Disable only if either of them is enabled */ if (old_crtc_state->dsc.compression_enable || - old_crtc_state->bigjoiner) { + old_crtc_state->bigjoiner_pipes) { intel_de_write(dev_priv, dss_ctl1_reg(crtc, old_crtc_state->cpu_transcoder), 0); intel_de_write(dev_priv, dss_ctl2_reg(crtc, old_crtc_state->cpu_transcoder), 0); } diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c b/drivers/gpu/drm/i915/display/intel_vrr.c index 139e8936edc5..396f2f994fa0 100644 --- a/drivers/gpu/drm/i915/display/intel_vrr.c +++ b/drivers/gpu/drm/i915/display/intel_vrr.c @@ -69,9 +69,9 @@ static int intel_vrr_vblank_exit_length(const struct intel_crtc_state *crtc_stat /* The hw imposes the extra scanline before frame start */ if (DISPLAY_VER(i915) >= 13) - return crtc_state->vrr.guardband + i915->framestart_delay + 1; + return crtc_state->vrr.guardband + crtc_state->framestart_delay + 1; else - return crtc_state->vrr.pipeline_full + i915->framestart_delay + 1; + return crtc_state->vrr.pipeline_full + crtc_state->framestart_delay + 1; } int intel_vrr_vmin_vblank_start(const struct intel_crtc_state *crtc_state) diff --git a/drivers/gpu/drm/i915/display/skl_scaler.c b/drivers/gpu/drm/i915/display/skl_scaler.c index c2e94118566b..4092679be21e 100644 --- a/drivers/gpu/drm/i915/display/skl_scaler.c +++ b/drivers/gpu/drm/i915/display/skl_scaler.c @@ -197,7 +197,8 @@ int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state) return skl_update_scaler(crtc_state, !crtc_state->hw.active, SKL_CRTC_INDEX, &crtc_state->scaler_state.scaler_id, - crtc_state->pipe_src_w, crtc_state->pipe_src_h, + drm_rect_width(&crtc_state->pipe_src), + drm_rect_height(&crtc_state->pipe_src), width, height, NULL, 0, crtc_state->pch_pfit.enabled); } @@ -400,10 +401,6 @@ void skl_pfit_enable(const struct intel_crtc_state *crtc_state) struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); const struct intel_crtc_scaler_state *scaler_state = &crtc_state->scaler_state; - struct drm_rect src = { - .x2 = crtc_state->pipe_src_w << 16, - .y2 = crtc_state->pipe_src_h << 16, - }; const struct drm_rect *dst = &crtc_state->pch_pfit.dst; u16 uv_rgb_hphase, uv_rgb_vphase; enum pipe pipe = crtc->pipe; @@ -412,7 +409,7 @@ void skl_pfit_enable(const struct intel_crtc_state *crtc_state) int x = dst->x1; int y = dst->y1; int hscale, vscale; - unsigned long irqflags; + struct drm_rect src; int id; u32 ps_ctrl; @@ -423,6 +420,10 @@ void skl_pfit_enable(const struct intel_crtc_state *crtc_state) crtc_state->scaler_state.scaler_id < 0)) return; + drm_rect_init(&src, 0, 0, + drm_rect_width(&crtc_state->pipe_src) << 16, + drm_rect_height(&crtc_state->pipe_src) << 16); + hscale = drm_rect_calc_hscale(&src, dst, 0, INT_MAX); vscale = drm_rect_calc_vscale(&src, dst, 0, INT_MAX); @@ -434,8 +435,6 @@ void skl_pfit_enable(const struct intel_crtc_state *crtc_state) ps_ctrl = skl_scaler_get_filter_select(crtc_state->hw.scaling_filter, 0); ps_ctrl |= PS_SCALER_EN | scaler_state->scalers[id].mode; - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); - skl_scaler_setup_filter(dev_priv, pipe, id, 0, crtc_state->hw.scaling_filter); @@ -449,8 +448,6 @@ void skl_pfit_enable(const struct intel_crtc_state *crtc_state) x << 16 | y); intel_de_write_fw(dev_priv, SKL_PS_WIN_SZ(pipe, id), width << 16 | height); - - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } void @@ -519,15 +516,10 @@ static void skl_detach_scaler(struct intel_crtc *crtc, int id) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = to_i915(dev); - unsigned long irqflags; - - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); intel_de_write_fw(dev_priv, SKL_PS_CTRL(crtc->pipe, id), 0); intel_de_write_fw(dev_priv, SKL_PS_WIN_POS(crtc->pipe, id), 0); intel_de_write_fw(dev_priv, SKL_PS_WIN_SZ(crtc->pipe, id), 0); - - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } /* diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c index 1223075595ff..caa03324a733 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane.c +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c @@ -615,9 +615,20 @@ skl_plane_disable_arm(struct intel_plane *plane, struct drm_i915_private *dev_priv = to_i915(plane->base.dev); enum plane_id plane_id = plane->id; enum pipe pipe = plane->pipe; - unsigned long irqflags; - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); + skl_write_plane_wm(plane, crtc_state); + + intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), 0); + intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id), 0); +} + +static void +icl_plane_disable_arm(struct intel_plane *plane, + const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + enum plane_id plane_id = plane->id; + enum pipe pipe = plane->pipe; if (icl_is_hdr_plane(dev_priv, plane_id)) intel_de_write_fw(dev_priv, PLANE_CUS_CTL(pipe, plane_id), 0); @@ -627,8 +638,6 @@ skl_plane_disable_arm(struct intel_plane *plane, intel_psr2_disable_plane_sel_fetch(plane, crtc_state); intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), 0); intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id), 0); - - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } static bool @@ -762,6 +771,18 @@ static u32 skl_plane_ctl_tiling(u64 fb_modifier) return PLANE_CTL_TILED_X; case I915_FORMAT_MOD_Y_TILED: return PLANE_CTL_TILED_Y; + case I915_FORMAT_MOD_4_TILED: + return PLANE_CTL_TILED_4; + case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS: + return PLANE_CTL_TILED_4 | + PLANE_CTL_RENDER_DECOMPRESSION_ENABLE | + PLANE_CTL_CLEAR_COLOR_DISABLE; + case I915_FORMAT_MOD_4_TILED_DG2_MC_CCS: + return PLANE_CTL_TILED_4 | + PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE | + PLANE_CTL_CLEAR_COLOR_DISABLE; + case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC: + return PLANE_CTL_TILED_4 | PLANE_CTL_RENDER_DECOMPRESSION_ENABLE; case I915_FORMAT_MOD_Y_TILED_CCS: case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC: return PLANE_CTL_TILED_Y | PLANE_CTL_RENDER_DECOMPRESSION_ENABLE; @@ -1065,7 +1086,7 @@ static void icl_plane_csc_load_black(struct intel_plane *plane) intel_de_write_fw(i915, PLANE_CSC_POSTOFF(pipe, plane_id, 2), 0); } -static int skl_plane_color_plane(const struct intel_plane_state *plane_state) +static int icl_plane_color_plane(const struct intel_plane_state *plane_state) { /* Program the UV plane on planar master */ if (plane_state->planar_linked_plane && !plane_state->planar_slave) @@ -1082,14 +1103,11 @@ skl_plane_update_noarm(struct intel_plane *plane, struct drm_i915_private *dev_priv = to_i915(plane->base.dev); enum plane_id plane_id = plane->id; enum pipe pipe = plane->pipe; - int color_plane = skl_plane_color_plane(plane_state); - u32 stride = skl_plane_stride(plane_state, color_plane); - const struct drm_framebuffer *fb = plane_state->hw.fb; + u32 stride = skl_plane_stride(plane_state, 0); int crtc_x = plane_state->uapi.dst.x1; int crtc_y = plane_state->uapi.dst.y1; u32 src_w = drm_rect_width(&plane_state->uapi.src) >> 16; u32 src_h = drm_rect_height(&plane_state->uapi.src) >> 16; - unsigned long irqflags; /* The scaler will handle the output position */ if (plane_state->scaler_id >= 0) { @@ -1097,14 +1115,99 @@ skl_plane_update_noarm(struct intel_plane *plane, crtc_y = 0; } - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); + intel_de_write_fw(dev_priv, PLANE_STRIDE(pipe, plane_id), + PLANE_STRIDE_(stride)); + intel_de_write_fw(dev_priv, PLANE_POS(pipe, plane_id), + PLANE_POS_Y(crtc_y) | PLANE_POS_X(crtc_x)); + intel_de_write_fw(dev_priv, PLANE_SIZE(pipe, plane_id), + PLANE_HEIGHT(src_h - 1) | PLANE_WIDTH(src_w - 1)); + + skl_write_plane_wm(plane, crtc_state); +} + +static void +skl_plane_update_arm(struct intel_plane *plane, + const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state) +{ + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + enum plane_id plane_id = plane->id; + enum pipe pipe = plane->pipe; + u32 x = plane_state->view.color_plane[0].x; + u32 y = plane_state->view.color_plane[0].y; + u32 plane_ctl, plane_color_ctl = 0; + + plane_ctl = plane_state->ctl | + skl_plane_ctl_crtc(crtc_state); + + if (DISPLAY_VER(dev_priv) >= 10) + plane_color_ctl = plane_state->color_ctl | + glk_plane_color_ctl_crtc(crtc_state); + + intel_de_write_fw(dev_priv, PLANE_KEYVAL(pipe, plane_id), skl_plane_keyval(plane_state)); + intel_de_write_fw(dev_priv, PLANE_KEYMSK(pipe, plane_id), skl_plane_keymsk(plane_state)); + intel_de_write_fw(dev_priv, PLANE_KEYMAX(pipe, plane_id), skl_plane_keymax(plane_state)); + + intel_de_write_fw(dev_priv, PLANE_OFFSET(pipe, plane_id), + PLANE_OFFSET_Y(y) | PLANE_OFFSET_X(x)); + + intel_de_write_fw(dev_priv, PLANE_AUX_DIST(pipe, plane_id), + skl_plane_aux_dist(plane_state, 0)); + + intel_de_write_fw(dev_priv, PLANE_AUX_OFFSET(pipe, plane_id), + PLANE_OFFSET_Y(plane_state->view.color_plane[1].y) | + PLANE_OFFSET_X(plane_state->view.color_plane[1].x)); + + if (DISPLAY_VER(dev_priv) >= 10) + intel_de_write_fw(dev_priv, PLANE_COLOR_CTL(pipe, plane_id), plane_color_ctl); /* - * FIXME: pxp session invalidation can hit any time even at time of commit - * or after the commit, display content will be garbage. + * Enable the scaler before the plane so that we don't + * get a catastrophic underrun even if the two operations + * end up happening in two different frames. + * + * TODO: split into noarm+arm pair */ - if (plane_state->force_black) - icl_plane_csc_load_black(plane); + if (plane_state->scaler_id >= 0) + skl_program_plane_scaler(plane, crtc_state, plane_state); + + /* + * The control register self-arms if the plane was previously + * disabled. Try to make the plane enable atomic by writing + * the control register just before the surface register. + */ + intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), plane_ctl); + intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id), + skl_plane_surf(plane_state, 0)); +} + +static void +icl_plane_update_noarm(struct intel_plane *plane, + const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state) +{ + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + enum plane_id plane_id = plane->id; + enum pipe pipe = plane->pipe; + int color_plane = icl_plane_color_plane(plane_state); + u32 stride = skl_plane_stride(plane_state, color_plane); + const struct drm_framebuffer *fb = plane_state->hw.fb; + int crtc_x = plane_state->uapi.dst.x1; + int crtc_y = plane_state->uapi.dst.y1; + int x = plane_state->view.color_plane[color_plane].x; + int y = plane_state->view.color_plane[color_plane].y; + int src_w = drm_rect_width(&plane_state->uapi.src) >> 16; + int src_h = drm_rect_height(&plane_state->uapi.src) >> 16; + u32 plane_color_ctl; + + plane_color_ctl = plane_state->color_ctl | + glk_plane_color_ctl_crtc(crtc_state); + + /* The scaler will handle the output position */ + if (plane_state->scaler_id >= 0) { + crtc_x = 0; + crtc_y = 0; + } intel_de_write_fw(dev_priv, PLANE_STRIDE(pipe, plane_id), PLANE_STRIDE_(stride)); @@ -1113,6 +1216,13 @@ skl_plane_update_noarm(struct intel_plane *plane, intel_de_write_fw(dev_priv, PLANE_SIZE(pipe, plane_id), PLANE_HEIGHT(src_h - 1) | PLANE_WIDTH(src_w - 1)); + intel_de_write_fw(dev_priv, PLANE_KEYVAL(pipe, plane_id), skl_plane_keyval(plane_state)); + intel_de_write_fw(dev_priv, PLANE_KEYMSK(pipe, plane_id), skl_plane_keymsk(plane_state)); + intel_de_write_fw(dev_priv, PLANE_KEYMAX(pipe, plane_id), skl_plane_keymax(plane_state)); + + intel_de_write_fw(dev_priv, PLANE_OFFSET(pipe, plane_id), + PLANE_OFFSET_Y(y) | PLANE_OFFSET_X(x)); + if (intel_fb_is_rc_ccs_cc_modifier(fb->modifier)) { intel_de_write_fw(dev_priv, PLANE_CC_VAL(pipe, plane_id, 0), lower_32_bits(plane_state->ccval)); @@ -1120,60 +1230,45 @@ skl_plane_update_noarm(struct intel_plane *plane, upper_32_bits(plane_state->ccval)); } + /* FLAT CCS doesn't need to program AUX_DIST */ + if (!HAS_FLAT_CCS(dev_priv)) + intel_de_write_fw(dev_priv, PLANE_AUX_DIST(pipe, plane_id), + skl_plane_aux_dist(plane_state, color_plane)); + if (icl_is_hdr_plane(dev_priv, plane_id)) intel_de_write_fw(dev_priv, PLANE_CUS_CTL(pipe, plane_id), plane_state->cus_ctl); + intel_de_write_fw(dev_priv, PLANE_COLOR_CTL(pipe, plane_id), plane_color_ctl); + if (fb->format->is_yuv && icl_is_hdr_plane(dev_priv, plane_id)) icl_program_input_csc(plane, crtc_state, plane_state); skl_write_plane_wm(plane, crtc_state); - intel_psr2_program_plane_sel_fetch(plane, crtc_state, plane_state, color_plane); + /* + * FIXME: pxp session invalidation can hit any time even at time of commit + * or after the commit, display content will be garbage. + */ + if (plane_state->force_black) + icl_plane_csc_load_black(plane); - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); + intel_psr2_program_plane_sel_fetch(plane, crtc_state, plane_state, color_plane); } static void -skl_plane_update_arm(struct intel_plane *plane, +icl_plane_update_arm(struct intel_plane *plane, const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state) { struct drm_i915_private *dev_priv = to_i915(plane->base.dev); enum plane_id plane_id = plane->id; enum pipe pipe = plane->pipe; - int color_plane = skl_plane_color_plane(plane_state); - u32 x = plane_state->view.color_plane[color_plane].x; - u32 y = plane_state->view.color_plane[color_plane].y; - u32 plane_color_ctl = 0; - u32 plane_ctl = plane_state->ctl; - unsigned long irqflags; - - plane_ctl |= skl_plane_ctl_crtc(crtc_state); - - if (DISPLAY_VER(dev_priv) >= 10) - plane_color_ctl = plane_state->color_ctl | - glk_plane_color_ctl_crtc(crtc_state); - - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); - - intel_de_write_fw(dev_priv, PLANE_KEYVAL(pipe, plane_id), skl_plane_keyval(plane_state)); - intel_de_write_fw(dev_priv, PLANE_KEYMSK(pipe, plane_id), skl_plane_keymsk(plane_state)); - intel_de_write_fw(dev_priv, PLANE_KEYMAX(pipe, plane_id), skl_plane_keymax(plane_state)); - - intel_de_write_fw(dev_priv, PLANE_OFFSET(pipe, plane_id), - PLANE_OFFSET_Y(y) | PLANE_OFFSET_X(x)); - - intel_de_write_fw(dev_priv, PLANE_AUX_DIST(pipe, plane_id), - skl_plane_aux_dist(plane_state, color_plane)); - - if (DISPLAY_VER(dev_priv) < 11) - intel_de_write_fw(dev_priv, PLANE_AUX_OFFSET(pipe, plane_id), - PLANE_OFFSET_Y(plane_state->view.color_plane[1].y) | - PLANE_OFFSET_X(plane_state->view.color_plane[1].x)); + int color_plane = icl_plane_color_plane(plane_state); + u32 plane_ctl; - if (DISPLAY_VER(dev_priv) >= 10) - intel_de_write_fw(dev_priv, PLANE_COLOR_CTL(pipe, plane_id), plane_color_ctl); + plane_ctl = plane_state->ctl | + skl_plane_ctl_crtc(crtc_state); /* * Enable the scaler before the plane so that we don't @@ -1193,8 +1288,6 @@ skl_plane_update_arm(struct intel_plane *plane, intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), plane_ctl); intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id), skl_plane_surf(plane_state, color_plane)); - - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } static void @@ -1204,7 +1297,6 @@ skl_plane_async_flip(struct intel_plane *plane, bool async_flip) { struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - unsigned long irqflags; enum plane_id plane_id = plane->id; enum pipe pipe = plane->pipe; u32 plane_ctl = plane_state->ctl; @@ -1214,13 +1306,9 @@ skl_plane_async_flip(struct intel_plane *plane, if (async_flip) plane_ctl |= PLANE_CTL_ASYNC_FLIP; - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); - intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), plane_ctl); intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id), skl_plane_surf(plane_state, 0)); - - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } static bool intel_format_is_p01x(u32 format) @@ -1325,7 +1413,7 @@ static int skl_plane_check_dst_coordinates(const struct intel_crtc_state *crtc_s to_i915(plane_state->uapi.plane->dev); int crtc_x = plane_state->uapi.dst.x1; int crtc_w = drm_rect_width(&plane_state->uapi.dst); - int pipe_src_w = crtc_state->pipe_src_w; + int pipe_src_w = drm_rect_width(&crtc_state->pipe_src); /* * Display WA #1175: glk @@ -1545,9 +1633,10 @@ static int skl_check_main_surface(struct intel_plane_state *plane_state) /* * CCS AUX surface doesn't have its own x/y offsets, we must make sure - * they match with the main surface x/y offsets. + * they match with the main surface x/y offsets. On DG2 + * there's no aux plane on fb so skip this checking. */ - if (intel_fb_is_ccs_modifier(fb->modifier)) { + if (intel_fb_is_ccs_modifier(fb->modifier) && aux_plane) { while (!skl_check_main_ccs_coordinates(plane_state, x, y, offset, aux_plane)) { if (offset == 0) @@ -1591,6 +1680,8 @@ static int skl_check_nv12_aux_surface(struct intel_plane_state *plane_state) const struct drm_framebuffer *fb = plane_state->hw.fb; unsigned int rotation = plane_state->hw.rotation; int uv_plane = 1; + int ccs_plane = intel_fb_is_ccs_modifier(fb->modifier) ? + skl_main_to_aux_plane(fb, uv_plane) : 0; int max_width = intel_plane_max_width(plane, fb, uv_plane, rotation); int max_height = intel_plane_max_height(plane, fb, uv_plane, rotation); int x = plane_state->uapi.src.x1 >> 17; @@ -1611,8 +1702,7 @@ static int skl_check_nv12_aux_surface(struct intel_plane_state *plane_state) offset = intel_plane_compute_aligned_offset(&x, &y, plane_state, uv_plane); - if (intel_fb_is_ccs_modifier(fb->modifier)) { - int ccs_plane = main_to_ccs_plane(fb, uv_plane); + if (ccs_plane) { u32 aux_offset = plane_state->view.color_plane[ccs_plane].offset; u32 alignment = intel_surf_alignment(fb, uv_plane); @@ -2011,9 +2101,7 @@ static bool gen12_plane_format_mod_supported(struct drm_plane *_plane, case DRM_FORMAT_Y216: case DRM_FORMAT_XVYU12_16161616: case DRM_FORMAT_XVYU16161616: - if (modifier == DRM_FORMAT_MOD_LINEAR || - modifier == I915_FORMAT_MOD_X_TILED || - modifier == I915_FORMAT_MOD_Y_TILED) + if (!intel_fb_is_ccs_modifier(modifier)) return true; fallthrough; default: @@ -2094,6 +2182,10 @@ static bool gen12_plane_has_mc_ccs(struct drm_i915_private *i915, if (IS_ADLP_DISPLAY_STEP(i915, STEP_A0, STEP_B0)) return false; + /* Wa_14013215631 */ + if (IS_DG2_DISPLAY_STEP(i915, STEP_A0, STEP_C0)) + return false; + return plane_id < PLANE_SPRITE4; } @@ -2106,6 +2198,8 @@ static u8 skl_get_plane_caps(struct drm_i915_private *i915, caps |= INTEL_PLANE_CAP_TILING_Y; if (DISPLAY_VER(i915) < 12) caps |= INTEL_PLANE_CAP_TILING_Yf; + if (HAS_4TILE(i915)) + caps |= INTEL_PLANE_CAP_TILING_4; if (skl_plane_has_rc_ccs(i915, pipe, plane_id)) { caps |= INTEL_PLANE_CAP_CCS_RC; @@ -2162,9 +2256,15 @@ skl_universal_plane_create(struct drm_i915_private *dev_priv, } plane->max_stride = skl_plane_max_stride; - plane->update_noarm = skl_plane_update_noarm; - plane->update_arm = skl_plane_update_arm; - plane->disable_arm = skl_plane_disable_arm; + if (DISPLAY_VER(dev_priv) >= 11) { + plane->update_noarm = icl_plane_update_noarm; + plane->update_arm = icl_plane_update_arm; + plane->disable_arm = icl_plane_disable_arm; + } else { + plane->update_noarm = skl_plane_update_noarm; + plane->update_arm = skl_plane_update_arm; + plane->disable_arm = skl_plane_disable_arm; + } plane->get_hw_state = skl_plane_get_hw_state; plane->check_plane = skl_plane_check; @@ -2278,13 +2378,14 @@ skl_get_initial_plane_config(struct intel_crtc *crtc, unsigned int aligned_height; struct drm_framebuffer *fb; struct intel_framebuffer *intel_fb; + static_assert(PLANE_CTL_TILED_YF == PLANE_CTL_TILED_4); if (!plane->get_hw_state(plane, &pipe)) return; drm_WARN_ON(dev, pipe != crtc->pipe); - if (crtc_state->bigjoiner) { + if (crtc_state->bigjoiner_pipes) { drm_dbg_kms(&dev_priv->drm, "Unsupported bigjoiner configuration for initial FB\n"); return; @@ -2332,19 +2433,34 @@ skl_get_initial_plane_config(struct intel_crtc *crtc, case PLANE_CTL_TILED_Y: plane_config->tiling = I915_TILING_Y; if (val & PLANE_CTL_RENDER_DECOMPRESSION_ENABLE) - fb->modifier = DISPLAY_VER(dev_priv) >= 12 ? - I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS : - I915_FORMAT_MOD_Y_TILED_CCS; + if (DISPLAY_VER(dev_priv) >= 12) + fb->modifier = I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS; + else + fb->modifier = I915_FORMAT_MOD_Y_TILED_CCS; else if (val & PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE) fb->modifier = I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS; else fb->modifier = I915_FORMAT_MOD_Y_TILED; break; - case PLANE_CTL_TILED_YF: - if (val & PLANE_CTL_RENDER_DECOMPRESSION_ENABLE) - fb->modifier = I915_FORMAT_MOD_Yf_TILED_CCS; - else - fb->modifier = I915_FORMAT_MOD_Yf_TILED; + case PLANE_CTL_TILED_YF: /* aka PLANE_CTL_TILED_4 on XE_LPD+ */ + if (HAS_4TILE(dev_priv)) { + u32 rc_mask = PLANE_CTL_RENDER_DECOMPRESSION_ENABLE | + PLANE_CTL_CLEAR_COLOR_DISABLE; + + if ((val & rc_mask) == rc_mask) + fb->modifier = I915_FORMAT_MOD_4_TILED_DG2_RC_CCS; + else if (val & PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE) + fb->modifier = I915_FORMAT_MOD_4_TILED_DG2_MC_CCS; + else if (val & PLANE_CTL_RENDER_DECOMPRESSION_ENABLE) + fb->modifier = I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC; + else + fb->modifier = I915_FORMAT_MOD_4_TILED; + } else { + if (val & PLANE_CTL_RENDER_DECOMPRESSION_ENABLE) + fb->modifier = I915_FORMAT_MOD_Yf_TILED_CCS; + else + fb->modifier = I915_FORMAT_MOD_Yf_TILED; + } break; default: MISSING_CASE(tiling); diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c index 0d936f658b3f..1954f07f0d3e 100644 --- a/drivers/gpu/drm/i915/display/vlv_dsi.c +++ b/drivers/gpu/drm/i915/display/vlv_dsi.c @@ -1660,6 +1660,8 @@ static const struct drm_connector_funcs intel_dsi_connector_funcs = { static void vlv_dsi_add_properties(struct intel_connector *connector) { struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + const struct drm_display_mode *fixed_mode = + intel_panel_preferred_fixed_mode(connector); u32 allowed_scalers; allowed_scalers = BIT(DRM_MODE_SCALE_ASPECT) | BIT(DRM_MODE_SCALE_FULLSCREEN); @@ -1673,8 +1675,8 @@ static void vlv_dsi_add_properties(struct intel_connector *connector) drm_connector_set_panel_orientation_with_quirk(&connector->base, intel_dsi_get_panel_orientation(connector), - connector->panel.fixed_mode->hdisplay, - connector->panel.fixed_mode->vdisplay); + fixed_mode->hdisplay, + fixed_mode->vdisplay); } #define NS_KHZ_RATIO 1000000 @@ -1857,7 +1859,7 @@ void vlv_dsi_init(struct drm_i915_private *dev_priv) struct drm_encoder *encoder; struct intel_connector *intel_connector; struct drm_connector *connector; - struct drm_display_mode *current_mode, *fixed_mode; + struct drm_display_mode *current_mode; enum port port; enum pipe pipe; @@ -1978,15 +1980,16 @@ void vlv_dsi_init(struct drm_i915_private *dev_priv) intel_connector_attach_encoder(intel_connector, intel_encoder); mutex_lock(&dev->mode_config.mutex); - fixed_mode = intel_panel_vbt_fixed_mode(intel_connector); + intel_panel_add_vbt_lfp_fixed_mode(intel_connector); mutex_unlock(&dev->mode_config.mutex); - if (!fixed_mode) { + if (!intel_panel_preferred_fixed_mode(intel_connector)) { drm_dbg_kms(&dev_priv->drm, "no fixed mode\n"); goto err_cleanup_connector; } - intel_panel_init(&intel_connector->panel, fixed_mode, NULL); + intel_panel_init(intel_connector); + intel_backlight_setup(intel_connector, INVALID_PIPE); vlv_dsi_add_properties(intel_connector); diff --git a/drivers/gpu/drm/i915/display/vlv_dsi_pll.c b/drivers/gpu/drm/i915/display/vlv_dsi_pll.c index df880f44700a..5894b0138343 100644 --- a/drivers/gpu/drm/i915/display/vlv_dsi_pll.c +++ b/drivers/gpu/drm/i915/display/vlv_dsi_pll.c @@ -26,6 +26,7 @@ */ #include <linux/kernel.h> +#include <linux/string_helpers.h> #include "i915_drv.h" #include "intel_de.h" @@ -393,10 +394,7 @@ static void glk_dsi_program_esc_clock(struct drm_device *dev, /* Calculate TXESC2 divider */ div2_value = DIV_ROUND_UP(div1_value, txesc1_div); - if (div2_value < 10) - txesc2_div = div2_value; - else - txesc2_div = 10; + txesc2_div = min_t(u32, div2_value, 10); intel_de_write(dev_priv, MIPIO_TXESC_CLK_DIV1, (1 << (txesc1_div - 1)) & GLK_TX_ESC_CLK_DIV1_MASK); @@ -581,7 +579,7 @@ static void assert_dsi_pll(struct drm_i915_private *i915, bool state) I915_STATE_WARN(cur_state != state, "DSI PLL state assertion failure (expected %s, current %s)\n", - onoff(state), onoff(cur_state)); + str_on_off(state), str_on_off(cur_state)); } void assert_dsi_pll_enabled(struct drm_i915_private *i915) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c index 9ae294eb7fb4..5db83aaf93ee 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c @@ -64,6 +64,7 @@ * */ +#include <linux/highmem.h> #include <linux/log2.h> #include <linux/nospec.h> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c index 78f8797853ce..fd0e15d9573c 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c @@ -4,8 +4,9 @@ * Copyright © 2008,2010 Intel Corporation */ -#include <linux/intel-iommu.h> #include <linux/dma-resv.h> +#include <linux/highmem.h> +#include <linux/intel-iommu.h> #include <linux/sync_file.h> #include <linux/uaccess.h> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c index 4115a222a853..02ed3b269326 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c @@ -3,6 +3,8 @@ * Copyright © 2019 Intel Corporation */ +#include <uapi/drm/i915_drm.h> + #include "intel_memory_region.h" #include "gem/i915_gem_region.h" #include "gem/i915_gem_lmem.h" diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c index 1c103c4dfaf4..747ac65e060f 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c @@ -22,6 +22,7 @@ * */ +#include <linux/highmem.h> #include <linux/sched/mm.h> #include <drm/drm_cache.h> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_phys.c b/drivers/gpu/drm/i915/gem/i915_gem_phys.c index ca6faffcc496..0d0e46dae559 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_phys.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_phys.c @@ -14,6 +14,7 @@ #include "i915_drv.h" #include "i915_gem_object.h" #include "i915_gem_region.h" +#include "i915_gem_tiling.h" #include "i915_scatterlist.h" static int i915_gem_object_get_pages_phys(struct drm_i915_gem_object *obj) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_region.c b/drivers/gpu/drm/i915/gem/i915_gem_region.c index 6cf94469d5a8..5866c88e4d02 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_region.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_region.c @@ -3,6 +3,8 @@ * Copyright © 2019 Intel Corporation */ +#include <uapi/drm/i915_drm.h> + #include "intel_memory_region.h" #include "i915_gem_region.h" #include "i915_drv.h" diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c index 3a1c782ed791..c7541dc687c1 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c @@ -12,8 +12,9 @@ #include "gem/i915_gem_region.h" #include "i915_drv.h" -#include "i915_gemfs.h" #include "i915_gem_object.h" +#include "i915_gem_tiling.h" +#include "i915_gemfs.h" #include "i915_scatterlist.h" #include "i915_trace.h" diff --git a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c index 0bf8f61134af..2a225daa2b12 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c @@ -15,6 +15,7 @@ #include "i915_drv.h" #include "i915_gem_stolen.h" #include "i915_reg.h" +#include "i915_utils.h" #include "i915_vgpu.h" #include "intel_mchbar_regs.h" @@ -401,7 +402,7 @@ static int i915_gem_init_stolen(struct intel_memory_region *mem) return 0; } - if (intel_vtd_active(i915) && GRAPHICS_VER(i915) < 8) { + if (i915_vtd_active(i915) && GRAPHICS_VER(i915) < 8) { drm_notice(&i915->drm, "%s, disabling use of stolen memory\n", "DMAR active"); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_tiling.c b/drivers/gpu/drm/i915/gem/i915_gem_tiling.c index d6adda5bf96b..80ac0db1ae8c 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_tiling.c @@ -219,6 +219,14 @@ i915_gem_object_fence_prepare(struct drm_i915_gem_object *obj, return ret; } +bool i915_gem_object_needs_bit17_swizzle(struct drm_i915_gem_object *obj) +{ + struct drm_i915_private *i915 = to_i915(obj->base.dev); + + return to_gt(i915)->ggtt->bit_6_swizzle_x == I915_BIT_6_SWIZZLE_9_10_17 && + i915_gem_object_is_tiled(obj); +} + int i915_gem_object_set_tiling(struct drm_i915_gem_object *obj, unsigned int tiling, unsigned int stride) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_tiling.h b/drivers/gpu/drm/i915/gem/i915_gem_tiling.h index 9924196a8139..6bd5751abf28 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_tiling.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_tiling.h @@ -8,8 +8,10 @@ #include <linux/types.h> +struct drm_i915_gem_object; struct drm_i915_private; +bool i915_gem_object_needs_bit17_swizzle(struct drm_i915_gem_object *obj); u32 i915_gem_fence_size(struct drm_i915_private *i915, u32 size, unsigned int tiling, unsigned int stride); u32 i915_gem_fence_alignment(struct drm_i915_private *i915, u32 size, diff --git a/drivers/gpu/drm/i915/gem/i915_gemfs.c b/drivers/gpu/drm/i915/gem/i915_gemfs.c index 7271fbf813fa..ee87874e59dc 100644 --- a/drivers/gpu/drm/i915/gem/i915_gemfs.c +++ b/drivers/gpu/drm/i915/gem/i915_gemfs.c @@ -9,6 +9,7 @@ #include "i915_drv.h" #include "i915_gemfs.h" +#include "i915_utils.h" int i915_gemfs_init(struct drm_i915_private *i915) { @@ -32,7 +33,7 @@ int i915_gemfs_init(struct drm_i915_private *i915) */ opts = NULL; - if (intel_vtd_active(i915)) { + if (i915_vtd_active(i915)) { if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) { opts = huge_opt; drm_info(&i915->drm, diff --git a/drivers/gpu/drm/i915/gem/selftests/huge_pages.c b/drivers/gpu/drm/i915/gem/selftests/huge_pages.c index 7a84fa68a99c..ef15967be51a 100644 --- a/drivers/gpu/drm/i915/gem/selftests/huge_pages.c +++ b/drivers/gpu/drm/i915/gem/selftests/huge_pages.c @@ -5,6 +5,8 @@ */ #include <linux/prime_numbers.h> +#include <linux/string_helpers.h> +#include <linux/swap.h> #include "i915_selftest.h" @@ -804,7 +806,7 @@ static int igt_mock_ppgtt_huge_fill(void *arg) if (vma->resource->page_sizes_gtt != expected_gtt) { pr_err("gtt=%u, expected=%u, size=%zd, single=%s\n", vma->resource->page_sizes_gtt, expected_gtt, - obj->base.size, yesno(!!single)); + obj->base.size, str_yes_no(!!single)); err = -EINVAL; break; } @@ -960,7 +962,7 @@ static int igt_mock_ppgtt_64K(void *arg) if (vma->resource->page_sizes_gtt != expected_gtt) { pr_err("gtt=%u, expected=%u, i=%d, single=%s\n", vma->resource->page_sizes_gtt, - expected_gtt, i, yesno(!!single)); + expected_gtt, i, str_yes_no(!!single)); err = -EINVAL; goto out_vma_unpin; } @@ -1706,14 +1708,14 @@ static int igt_shrink_thp(void *arg) I915_SHRINK_WRITEBACK); if (should_swap == i915_gem_object_has_pages(obj)) { pr_err("unexpected pages mismatch, should_swap=%s\n", - yesno(should_swap)); + str_yes_no(should_swap)); err = -EINVAL; goto out_put; } if (should_swap == (obj->mm.page_sizes.sg || obj->mm.page_sizes.phys)) { pr_err("unexpected residual page-size bits, should_swap=%s\n", - yesno(should_swap)); + str_yes_no(should_swap)); err = -EINVAL; goto out_put; } diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c index 7609db87df05..93a67422ca3b 100644 --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c @@ -5,6 +5,7 @@ */ #include <linux/prime_numbers.h> +#include <linux/string_helpers.h> #include "gem/i915_gem_internal.h" #include "gem/i915_gem_pm.h" @@ -700,7 +701,7 @@ static int igt_ctx_exec(void *arg) pr_err("Failed to fill dword %lu [%lu/%lu] with gpu (%s) [full-ppgtt? %s], err=%d\n", ndwords, dw, max_dwords(obj), engine->name, - yesno(i915_gem_context_has_full_ppgtt(ctx)), + str_yes_no(i915_gem_context_has_full_ppgtt(ctx)), err); intel_context_put(ce); kernel_context_close(ctx); @@ -834,7 +835,7 @@ static int igt_shared_ctx_exec(void *arg) pr_err("Failed to fill dword %lu [%lu/%lu] with gpu (%s) [full-ppgtt? %s], err=%d\n", ndwords, dw, max_dwords(obj), engine->name, - yesno(i915_gem_context_has_full_ppgtt(ctx)), + str_yes_no(i915_gem_context_has_full_ppgtt(ctx)), err); intel_context_put(ce); kernel_context_close(ctx); @@ -1415,7 +1416,7 @@ static int igt_ctx_readonly(void *arg) pr_err("Failed to fill dword %lu [%lu/%lu] with gpu (%s) [full-ppgtt? %s], err=%d\n", ndwords, dw, max_dwords(obj), ce->engine->name, - yesno(i915_gem_context_has_full_ppgtt(ctx)), + str_yes_no(i915_gem_context_has_full_ppgtt(ctx)), err); i915_gem_context_unlock_engines(ctx); goto out_file; diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c index dfc34cc2ef8c..5bc93a1ce3e3 100644 --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c @@ -4,6 +4,7 @@ * Copyright © 2016 Intel Corporation */ +#include <linux/highmem.h> #include <linux/prime_numbers.h> #include "gem/i915_gem_internal.h" diff --git a/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c b/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c index 209cf265bf74..9dc9dccf7b09 100644 --- a/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c +++ b/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c @@ -4,6 +4,7 @@ */ #include <linux/kthread.h> +#include <linux/string_helpers.h> #include <trace/events/dma_fence.h> #include <uapi/linux/sched/types.h> @@ -512,7 +513,7 @@ void intel_engine_print_breadcrumbs(struct intel_engine_cs *engine, if (!b) return; - drm_printf(p, "IRQ: %s\n", enableddisabled(b->irq_armed)); + drm_printf(p, "IRQ: %s\n", str_enabled_disabled(b->irq_armed)); if (!list_empty(&b->signalers)) print_signals(b, p); } diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c index e1aa78b20d2d..7447411a5b26 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c @@ -3,6 +3,8 @@ * Copyright © 2016 Intel Corporation */ +#include <linux/string_helpers.h> + #include <drm/drm_print.h> #include "gem/i915_gem_context.h" @@ -1706,9 +1708,8 @@ static void intel_engine_print_registers(struct intel_engine_cs *engine, u8 read, write; drm_printf(m, "\tExeclist tasklet queued? %s (%s), preempt? %s, timeslice? %s\n", - yesno(test_bit(TASKLET_STATE_SCHED, - &engine->sched_engine->tasklet.state)), - enableddisabled(!atomic_read(&engine->sched_engine->tasklet.count)), + str_yes_no(test_bit(TASKLET_STATE_SCHED, &engine->sched_engine->tasklet.state)), + str_enabled_disabled(!atomic_read(&engine->sched_engine->tasklet.count)), repr_timer(&engine->execlists.preempt), repr_timer(&engine->execlists.timer)); @@ -1969,7 +1970,7 @@ void intel_engine_dump(struct intel_engine_cs *engine, drm_printf(m, "\tAwake? %d\n", atomic_read(&engine->wakeref.count)); drm_printf(m, "\tBarriers?: %s\n", - yesno(!llist_empty(&engine->barrier_tasks))); + str_yes_no(!llist_empty(&engine->barrier_tasks))); drm_printf(m, "\tLatency: %luus\n", ewma__engine_latency_read(&engine->latency)); if (intel_engine_supports_stats(engine)) @@ -2011,7 +2012,7 @@ void intel_engine_dump(struct intel_engine_cs *engine, drm_printf(m, "HWSP:\n"); hexdump(m, engine->status_page.addr, PAGE_SIZE); - drm_printf(m, "Idle? %s\n", yesno(intel_engine_is_idle(engine))); + drm_printf(m, "Idle? %s\n", str_yes_no(intel_engine_is_idle(engine))); intel_engine_print_breadcrumbs(engine, m); } diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c index 3e0c81f06bd0..1c602d4ae297 100644 --- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c +++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c @@ -107,6 +107,7 @@ * */ #include <linux/interrupt.h> +#include <linux/string_helpers.h> #include "i915_drv.h" #include "i915_trace.h" @@ -1335,11 +1336,11 @@ static void execlists_dequeue(struct intel_engine_cs *engine) } else if (timeslice_expired(engine, last)) { ENGINE_TRACE(engine, "expired:%s last=%llx:%lld, prio=%d, hint=%d, yield?=%s\n", - yesno(timer_expired(&execlists->timer)), + str_yes_no(timer_expired(&execlists->timer)), last->fence.context, last->fence.seqno, rq_prio(last), sched_engine->queue_priority_hint, - yesno(timeslice_yield(execlists, last))); + str_yes_no(timeslice_yield(execlists, last))); /* * Consume this timeslice; ensure we start a new one. @@ -1427,7 +1428,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine) __i915_request_is_complete(rq) ? "!" : __i915_request_has_started(rq) ? "*" : "", - yesno(engine != ve->siblings[0])); + str_yes_no(engine != ve->siblings[0])); WRITE_ONCE(ve->request, NULL); WRITE_ONCE(ve->base.sched_engine->queue_priority_hint, INT_MIN); diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt.c b/drivers/gpu/drm/i915/gt/intel_ggtt.c index 8850d4e0f9cc..e164f30a900d 100644 --- a/drivers/gpu/drm/i915/gt/intel_ggtt.c +++ b/drivers/gpu/drm/i915/gt/intel_ggtt.c @@ -18,6 +18,7 @@ #include "intel_gt_regs.h" #include "i915_drv.h" #include "i915_scatterlist.h" +#include "i915_utils.h" #include "i915_vgpu.h" #include "intel_gtt.h" @@ -104,7 +105,7 @@ static bool needs_idle_maps(struct drm_i915_private *i915) * Query intel_iommu to see if we need the workaround. Presumably that * was loaded first. */ - if (!intel_vtd_active(i915)) + if (!i915_vtd_active(i915)) return false; if (GRAPHICS_VER(i915) == 5 && IS_MOBILE(i915)) @@ -1256,7 +1257,7 @@ int i915_ggtt_probe_hw(struct drm_i915_private *i915) if (ret) return ret; - if (intel_vtd_active(i915)) + if (i915_vtd_active(i915)) drm_info(&i915->drm, "VT-d active for gfx access\n"); return 0; diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c b/drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c index 76880fb8fc19..6ebda3d65086 100644 --- a/drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c +++ b/drivers/gpu/drm/i915/gt/intel_ggtt_fencing.c @@ -3,6 +3,8 @@ * Copyright © 2008-2015 Intel Corporation */ +#include <linux/highmem.h> + #include "i915_drv.h" #include "i915_reg.h" #include "i915_scatterlist.h" diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm.c b/drivers/gpu/drm/i915/gt/intel_gt_pm.c index c0fa41e4c803..e4ecc17889d3 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_pm.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm.c @@ -3,6 +3,7 @@ * Copyright © 2019 Intel Corporation */ +#include <linux/string_helpers.h> #include <linux/suspend.h> #include "i915_drv.h" @@ -157,7 +158,7 @@ static void gt_sanitize(struct intel_gt *gt, bool force) enum intel_engine_id id; intel_wakeref_t wakeref; - GT_TRACE(gt, "force:%s", yesno(force)); + GT_TRACE(gt, "force:%s", str_yes_no(force)); /* Use a raw wakeref to avoid calling intel_display_power_get early */ wakeref = intel_runtime_pm_get(gt->uncore->rpm); diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c b/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c index 37765919fe32..437e96bb3b93 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c @@ -5,6 +5,7 @@ */ #include <linux/seq_file.h> +#include <linux/string_helpers.h> #include "i915_drv.h" #include "i915_reg.h" @@ -105,14 +106,14 @@ static int vlv_drpc(struct seq_file *m) rcctl1 = intel_uncore_read(uncore, GEN6_RC_CONTROL); seq_printf(m, "RC6 Enabled: %s\n", - yesno(rcctl1 & (GEN7_RC_CTL_TO_MODE | + str_yes_no(rcctl1 & (GEN7_RC_CTL_TO_MODE | GEN6_RC_CTL_EI_MODE(1)))); seq_printf(m, "Render Power Well: %s\n", (pw_status & VLV_GTLC_PW_RENDER_STATUS_MASK) ? "Up" : "Down"); seq_printf(m, "Media Power Well: %s\n", (pw_status & VLV_GTLC_PW_MEDIA_STATUS_MASK) ? "Up" : "Down"); - print_rc6_res(m, "Render RC6 residency since boot:", VLV_GT_RENDER_RC6); + print_rc6_res(m, "Render RC6 residency since boot:", GEN6_GT_GFX_RC6); print_rc6_res(m, "Media RC6 residency since boot:", VLV_GT_MEDIA_RC6); return fw_domains_show(m, NULL); @@ -140,19 +141,19 @@ static int gen6_drpc(struct seq_file *m) snb_pcode_read(i915, GEN6_PCODE_READ_RC6VIDS, &rc6vids, NULL); seq_printf(m, "RC1e Enabled: %s\n", - yesno(rcctl1 & GEN6_RC_CTL_RC1e_ENABLE)); + str_yes_no(rcctl1 & GEN6_RC_CTL_RC1e_ENABLE)); seq_printf(m, "RC6 Enabled: %s\n", - yesno(rcctl1 & GEN6_RC_CTL_RC6_ENABLE)); + str_yes_no(rcctl1 & GEN6_RC_CTL_RC6_ENABLE)); if (GRAPHICS_VER(i915) >= 9) { seq_printf(m, "Render Well Gating Enabled: %s\n", - yesno(gen9_powergate_enable & GEN9_RENDER_PG_ENABLE)); + str_yes_no(gen9_powergate_enable & GEN9_RENDER_PG_ENABLE)); seq_printf(m, "Media Well Gating Enabled: %s\n", - yesno(gen9_powergate_enable & GEN9_MEDIA_PG_ENABLE)); + str_yes_no(gen9_powergate_enable & GEN9_MEDIA_PG_ENABLE)); } seq_printf(m, "Deep RC6 Enabled: %s\n", - yesno(rcctl1 & GEN6_RC_CTL_RC6p_ENABLE)); + str_yes_no(rcctl1 & GEN6_RC_CTL_RC6p_ENABLE)); seq_printf(m, "Deepest RC6 Enabled: %s\n", - yesno(rcctl1 & GEN6_RC_CTL_RC6pp_ENABLE)); + str_yes_no(rcctl1 & GEN6_RC_CTL_RC6pp_ENABLE)); seq_puts(m, "Current RC state: "); switch (gt_core_status & GEN6_RCn_MASK) { case GEN6_RC0: @@ -176,7 +177,7 @@ static int gen6_drpc(struct seq_file *m) } seq_printf(m, "Core Power Down: %s\n", - yesno(gt_core_status & GEN6_CORE_CPD_STATE_MASK)); + str_yes_no(gt_core_status & GEN6_CORE_CPD_STATE_MASK)); if (GRAPHICS_VER(i915) >= 9) { seq_printf(m, "Render Power Well: %s\n", (gen9_powergate_status & @@ -216,16 +217,17 @@ static int ilk_drpc(struct seq_file *m) rstdbyctl = intel_uncore_read(uncore, RSTDBYCTL); crstandvid = intel_uncore_read16(uncore, CRSTANDVID); - seq_printf(m, "HD boost: %s\n", yesno(rgvmodectl & MEMMODE_BOOST_EN)); + seq_printf(m, "HD boost: %s\n", + str_yes_no(rgvmodectl & MEMMODE_BOOST_EN)); seq_printf(m, "Boost freq: %d\n", (rgvmodectl & MEMMODE_BOOST_FREQ_MASK) >> MEMMODE_BOOST_FREQ_SHIFT); seq_printf(m, "HW control enabled: %s\n", - yesno(rgvmodectl & MEMMODE_HWIDLE_EN)); + str_yes_no(rgvmodectl & MEMMODE_HWIDLE_EN)); seq_printf(m, "SW control enabled: %s\n", - yesno(rgvmodectl & MEMMODE_SWMODE_EN)); + str_yes_no(rgvmodectl & MEMMODE_SWMODE_EN)); seq_printf(m, "Gated voltage change: %s\n", - yesno(rgvmodectl & MEMMODE_RCLK_GATE)); + str_yes_no(rgvmodectl & MEMMODE_RCLK_GATE)); seq_printf(m, "Starting frequency: P%d\n", (rgvmodectl & MEMMODE_FSTART_MASK) >> MEMMODE_FSTART_SHIFT); seq_printf(m, "Max P-state: P%d\n", @@ -234,7 +236,7 @@ static int ilk_drpc(struct seq_file *m) seq_printf(m, "RS1 VID: %d\n", (crstandvid & 0x3f)); seq_printf(m, "RS2 VID: %d\n", ((crstandvid >> 8) & 0x3f)); seq_printf(m, "Render standby enabled: %s\n", - yesno(!(rstdbyctl & RCX_SW_EXIT))); + str_yes_no(!(rstdbyctl & RCX_SW_EXIT))); seq_puts(m, "Current RS state: "); switch (rstdbyctl & RSX_STATUS_MASK) { case RSX_STATUS_ON: @@ -307,12 +309,11 @@ void intel_gt_pm_frequency_dump(struct intel_gt *gt, struct drm_printer *p) rpmodectl = intel_uncore_read(uncore, GEN6_RP_CONTROL); drm_printf(p, "Video Turbo Mode: %s\n", - yesno(rpmodectl & GEN6_RP_MEDIA_TURBO)); + str_yes_no(rpmodectl & GEN6_RP_MEDIA_TURBO)); drm_printf(p, "HW control enabled: %s\n", - yesno(rpmodectl & GEN6_RP_ENABLE)); + str_yes_no(rpmodectl & GEN6_RP_ENABLE)); drm_printf(p, "SW control enabled: %s\n", - yesno((rpmodectl & GEN6_RP_MEDIA_MODE_MASK) == - GEN6_RP_MEDIA_SW_MODE)); + str_yes_no((rpmodectl & GEN6_RP_MEDIA_MODE_MASK) == GEN6_RP_MEDIA_SW_MODE)); vlv_punit_get(i915); freq_sts = vlv_punit_read(i915, PUNIT_REG_GPU_FREQ_STS); @@ -417,12 +418,11 @@ void intel_gt_pm_frequency_dump(struct intel_gt *gt, struct drm_printer *p) pm_mask = intel_uncore_read(uncore, GEN6_PMINTRMSK); drm_printf(p, "Video Turbo Mode: %s\n", - yesno(rpmodectl & GEN6_RP_MEDIA_TURBO)); + str_yes_no(rpmodectl & GEN6_RP_MEDIA_TURBO)); drm_printf(p, "HW control enabled: %s\n", - yesno(rpmodectl & GEN6_RP_ENABLE)); + str_yes_no(rpmodectl & GEN6_RP_ENABLE)); drm_printf(p, "SW control enabled: %s\n", - yesno((rpmodectl & GEN6_RP_MEDIA_MODE_MASK) == - GEN6_RP_MEDIA_SW_MODE)); + str_yes_no((rpmodectl & GEN6_RP_MEDIA_MODE_MASK) == GEN6_RP_MEDIA_SW_MODE)); drm_printf(p, "PM IER=0x%08x IMR=0x%08x, MASK=0x%08x\n", pm_ier, pm_imr, pm_mask); @@ -542,7 +542,7 @@ static int llc_show(struct seq_file *m, void *data) intel_wakeref_t wakeref; int gpu_freq, ia_freq; - seq_printf(m, "LLC: %s\n", yesno(HAS_LLC(i915))); + seq_printf(m, "LLC: %s\n", str_yes_no(HAS_LLC(i915))); seq_printf(m, "%s: %uMB\n", edram ? "eDRAM" : "eLLC", i915->edram_size_mb); @@ -604,10 +604,12 @@ static int rps_boost_show(struct seq_file *m, void *data) struct drm_i915_private *i915 = gt->i915; struct intel_rps *rps = >->rps; - seq_printf(m, "RPS enabled? %s\n", yesno(intel_rps_is_enabled(rps))); - seq_printf(m, "RPS active? %s\n", yesno(intel_rps_is_active(rps))); + seq_printf(m, "RPS enabled? %s\n", + str_yes_no(intel_rps_is_enabled(rps))); + seq_printf(m, "RPS active? %s\n", + str_yes_no(intel_rps_is_active(rps))); seq_printf(m, "GPU busy? %s, %llums\n", - yesno(gt->awake), + str_yes_no(gt->awake), ktime_to_ms(intel_gt_get_awake_time(gt))); seq_printf(m, "Boosts outstanding? %d\n", atomic_read(&rps->num_waiters)); diff --git a/drivers/gpu/drm/i915/gt/intel_gt_regs.h b/drivers/gpu/drm/i915/gt/intel_gt_regs.h index 19cd34f24263..201b507c9dde 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_regs.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_regs.h @@ -1440,7 +1440,6 @@ #define VLV_MEDIA_RC6_COUNT_EN (1 << 1) #define VLV_RENDER_RC6_COUNT_EN (1 << 0) #define GEN6_GT_GFX_RC6 _MMIO(0x138108) -#define VLV_GT_RENDER_RC6 _MMIO(0x138108) #define VLV_GT_MEDIA_RC6 _MMIO(0x13810c) #define GEN6_GT_GFX_RC6p _MMIO(0x13810c) diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.c b/drivers/gpu/drm/i915/gt/intel_gtt.c index a5f5b2dda332..cc53b481a1c5 100644 --- a/drivers/gpu/drm/i915/gt/intel_gtt.c +++ b/drivers/gpu/drm/i915/gt/intel_gtt.c @@ -13,10 +13,22 @@ #include "gem/i915_gem_internal.h" #include "gem/i915_gem_lmem.h" #include "i915_trace.h" +#include "i915_utils.h" #include "intel_gt.h" #include "intel_gt_regs.h" #include "intel_gtt.h" + +static bool intel_ggtt_update_needs_vtd_wa(struct drm_i915_private *i915) +{ + return IS_BROXTON(i915) && i915_vtd_active(i915); +} + +bool intel_vm_no_concurrent_access_wa(struct drm_i915_private *i915) +{ + return IS_CHERRYVIEW(i915) || intel_ggtt_update_needs_vtd_wa(i915); +} + struct drm_i915_gem_object *alloc_pt_lmem(struct i915_address_space *vm, int sz) { struct drm_i915_gem_object *obj; diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.h b/drivers/gpu/drm/i915/gt/intel_gtt.h index 9d83c2d3959c..ba7025388a5e 100644 --- a/drivers/gpu/drm/i915/gt/intel_gtt.h +++ b/drivers/gpu/drm/i915/gt/intel_gtt.h @@ -383,6 +383,8 @@ struct i915_ppgtt { #define i915_is_dpt(vm) ((vm)->is_dpt) #define i915_is_ggtt_or_dpt(vm) (i915_is_ggtt(vm) || i915_is_dpt(vm)) +bool intel_vm_no_concurrent_access_wa(struct drm_i915_private *i915); + int __must_check i915_vm_lock_objects(struct i915_address_space *vm, struct i915_gem_ww_ctx *ww); diff --git a/drivers/gpu/drm/i915/gt/intel_rc6.c b/drivers/gpu/drm/i915/gt/intel_rc6.c index 6df359c534fe..63db136cbc27 100644 --- a/drivers/gpu/drm/i915/gt/intel_rc6.c +++ b/drivers/gpu/drm/i915/gt/intel_rc6.c @@ -4,6 +4,7 @@ */ #include <linux/pm_runtime.h> +#include <linux/string_helpers.h> #include "i915_drv.h" #include "i915_reg.h" @@ -430,8 +431,8 @@ static bool bxt_check_bios_rc6_setup(struct intel_rc6 *rc6) rc_sw_target >>= RC_SW_TARGET_STATE_SHIFT; drm_dbg(&i915->drm, "BIOS enabled RC states: " "HW_CTRL %s HW_RC6 %s SW_TARGET_STATE %x\n", - onoff(rc_ctl & GEN6_RC_CTL_HW_ENABLE), - onoff(rc_ctl & GEN6_RC_CTL_RC6_ENABLE), + str_on_off(rc_ctl & GEN6_RC_CTL_HW_ENABLE), + str_on_off(rc_ctl & GEN6_RC_CTL_RC6_ENABLE), rc_sw_target); if (!(intel_uncore_read(uncore, RC6_LOCATION) & RC6_CTX_IN_DRAM)) { diff --git a/drivers/gpu/drm/i915/gt/intel_reset.c b/drivers/gpu/drm/i915/gt/intel_reset.c index 82713264b96c..a6ae213c7d89 100644 --- a/drivers/gpu/drm/i915/gt/intel_reset.c +++ b/drivers/gpu/drm/i915/gt/intel_reset.c @@ -5,6 +5,7 @@ #include <linux/sched/mm.h> #include <linux/stop_machine.h> +#include <linux/string_helpers.h> #include "display/intel_display.h" #include "display/intel_overlay.h" @@ -137,7 +138,7 @@ void __i915_request_reset(struct i915_request *rq, bool guilty) { bool banned = false; - RQ_TRACE(rq, "guilty? %s\n", yesno(guilty)); + RQ_TRACE(rq, "guilty? %s\n", str_yes_no(guilty)); GEM_BUG_ON(__i915_request_is_complete(rq)); rcu_read_lock(); /* protect the GEM context */ diff --git a/drivers/gpu/drm/i915/gt/intel_rps.c b/drivers/gpu/drm/i915/gt/intel_rps.c index c8124101aada..a9c13b1a3018 100644 --- a/drivers/gpu/drm/i915/gt/intel_rps.c +++ b/drivers/gpu/drm/i915/gt/intel_rps.c @@ -3,6 +3,8 @@ * Copyright © 2019 Intel Corporation */ +#include <linux/string_helpers.h> + #include <drm/i915_drm.h> #include "i915_drv.h" @@ -772,7 +774,8 @@ static void gen6_rps_set_thresholds(struct intel_rps *rps, u8 val) void intel_rps_mark_interactive(struct intel_rps *rps, bool interactive) { - GT_TRACE(rps_to_gt(rps), "mark interactive: %s\n", yesno(interactive)); + GT_TRACE(rps_to_gt(rps), "mark interactive: %s\n", + str_yes_no(interactive)); mutex_lock(&rps->power.mutex); if (interactive) { @@ -1279,7 +1282,8 @@ static bool chv_rps_enable(struct intel_rps *rps) drm_WARN_ONCE(&i915->drm, (val & GPLLENABLE) == 0, "GPLL not enabled\n"); - drm_dbg(&i915->drm, "GPLL enabled? %s\n", yesno(val & GPLLENABLE)); + drm_dbg(&i915->drm, "GPLL enabled? %s\n", + str_yes_no(val & GPLLENABLE)); drm_dbg(&i915->drm, "GPU status: 0x%08x\n", val); return rps_reset(rps); @@ -1380,7 +1384,8 @@ static bool vlv_rps_enable(struct intel_rps *rps) drm_WARN_ONCE(&i915->drm, (val & GPLLENABLE) == 0, "GPLL not enabled\n"); - drm_dbg(&i915->drm, "GPLL enabled? %s\n", yesno(val & GPLLENABLE)); + drm_dbg(&i915->drm, "GPLL enabled? %s\n", + str_yes_no(val & GPLLENABLE)); drm_dbg(&i915->drm, "GPU status: 0x%08x\n", val); return rps_reset(rps); @@ -1772,7 +1777,7 @@ static void rps_work(struct work_struct *work) GT_TRACE(gt, "pm_iir:%x, client_boost:%s, last:%d, cur:%x, min:%x, max:%x\n", - pm_iir, yesno(client_boost), + pm_iir, str_yes_no(client_boost), adj, new_freq, min, max); if (client_boost && new_freq < rps->boost_freq) { diff --git a/drivers/gpu/drm/i915/gt/intel_sseu.c b/drivers/gpu/drm/i915/gt/intel_sseu.c index 4ac0bbaf0c31..614915ffbd37 100644 --- a/drivers/gpu/drm/i915/gt/intel_sseu.c +++ b/drivers/gpu/drm/i915/gt/intel_sseu.c @@ -3,6 +3,8 @@ * Copyright © 2019 Intel Corporation */ +#include <linux/string_helpers.h> + #include "i915_drv.h" #include "intel_engine_regs.h" #include "intel_gt_regs.h" @@ -711,10 +713,11 @@ void intel_sseu_dump(const struct sseu_dev_info *sseu, struct drm_printer *p) drm_printf(p, "EU total: %u\n", sseu->eu_total); drm_printf(p, "EU per subslice: %u\n", sseu->eu_per_subslice); drm_printf(p, "has slice power gating: %s\n", - yesno(sseu->has_slice_pg)); + str_yes_no(sseu->has_slice_pg)); drm_printf(p, "has subslice power gating: %s\n", - yesno(sseu->has_subslice_pg)); - drm_printf(p, "has EU power gating: %s\n", yesno(sseu->has_eu_pg)); + str_yes_no(sseu->has_subslice_pg)); + drm_printf(p, "has EU power gating: %s\n", + str_yes_no(sseu->has_eu_pg)); } void intel_sseu_print_topology(const struct sseu_dev_info *sseu, diff --git a/drivers/gpu/drm/i915/gt/intel_sseu_debugfs.c b/drivers/gpu/drm/i915/gt/intel_sseu_debugfs.c index 903626f106ea..a9d5bc49f361 100644 --- a/drivers/gpu/drm/i915/gt/intel_sseu_debugfs.c +++ b/drivers/gpu/drm/i915/gt/intel_sseu_debugfs.c @@ -4,6 +4,8 @@ * Copyright © 2020 Intel Corporation */ +#include <linux/string_helpers.h> + #include "i915_drv.h" #include "intel_gt_debugfs.h" #include "intel_gt_regs.h" @@ -226,16 +228,16 @@ static void i915_print_sseu_info(struct seq_file *m, if (!is_available_info) return; - seq_printf(m, " Has Pooled EU: %s\n", yesno(has_pooled_eu)); + seq_printf(m, " Has Pooled EU: %s\n", str_yes_no(has_pooled_eu)); if (has_pooled_eu) seq_printf(m, " Min EU in pool: %u\n", sseu->min_eu_in_pool); seq_printf(m, " Has Slice Power Gating: %s\n", - yesno(sseu->has_slice_pg)); + str_yes_no(sseu->has_slice_pg)); seq_printf(m, " Has Subslice Power Gating: %s\n", - yesno(sseu->has_subslice_pg)); + str_yes_no(sseu->has_subslice_pg)); seq_printf(m, " Has EU Power Gating: %s\n", - yesno(sseu->has_eu_pg)); + str_yes_no(sseu->has_eu_pg)); } /* diff --git a/drivers/gpu/drm/i915/gt/selftest_timeline.c b/drivers/gpu/drm/i915/gt/selftest_timeline.c index 0410c402f2a3..522d0190509c 100644 --- a/drivers/gpu/drm/i915/gt/selftest_timeline.c +++ b/drivers/gpu/drm/i915/gt/selftest_timeline.c @@ -4,6 +4,7 @@ */ #include <linux/prime_numbers.h> +#include <linux/string_helpers.h> #include "intel_context.h" #include "intel_engine_heartbeat.h" @@ -209,7 +210,7 @@ static int __igt_sync(struct intel_timeline *tl, if (__intel_timeline_sync_is_later(tl, ctx, p->seqno) != p->expected) { pr_err("%s: %s(ctx=%llu, seqno=%u) expected passed %s but failed\n", - name, p->name, ctx, p->seqno, yesno(p->expected)); + name, p->name, ctx, p->seqno, str_yes_no(p->expected)); return -EINVAL; } diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c index 2f7fc87a78e1..f01325cd1b62 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c @@ -6,6 +6,7 @@ #include <linux/circ_buf.h> #include <linux/ktime.h> #include <linux/time64.h> +#include <linux/string_helpers.h> #include <linux/timekeeping.h> #include "i915_drv.h" @@ -170,7 +171,7 @@ static int ct_control_enable(struct intel_guc_ct *ct, bool enable) GUC_CTB_CONTROL_ENABLE : GUC_CTB_CONTROL_DISABLE); if (unlikely(err)) CT_PROBE_ERROR(ct, "Failed to control/%s CTB (%pe)\n", - enabledisable(enable), ERR_PTR(err)); + str_enable_disable(enable), ERR_PTR(err)); return err; } @@ -1202,7 +1203,7 @@ void intel_guc_ct_event_handler(struct intel_guc_ct *ct) void intel_guc_ct_print_info(struct intel_guc_ct *ct, struct drm_printer *p) { - drm_printf(p, "CT %s\n", enableddisabled(ct->enabled)); + drm_printf(p, "CT %s\n", str_enabled_disabled(ct->enabled)); if (!ct->enabled) return; diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c index b53f61f3101f..a24dc6441872 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c @@ -4,6 +4,7 @@ */ #include <linux/debugfs.h> +#include <linux/string_helpers.h> #include "gt/intel_gt.h" #include "i915_drv.h" @@ -476,8 +477,8 @@ int intel_guc_log_create(struct intel_guc_log *log) log->level = __get_default_log_level(log); DRM_DEBUG_DRIVER("guc_log_level=%d (%s, verbose:%s, verbosity:%d)\n", - log->level, enableddisabled(log->level), - yesno(GUC_LOG_LEVEL_IS_VERBOSE(log->level)), + log->level, str_enabled_disabled(log->level), + str_yes_no(GUC_LOG_LEVEL_IS_VERBOSE(log->level)), GUC_LOG_LEVEL_TO_VERBOSITY(log->level)); return 0; diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_rc.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_rc.c index fc805d466d99..e00661fb0853 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_rc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_rc.c @@ -3,6 +3,8 @@ * Copyright © 2021 Intel Corporation */ +#include <linux/string_helpers.h> + #include "intel_guc_rc.h" #include "gt/intel_gt.h" #include "i915_drv.h" @@ -59,12 +61,12 @@ static int __guc_rc_control(struct intel_guc *guc, bool enable) ret = guc_action_control_gucrc(guc, enable); if (ret) { drm_err(drm, "Failed to %s GuC RC (%pe)\n", - enabledisable(enable), ERR_PTR(ret)); + str_enable_disable(enable), ERR_PTR(ret)); return ret; } drm_info(>->i915->drm, "GuC RC: %s\n", - enableddisabled(enable)); + str_enabled_disabled(enable)); return 0; } diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c index ac749ab11035..9f032c65a488 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c @@ -4,6 +4,7 @@ */ #include <drm/drm_cache.h> +#include <linux/string_helpers.h> #include "i915_drv.h" #include "i915_reg.h" @@ -719,7 +720,7 @@ int intel_guc_slpc_print_info(struct intel_guc_slpc *slpc, struct drm_printer *p drm_printf(p, "\tSLPC state: %s\n", slpc_get_state_string(slpc)); drm_printf(p, "\tGTPERF task active: %s\n", - yesno(slpc_tasks->status & SLPC_GTPERF_TASK_ENABLED)); + str_yes_no(slpc_tasks->status & SLPC_GTPERF_TASK_ENABLED)); drm_printf(p, "\tMax freq: %u MHz\n", slpc_decode_max_freq(slpc)); drm_printf(p, "\tMin freq: %u MHz\n", diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc.c b/drivers/gpu/drm/i915/gt/uc/intel_uc.c index da199aa6989f..8c9ef690ac9d 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_uc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_uc.c @@ -3,6 +3,8 @@ * Copyright © 2016-2019 Intel Corporation */ +#include <linux/string_helpers.h> + #include "gt/intel_gt.h" #include "gt/intel_reset.h" #include "intel_guc.h" @@ -78,10 +80,10 @@ static void __confirm_options(struct intel_uc *uc) drm_dbg(&i915->drm, "enable_guc=%d (guc:%s submission:%s huc:%s slpc:%s)\n", i915->params.enable_guc, - yesno(intel_uc_wants_guc(uc)), - yesno(intel_uc_wants_guc_submission(uc)), - yesno(intel_uc_wants_huc(uc)), - yesno(intel_uc_wants_guc_slpc(uc))); + str_yes_no(intel_uc_wants_guc(uc)), + str_yes_no(intel_uc_wants_guc_submission(uc)), + str_yes_no(intel_uc_wants_huc(uc)), + str_yes_no(intel_uc_wants_guc_slpc(uc))); if (i915->params.enable_guc == 0) { GEM_BUG_ON(intel_uc_wants_guc(uc)); @@ -522,9 +524,9 @@ static int __uc_init_hw(struct intel_uc *uc) } drm_info(&i915->drm, "GuC submission %s\n", - enableddisabled(intel_uc_uses_guc_submission(uc))); + str_enabled_disabled(intel_uc_uses_guc_submission(uc))); drm_info(&i915->drm, "GuC SLPC %s\n", - enableddisabled(intel_uc_uses_guc_slpc(uc))); + str_enabled_disabled(intel_uc_uses_guc_slpc(uc))); return 0; diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc_debugfs.c b/drivers/gpu/drm/i915/gt/uc/intel_uc_debugfs.c index c2f7924295e7..284d6fbc2d08 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_uc_debugfs.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_uc_debugfs.c @@ -4,6 +4,8 @@ */ #include <linux/debugfs.h> +#include <linux/string_helpers.h> + #include <drm/drm_print.h> #include "gt/intel_gt_debugfs.h" @@ -18,17 +20,17 @@ static int uc_usage_show(struct seq_file *m, void *data) struct drm_printer p = drm_seq_file_printer(m); drm_printf(&p, "[guc] supported:%s wanted:%s used:%s\n", - yesno(intel_uc_supports_guc(uc)), - yesno(intel_uc_wants_guc(uc)), - yesno(intel_uc_uses_guc(uc))); + str_yes_no(intel_uc_supports_guc(uc)), + str_yes_no(intel_uc_wants_guc(uc)), + str_yes_no(intel_uc_uses_guc(uc))); drm_printf(&p, "[huc] supported:%s wanted:%s used:%s\n", - yesno(intel_uc_supports_huc(uc)), - yesno(intel_uc_wants_huc(uc)), - yesno(intel_uc_uses_huc(uc))); + str_yes_no(intel_uc_supports_huc(uc)), + str_yes_no(intel_uc_wants_huc(uc)), + str_yes_no(intel_uc_uses_huc(uc))); drm_printf(&p, "[submission] supported:%s wanted:%s used:%s\n", - yesno(intel_uc_supports_guc_submission(uc)), - yesno(intel_uc_wants_guc_submission(uc)), - yesno(intel_uc_uses_guc_submission(uc))); + str_yes_no(intel_uc_supports_guc_submission(uc)), + str_yes_no(intel_uc_wants_guc_submission(uc)), + str_yes_no(intel_uc_uses_guc_submission(uc))); return 0; } diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c index c88113044494..541f180aaa29 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c @@ -5,6 +5,7 @@ #include <linux/bitfield.h> #include <linux/firmware.h> +#include <linux/highmem.h> #include <drm/drm_cache.h> #include <drm/drm_print.h> diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c index 520a7e1942f3..57b0f4977760 100644 --- a/drivers/gpu/drm/i915/gvt/handlers.c +++ b/drivers/gpu/drm/i915/gvt/handlers.c @@ -42,6 +42,7 @@ #include "i915_pvinfo.h" #include "intel_mchbar_regs.h" #include "display/intel_display_types.h" +#include "display/intel_dmc_regs.h" #include "display/intel_fbc.h" #include "display/vlv_dsi_pll_regs.h" #include "gt/intel_gt_regs.h" @@ -576,14 +577,19 @@ static u32 bxt_vgpu_get_dp_bitrate(struct intel_vgpu *vgpu, enum port port) } clock.m1 = 2; - clock.m2 = (vgpu_vreg_t(vgpu, BXT_PORT_PLL(phy, ch, 0)) & PORT_PLL_M2_MASK) << 22; + clock.m2 = REG_FIELD_GET(PORT_PLL_M2_INT_MASK, + vgpu_vreg_t(vgpu, BXT_PORT_PLL(phy, ch, 0))) << 22; if (vgpu_vreg_t(vgpu, BXT_PORT_PLL(phy, ch, 3)) & PORT_PLL_M2_FRAC_ENABLE) - clock.m2 |= vgpu_vreg_t(vgpu, BXT_PORT_PLL(phy, ch, 2)) & PORT_PLL_M2_FRAC_MASK; - clock.n = (vgpu_vreg_t(vgpu, BXT_PORT_PLL(phy, ch, 1)) & PORT_PLL_N_MASK) >> PORT_PLL_N_SHIFT; - clock.p1 = (vgpu_vreg_t(vgpu, BXT_PORT_PLL_EBB_0(phy, ch)) & PORT_PLL_P1_MASK) >> PORT_PLL_P1_SHIFT; - clock.p2 = (vgpu_vreg_t(vgpu, BXT_PORT_PLL_EBB_0(phy, ch)) & PORT_PLL_P2_MASK) >> PORT_PLL_P2_SHIFT; + clock.m2 |= REG_FIELD_GET(PORT_PLL_M2_FRAC_MASK, + vgpu_vreg_t(vgpu, BXT_PORT_PLL(phy, ch, 2))); + clock.n = REG_FIELD_GET(PORT_PLL_N_MASK, + vgpu_vreg_t(vgpu, BXT_PORT_PLL(phy, ch, 1))); + clock.p1 = REG_FIELD_GET(PORT_PLL_P1_MASK, + vgpu_vreg_t(vgpu, BXT_PORT_PLL_EBB_0(phy, ch))); + clock.p2 = REG_FIELD_GET(PORT_PLL_P2_MASK, + vgpu_vreg_t(vgpu, BXT_PORT_PLL_EBB_0(phy, ch))); clock.m = clock.m1 * clock.m2; - clock.p = clock.p1 * clock.p2; + clock.p = clock.p1 * clock.p2 * 5; if (clock.n == 0 || clock.p == 0) { gvt_dbg_dpy("vgpu-%d PORT_%c PLL has invalid divider\n", vgpu->id, port_name(port)); @@ -593,7 +599,7 @@ static u32 bxt_vgpu_get_dp_bitrate(struct intel_vgpu *vgpu, enum port port) clock.vco = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(refclk, clock.m), clock.n << 22); clock.dot = DIV_ROUND_CLOSEST(clock.vco, clock.p); - dp_br = clock.dot / 5; + dp_br = clock.dot; out: return dp_br; diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index 5f6e41636655..f93e6122f247 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -25,6 +25,8 @@ * */ +#include <linux/highmem.h> + #include <drm/drm_cache.h> #include "gt/intel_engine.h" diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 946bbe57bfe5..02239395ce81 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -28,6 +28,7 @@ #include <linux/sched/mm.h> #include <linux/sort.h> +#include <linux/string_helpers.h> #include <drm/drm_debugfs.h> @@ -47,6 +48,7 @@ #include "i915_debugfs.h" #include "i915_debugfs_params.h" +#include "i915_driver.h" #include "i915_irq.h" #include "i915_scheduler.h" #include "intel_mchbar_regs.h" @@ -455,9 +457,11 @@ static int i915_rps_boost_info(struct seq_file *m, void *data) struct drm_i915_private *dev_priv = node_to_i915(m->private); struct intel_rps *rps = &to_gt(dev_priv)->rps; - seq_printf(m, "RPS enabled? %s\n", yesno(intel_rps_is_enabled(rps))); - seq_printf(m, "RPS active? %s\n", yesno(intel_rps_is_active(rps))); - seq_printf(m, "GPU busy? %s\n", yesno(to_gt(dev_priv)->awake)); + seq_printf(m, "RPS enabled? %s\n", + str_yes_no(intel_rps_is_enabled(rps))); + seq_printf(m, "RPS active? %s\n", + str_yes_no(intel_rps_is_active(rps))); + seq_printf(m, "GPU busy? %s\n", str_yes_no(to_gt(dev_priv)->awake)); seq_printf(m, "Boosts outstanding? %d\n", atomic_read(&rps->num_waiters)); seq_printf(m, "Interactive? %d\n", READ_ONCE(rps->power.interactive)); @@ -488,11 +492,11 @@ static int i915_runtime_pm_status(struct seq_file *m, void *unused) seq_puts(m, "Runtime power management not supported\n"); seq_printf(m, "Runtime power status: %s\n", - enableddisabled(!dev_priv->power_domains.init_wakeref)); + str_enabled_disabled(!dev_priv->power_domains.init_wakeref)); - seq_printf(m, "GPU idle: %s\n", yesno(!to_gt(dev_priv)->awake)); + seq_printf(m, "GPU idle: %s\n", str_yes_no(!to_gt(dev_priv)->awake)); seq_printf(m, "IRQs disabled: %s\n", - yesno(!intel_irqs_enabled(dev_priv))); + str_yes_no(!intel_irqs_enabled(dev_priv))); #ifdef CONFIG_PM seq_printf(m, "Usage count: %d\n", atomic_read(&dev_priv->drm.dev->power.usage_count)); @@ -522,7 +526,7 @@ static int i915_engine_info(struct seq_file *m, void *unused) wakeref = intel_runtime_pm_get(&i915->runtime_pm); seq_printf(m, "GT awake? %s [%d], %llums\n", - yesno(to_gt(i915)->awake), + str_yes_no(to_gt(i915)->awake), atomic_read(&to_gt(i915)->wakeref.count), ktime_to_ms(intel_gt_get_awake_time(to_gt(i915)))); seq_printf(m, "CS timestamp frequency: %u Hz, %d ns\n", diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c index 62b3f332bbf5..09de45d3e274 100644 --- a/drivers/gpu/drm/i915/i915_driver.c +++ b/drivers/gpu/drm/i915/i915_driver.c @@ -36,6 +36,7 @@ #include <linux/pm_runtime.h> #include <linux/pnp.h> #include <linux/slab.h> +#include <linux/string_helpers.h> #include <linux/vga_switcheroo.h> #include <linux/vt.h> @@ -87,6 +88,7 @@ #include "i915_suspend.h" #include "i915_switcheroo.h" #include "i915_sysfs.h" +#include "i915_utils.h" #include "i915_vgpu.h" #include "intel_dram.h" #include "intel_gvt.h" @@ -752,7 +754,8 @@ static void i915_driver_unregister(struct drm_i915_private *dev_priv) void i915_print_iommu_status(struct drm_i915_private *i915, struct drm_printer *p) { - drm_printf(p, "iommu: %s\n", enableddisabled(intel_vtd_active(i915))); + drm_printf(p, "iommu: %s\n", + str_enabled_disabled(i915_vtd_active(i915))); } static void i915_welcome_messages(struct drm_i915_private *dev_priv) diff --git a/drivers/gpu/drm/i915/i915_driver.h b/drivers/gpu/drm/i915/i915_driver.h index 9d11de65daaf..44ec543d92cb 100644 --- a/drivers/gpu/drm/i915/i915_driver.h +++ b/drivers/gpu/drm/i915/i915_driver.h @@ -11,6 +11,7 @@ struct pci_dev; struct pci_device_id; struct drm_i915_private; +struct drm_printer; #define DRIVER_NAME "i915" #define DRIVER_DESC "Intel Graphics" @@ -26,4 +27,7 @@ void i915_driver_shutdown(struct drm_i915_private *i915); int i915_driver_resume_switcheroo(struct drm_i915_private *i915); int i915_driver_suspend_switcheroo(struct drm_i915_private *i915, pm_message_t state); +void +i915_print_iommu_status(struct drm_i915_private *i915, struct drm_printer *p); + #endif /* __I915_DRIVER_H__ */ diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index fa14da84362e..ce2cd6491d6d 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -32,11 +32,6 @@ #include <uapi/drm/i915_drm.h> -#include <asm/hypervisor.h> - -#include <linux/i2c.h> -#include <linux/i2c-algo-bit.h> -#include <linux/intel-iommu.h> #include <linux/pm_qos.h> #include <drm/drm_connector.h> @@ -99,6 +94,7 @@ struct intel_dpll_funcs; struct intel_encoder; struct intel_fbdev; struct intel_fdi_funcs; +struct intel_gmbus; struct intel_hotplug_funcs; struct intel_initial_plane_config; struct intel_limit; @@ -197,30 +193,10 @@ struct drm_i915_display_funcs { #define I915_COLOR_UNEVICTABLE (-1) /* a non-vma sharing the address space */ -/* - * HIGH_RR is the highest eDP panel refresh rate read from EDID - * LOW_RR is the lowest eDP panel refresh rate found from EDID - * parsing for same resolution. - */ -enum drrs_refresh_rate_type { - DRRS_HIGH_RR, - DRRS_LOW_RR, - DRRS_MAX_RR, /* RR count */ -}; - -enum drrs_support_type { - DRRS_NOT_SUPPORTED = 0, - STATIC_DRRS_SUPPORT = 1, - SEAMLESS_DRRS_SUPPORT = 2 -}; - -struct i915_drrs { - struct mutex mutex; - struct delayed_work work; - struct intel_dp *dp; - unsigned busy_frontbuffer_bits; - enum drrs_refresh_rate_type refresh_rate_type; - enum drrs_support_type type; +enum drrs_type { + DRRS_TYPE_NONE, + DRRS_TYPE_STATIC, + DRRS_TYPE_SEAMLESS, }; #define QUIRK_LVDS_SSC_DISABLE (1<<1) @@ -231,16 +207,6 @@ struct i915_drrs { #define QUIRK_INCREASE_DDI_DISABLED_TIME (1<<7) #define QUIRK_NO_PPS_BACKLIGHT_POWER_HOOK (1<<8) -struct intel_gmbus { - struct i2c_adapter adapter; -#define GMBUS_FORCE_BIT_RETRY (1U << 31) - u32 force_bit; - u32 reg0; - i915_reg_t gpio_reg; - struct i2c_algo_bit_data bit_algo; - struct drm_i915_private *dev_priv; -}; - struct i915_suspend_saved_registers { u32 saveDSPARB; u32 saveSWF0[16]; @@ -360,17 +326,18 @@ struct intel_vbt_data { bool override_afc_startup; u8 override_afc_startup_val; - enum drrs_support_type drrs_type; + enum drrs_type drrs_type; struct { int rate; int lanes; int preemphasis; int vswing; - bool low_vswing; - bool initialized; int bpp; struct edp_power_seq pps; + u8 drrs_msa_timing_delay; + bool low_vswing; + bool initialized; bool hobl; } edp; @@ -412,6 +379,7 @@ struct intel_vbt_data { int crt_ddc_pin; struct list_head display_devices; + struct list_head bdb_blocks; struct intel_bios_encoder_data *ports[I915_MAX_PORTS]; /* Non-NULL if port present. */ struct sdvo_device_mapping sdvo_mappings[2]; @@ -510,7 +478,7 @@ struct drm_i915_private { struct intel_dmc dmc; - struct intel_gmbus gmbus[GMBUS_NUM_PINS]; + struct intel_gmbus *gmbus[GMBUS_NUM_PINS]; /** gmbus_mutex protects against concurrent usage of the single hw gmbus * controller on different i2c buses. */ @@ -553,7 +521,6 @@ struct drm_i915_private { struct i915_hotplug hotplug; struct intel_fbc *fbc[I915_MAX_FBCS]; - struct i915_drrs drrs; struct intel_opregion opregion; struct intel_vbt_data vbt; @@ -666,12 +633,6 @@ struct drm_i915_private { struct list_head global_obj_list; - /* - * For reading active_pipes holding any crtc lock is - * sufficient, for writing must hold all of them. - */ - u8 active_pipes; - struct i915_frontbuffer_tracking fb_tracking; struct intel_atomic_helper { @@ -701,8 +662,6 @@ struct drm_i915_private { struct i915_gpu_error gpu_error; - struct drm_i915_gem_object *vlv_pctx; - /* list of fbdev register on this device */ struct intel_fbdev *fbdev; struct work_struct fbdev_suspend_work; @@ -723,7 +682,6 @@ struct drm_i915_private { u32 bxt_phy_grc; u32 suspend_count; - bool power_domains_suspended; struct i915_suspend_saved_registers regfile; struct vlv_s0ix_state *vlv_s0ix_state; @@ -825,8 +783,6 @@ struct drm_i915_private { struct file *mmap_singleton; } gem; - u8 framestart_delay; - /* Window2 specifies time required to program DSB (Window2) in number of scan lines */ u8 window2_delay; @@ -837,8 +793,16 @@ struct drm_i915_private { bool irq_enabled; - /* perform PHY state sanity checks? */ - bool chv_phy_assert[2]; + union { + /* perform PHY state sanity checks? */ + bool chv_phy_assert[2]; + + /* + * DG2: Mask of PHYs that were not calibrated by the firmware + * and should not be used. + */ + u8 snps_phy_failed_calibration; + }; bool ipc_enabled; @@ -1251,6 +1215,7 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915, #define CMDPARSER_USES_GGTT(dev_priv) (GRAPHICS_VER(dev_priv) == 7) #define HAS_LLC(dev_priv) (INTEL_INFO(dev_priv)->has_llc) +#define HAS_4TILE(dev_priv) (INTEL_INFO(dev_priv)->has_4tile) #define HAS_SNOOP(dev_priv) (INTEL_INFO(dev_priv)->has_snoop) #define HAS_EDRAM(dev_priv) ((dev_priv)->edram_size_mb) #define HAS_SECURE_BATCHES(dev_priv) (GRAPHICS_VER(dev_priv) < 6) @@ -1398,42 +1363,10 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915, #define HAS_GUC_DEPRIVILEGE(dev_priv) \ (INTEL_INFO(dev_priv)->has_guc_deprivilege) -static inline bool run_as_guest(void) -{ - return !hypervisor_is_type(X86_HYPER_NATIVE); -} - #define HAS_D12_PLANE_MINIMIZATION(dev_priv) (IS_ROCKETLAKE(dev_priv) || \ IS_ALDERLAKE_S(dev_priv)) -static inline bool intel_vtd_active(struct drm_i915_private *i915) -{ - if (device_iommu_mapped(i915->drm.dev)) - return true; - - /* Running as a guest, we assume the host is enforcing VT'd */ - return run_as_guest(); -} - -void -i915_print_iommu_status(struct drm_i915_private *i915, struct drm_printer *p); - -static inline bool intel_scanout_needs_vtd_wa(struct drm_i915_private *dev_priv) -{ - return DISPLAY_VER(dev_priv) >= 6 && intel_vtd_active(dev_priv); -} - -static inline bool -intel_ggtt_update_needs_vtd_wa(struct drm_i915_private *i915) -{ - return IS_BROXTON(i915) && intel_vtd_active(i915); -} - -static inline bool -intel_vm_no_concurrent_access_wa(struct drm_i915_private *i915) -{ - return IS_CHERRYVIEW(i915) || intel_ggtt_update_needs_vtd_wa(i915); -} +#define HAS_MBUS_JOINING(i915) (IS_ALDERLAKE_P(i915)) /* i915_gem.c */ void i915_gem_init_early(struct drm_i915_private *dev_priv); @@ -1508,15 +1441,6 @@ void i915_gem_driver_release(struct drm_i915_private *dev_priv); int i915_gem_open(struct drm_i915_private *i915, struct drm_file *file); -/* i915_gem_tiling.c */ -static inline bool i915_gem_object_needs_bit17_swizzle(struct drm_i915_gem_object *obj) -{ - struct drm_i915_private *i915 = to_i915(obj->base.dev); - - return to_gt(i915)->ggtt->bit_6_swizzle_x == I915_BIT_6_SWIZZLE_9_10_17 && - i915_gem_object_is_tiled(obj); -} - /* intel_device_info.c */ static inline struct intel_device_info * mkwrite_device_info(struct drm_i915_private *dev_priv) diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 1d042551619e..d0e7ee7b07df 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -28,9 +28,11 @@ */ #include <linux/ascii85.h> +#include <linux/highmem.h> #include <linux/nmi.h> #include <linux/pagevec.h> #include <linux/scatterlist.h> +#include <linux/string_helpers.h> #include <linux/utsname.h> #include <linux/zlib.h> @@ -52,6 +54,7 @@ #include "i915_gpu_error.h" #include "i915_memcpy.h" #include "i915_scatterlist.h" +#include "i915_utils.h" #define ALLOW_FAIL (__GFP_KSWAPD_RECLAIM | __GFP_RETRY_MAYFAIL | __GFP_NOWARN) #define ATOMIC_MAYFAIL (GFP_ATOMIC | __GFP_NOWARN) @@ -719,7 +722,7 @@ static void err_print_gt(struct drm_i915_error_state_buf *m, const struct intel_engine_coredump *ee; int i; - err_printf(m, "GT awake: %s\n", yesno(gt->awake)); + err_printf(m, "GT awake: %s\n", str_yes_no(gt->awake)); err_printf(m, "EIR: 0x%08x\n", gt->eir); err_printf(m, "IER: 0x%08x\n", gt->ier); for (i = 0; i < gt->ngtier; i++) @@ -823,18 +826,10 @@ static void __err_print_to_sgl(struct drm_i915_error_state_buf *m, err_printf(m, "IOMMU enabled?: %d\n", error->iommu); - if (HAS_DMC(m->i915)) { - struct intel_dmc *dmc = &m->i915->dmc; + intel_dmc_print_error_state(m, m->i915); - err_printf(m, "DMC loaded: %s\n", - yesno(intel_dmc_has_payload(m->i915) != 0)); - err_printf(m, "DMC fw version: %d.%d\n", - DMC_VERSION_MAJOR(dmc->version), - DMC_VERSION_MINOR(dmc->version)); - } - - err_printf(m, "RPM wakelock: %s\n", yesno(error->wakelock)); - err_printf(m, "PM suspended: %s\n", yesno(error->suspended)); + err_printf(m, "RPM wakelock: %s\n", str_yes_no(error->wakelock)); + err_printf(m, "PM suspended: %s\n", str_yes_no(error->suspended)); if (error->gt) err_print_gt(m, error->gt); @@ -1812,7 +1807,7 @@ static void capture_gen(struct i915_gpu_coredump *error) error->wakelock = atomic_read(&i915->runtime_pm.wakeref_count); error->suspended = i915->runtime_pm.suspended; - error->iommu = intel_vtd_active(i915); + error->iommu = i915_vtd_active(i915); error->reset_count = i915_reset_count(&i915->gpu_error); error->suspend_count = i915->suspend_count; diff --git a/drivers/gpu/drm/i915/i915_gpu_error.h b/drivers/gpu/drm/i915/i915_gpu_error.h index 903d838e2e63..88ce3a08f555 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.h +++ b/drivers/gpu/drm/i915/i915_gpu_error.h @@ -281,6 +281,12 @@ void i915_disable_error_state(struct drm_i915_private *i915, int err); #else +__printf(2, 3) +static inline void +i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...) +{ +} + static inline void i915_capture_error_state(struct intel_gt *gt, intel_engine_mask_t engine_mask) { diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index eea355c2fc28..5ad071e09301 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -22,6 +22,8 @@ * IN THE SOFTWARE. */ +#include <linux/string_helpers.h> + #include <drm/drm_print.h> #include "i915_params.h" @@ -94,7 +96,7 @@ i915_param_named_unsafe(enable_hangcheck, bool, 0400, i915_param_named_unsafe(enable_psr, int, 0400, "Enable PSR " - "(0=disabled, 1=enabled) " + "(0=disabled, 1=enable up to PSR1, 2=enable up to PSR2) " "Default: -1 (use per-chip default)"); i915_param_named(psr_safest_params, bool, 0400, @@ -206,7 +208,8 @@ static __always_inline void _print_param(struct drm_printer *p, const void *x) { if (!__builtin_strcmp(type, "bool")) - drm_printf(p, "i915.%s=%s\n", name, yesno(*(const bool *)x)); + drm_printf(p, "i915.%s=%s\n", name, + str_yes_no(*(const bool *)x)); else if (!__builtin_strcmp(type, "int")) drm_printf(p, "i915.%s=%d\n", name, *(const int *)x); else if (!__builtin_strcmp(type, "unsigned int")) diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c index c32c0c6661c8..9e077929ed67 100644 --- a/drivers/gpu/drm/i915/i915_pci.c +++ b/drivers/gpu/drm/i915/i915_pci.c @@ -1040,25 +1040,36 @@ static const struct intel_device_info xehpsdv_info = { .require_force_probe = 1, }; +#define DG2_FEATURES \ + XE_HP_FEATURES, \ + XE_HPM_FEATURES, \ + DGFX_FEATURES, \ + .graphics.rel = 55, \ + .media.rel = 55, \ + PLATFORM(INTEL_DG2), \ + .has_4tile = 1, \ + .has_64k_pages = 1, \ + .has_guc_deprivilege = 1, \ + .needs_compact_pt = 1, \ + .platform_engine_mask = \ + BIT(RCS0) | BIT(BCS0) | \ + BIT(VECS0) | BIT(VECS1) | \ + BIT(VCS0) | BIT(VCS2) + __maybe_unused static const struct intel_device_info dg2_info = { - XE_HP_FEATURES, - XE_HPM_FEATURES, + DG2_FEATURES, XE_LPD_FEATURES, - DGFX_FEATURES, - .graphics.rel = 55, - .media.rel = 55, - PLATFORM(INTEL_DG2), - .has_guc_deprivilege = 1, - .has_64k_pages = 1, - .needs_compact_pt = 1, - .platform_engine_mask = - BIT(RCS0) | BIT(BCS0) | - BIT(VECS0) | BIT(VECS1) | - BIT(VCS0) | BIT(VCS2), - .require_force_probe = 1, .display.cpu_transcoder_mask = BIT(TRANSCODER_A) | BIT(TRANSCODER_B) | BIT(TRANSCODER_C) | BIT(TRANSCODER_D), + .require_force_probe = 1, +}; + +__maybe_unused +static const struct intel_device_info ats_m_info = { + DG2_FEATURES, + .display = { 0 }, + .require_force_probe = 1, }; #undef PLATFORM diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c index cfc21042499d..3e3b09588fd3 100644 --- a/drivers/gpu/drm/i915/i915_pmu.c +++ b/drivers/gpu/drm/i915/i915_pmu.c @@ -148,10 +148,7 @@ static u64 __get_rc6(struct intel_gt *gt) struct drm_i915_private *i915 = gt->i915; u64 val; - val = intel_rc6_residency_ns(>->rc6, - IS_VALLEYVIEW(i915) ? - VLV_GT_RENDER_RC6 : - GEN6_GT_GFX_RC6); + val = intel_rc6_residency_ns(>->rc6, GEN6_GT_GFX_RC6); if (HAS_RC6p(i915)) val += intel_rc6_residency_ns(>->rc6, GEN6_GT_GFX_RC6p); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 3c87d77d2cf6..51f46fe45c72 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -644,22 +644,20 @@ #define _PORT_PLL_A 0x46074 #define _PORT_PLL_B 0x46078 #define _PORT_PLL_C 0x4607c -#define PORT_PLL_ENABLE (1 << 31) -#define PORT_PLL_LOCK (1 << 30) -#define PORT_PLL_REF_SEL (1 << 27) -#define PORT_PLL_POWER_ENABLE (1 << 26) -#define PORT_PLL_POWER_STATE (1 << 25) +#define PORT_PLL_ENABLE REG_BIT(31) +#define PORT_PLL_LOCK REG_BIT(30) +#define PORT_PLL_REF_SEL REG_BIT(27) +#define PORT_PLL_POWER_ENABLE REG_BIT(26) +#define PORT_PLL_POWER_STATE REG_BIT(25) #define BXT_PORT_PLL_ENABLE(port) _MMIO_PORT(port, _PORT_PLL_A, _PORT_PLL_B) #define _PORT_PLL_EBB_0_A 0x162034 #define _PORT_PLL_EBB_0_B 0x6C034 #define _PORT_PLL_EBB_0_C 0x6C340 -#define PORT_PLL_P1_SHIFT 13 -#define PORT_PLL_P1_MASK (0x07 << PORT_PLL_P1_SHIFT) -#define PORT_PLL_P1(x) ((x) << PORT_PLL_P1_SHIFT) -#define PORT_PLL_P2_SHIFT 8 -#define PORT_PLL_P2_MASK (0x1f << PORT_PLL_P2_SHIFT) -#define PORT_PLL_P2(x) ((x) << PORT_PLL_P2_SHIFT) +#define PORT_PLL_P1_MASK REG_GENMASK(15, 13) +#define PORT_PLL_P1(p1) REG_FIELD_PREP(PORT_PLL_P1_MASK, (p1)) +#define PORT_PLL_P2_MASK REG_GENMASK(12, 8) +#define PORT_PLL_P2(p2) REG_FIELD_PREP(PORT_PLL_P2_MASK, (p2)) #define BXT_PORT_PLL_EBB_0(phy, ch) _MMIO_BXT_PHY_CH(phy, ch, \ _PORT_PLL_EBB_0_B, \ _PORT_PLL_EBB_0_C) @@ -667,8 +665,8 @@ #define _PORT_PLL_EBB_4_A 0x162038 #define _PORT_PLL_EBB_4_B 0x6C038 #define _PORT_PLL_EBB_4_C 0x6C344 -#define PORT_PLL_10BIT_CLK_ENABLE (1 << 13) -#define PORT_PLL_RECALIBRATE (1 << 14) +#define PORT_PLL_RECALIBRATE REG_BIT(14) +#define PORT_PLL_10BIT_CLK_ENABLE REG_BIT(13) #define BXT_PORT_PLL_EBB_4(phy, ch) _MMIO_BXT_PHY_CH(phy, ch, \ _PORT_PLL_EBB_4_B, \ _PORT_PLL_EBB_4_C) @@ -677,31 +675,33 @@ #define _PORT_PLL_0_B 0x6C100 #define _PORT_PLL_0_C 0x6C380 /* PORT_PLL_0_A */ -#define PORT_PLL_M2_MASK 0xFF +#define PORT_PLL_M2_INT_MASK REG_GENMASK(7, 0) +#define PORT_PLL_M2_INT(m2_int) REG_FIELD_PREP(PORT_PLL_M2_INT_MASK, (m2_int)) /* PORT_PLL_1_A */ -#define PORT_PLL_N_SHIFT 8 -#define PORT_PLL_N_MASK (0x0F << PORT_PLL_N_SHIFT) -#define PORT_PLL_N(x) ((x) << PORT_PLL_N_SHIFT) +#define PORT_PLL_N_MASK REG_GENMASK(11, 8) +#define PORT_PLL_N(n) REG_FIELD_PREP(PORT_PLL_N_MASK, (n)) /* PORT_PLL_2_A */ -#define PORT_PLL_M2_FRAC_MASK 0x3FFFFF +#define PORT_PLL_M2_FRAC_MASK REG_GENMASK(21, 0) +#define PORT_PLL_M2_FRAC(m2_frac) REG_FIELD_PREP(PORT_PLL_M2_FRAC_MASK, (m2_frac)) /* PORT_PLL_3_A */ -#define PORT_PLL_M2_FRAC_ENABLE (1 << 16) +#define PORT_PLL_M2_FRAC_ENABLE REG_BIT(16) /* PORT_PLL_6_A */ -#define PORT_PLL_PROP_COEFF_MASK 0xF -#define PORT_PLL_INT_COEFF_MASK (0x1F << 8) -#define PORT_PLL_INT_COEFF(x) ((x) << 8) -#define PORT_PLL_GAIN_CTL_MASK (0x07 << 16) -#define PORT_PLL_GAIN_CTL(x) ((x) << 16) +#define PORT_PLL_GAIN_CTL_MASK REG_GENMASK(18, 16) +#define PORT_PLL_GAIN_CTL(x) REG_FIELD_PREP(PORT_PLL_GAIN_CTL_MASK, (x)) +#define PORT_PLL_INT_COEFF_MASK REG_GENMASK(12, 8) +#define PORT_PLL_INT_COEFF(x) REG_FIELD_PREP(PORT_PLL_INT_COEFF_MASK, (x)) +#define PORT_PLL_PROP_COEFF_MASK REG_GENMASK(3, 0) +#define PORT_PLL_PROP_COEFF(x) REG_FIELD_PREP(PORT_PLL_PROP_COEFF_MASK, (x)) /* PORT_PLL_8_A */ -#define PORT_PLL_TARGET_CNT_MASK 0x3FF +#define PORT_PLL_TARGET_CNT_MASK REG_GENMASK(9, 0) +#define PORT_PLL_TARGET_CNT(x) REG_FIELD_PREP(PORT_PLL_TARGET_CNT_MASK, (x)) /* PORT_PLL_9_A */ -#define PORT_PLL_LOCK_THRESHOLD_SHIFT 1 -#define PORT_PLL_LOCK_THRESHOLD_MASK (0x7 << PORT_PLL_LOCK_THRESHOLD_SHIFT) +#define PORT_PLL_LOCK_THRESHOLD_MASK REG_GENMASK(3, 1) +#define PORT_PLL_LOCK_THRESHOLD(x) REG_FIELD_PREP(PORT_PLL_LOCK_THRESHOLD_MASK, (x)) /* PORT_PLL_10_A */ -#define PORT_PLL_DCO_AMP_OVR_EN_H (1 << 27) -#define PORT_PLL_DCO_AMP_DEFAULT 15 -#define PORT_PLL_DCO_AMP_MASK 0x3c00 -#define PORT_PLL_DCO_AMP(x) ((x) << 10) +#define PORT_PLL_DCO_AMP_OVR_EN_H REG_BIT(27) +#define PORT_PLL_DCO_AMP_MASK REG_GENMASK(13, 10) +#define PORT_PLL_DCO_AMP(x) REG_FIELD_PREP(PORT_PLL_DCO_AMP_MASK, (x)) #define _PORT_PLL_BASE(phy, ch) _BXT_PHY_CH(phy, ch, \ _PORT_PLL_0_B, \ _PORT_PLL_0_C) @@ -1103,16 +1103,21 @@ #define MBUS_ABOX_BT_CREDIT_POOL1_MASK (0x1F << 0) #define MBUS_ABOX_BT_CREDIT_POOL1(x) ((x) << 0) -#define _PIPEA_MBUS_DBOX_CTL 0x7003C -#define _PIPEB_MBUS_DBOX_CTL 0x7103C -#define PIPE_MBUS_DBOX_CTL(pipe) _MMIO_PIPE(pipe, _PIPEA_MBUS_DBOX_CTL, \ - _PIPEB_MBUS_DBOX_CTL) -#define MBUS_DBOX_BW_CREDIT_MASK (3 << 14) -#define MBUS_DBOX_BW_CREDIT(x) ((x) << 14) -#define MBUS_DBOX_B_CREDIT_MASK (0x1F << 8) -#define MBUS_DBOX_B_CREDIT(x) ((x) << 8) -#define MBUS_DBOX_A_CREDIT_MASK (0xF << 0) -#define MBUS_DBOX_A_CREDIT(x) ((x) << 0) +#define _PIPEA_MBUS_DBOX_CTL 0x7003C +#define _PIPEB_MBUS_DBOX_CTL 0x7103C +#define PIPE_MBUS_DBOX_CTL(pipe) _MMIO_PIPE(pipe, _PIPEA_MBUS_DBOX_CTL, \ + _PIPEB_MBUS_DBOX_CTL) +#define MBUS_DBOX_B2B_TRANSACTIONS_MAX_MASK REG_GENMASK(24, 20) /* tgl+ */ +#define MBUS_DBOX_B2B_TRANSACTIONS_MAX(x) REG_FIELD_PREP(MBUS_DBOX_B2B_TRANSACTIONS_MAX_MASK, x) +#define MBUS_DBOX_B2B_TRANSACTIONS_DELAY_MASK REG_GENMASK(19, 17) /* tgl+ */ +#define MBUS_DBOX_B2B_TRANSACTIONS_DELAY(x) REG_FIELD_PREP(MBUS_DBOX_B2B_TRANSACTIONS_DELAY_MASK, x) +#define MBUS_DBOX_REGULATE_B2B_TRANSACTIONS_EN REG_BIT(16) /* tgl+ */ +#define MBUS_DBOX_BW_CREDIT_MASK REG_GENMASK(15, 14) +#define MBUS_DBOX_BW_CREDIT(x) REG_FIELD_PREP(MBUS_DBOX_BW_CREDIT_MASK, x) +#define MBUS_DBOX_B_CREDIT_MASK REG_GENMASK(12, 8) +#define MBUS_DBOX_B_CREDIT(x) REG_FIELD_PREP(MBUS_DBOX_B_CREDIT_MASK, x) +#define MBUS_DBOX_A_CREDIT_MASK REG_GENMASK(3, 0) +#define MBUS_DBOX_A_CREDIT(x) REG_FIELD_PREP(MBUS_DBOX_A_CREDIT_MASK, x) #define MBUS_UBOX_CTL _MMIO(0x4503C) #define MBUS_BBOX_CTL_S1 _MMIO(0x45040) @@ -3705,9 +3710,11 @@ #define PIPECONF_INTERLACE_IF_ID_ILK REG_FIELD_PREP(PIPECONF_INTERLACE_MASK_ILK, 3) #define PIPECONF_INTERLACE_IF_ID_DBL_ILK REG_FIELD_PREP(PIPECONF_INTERLACE_MASK_ILK, 4) /* ilk/snb only */ #define PIPECONF_INTERLACE_PF_ID_DBL_ILK REG_FIELD_PREP(PIPECONF_INTERLACE_MASK_ILK, 5) /* ilk/snb only */ -#define PIPECONF_EDP_RR_MODE_SWITCH REG_BIT(20) +#define PIPECONF_REFRESH_RATE_ALT_ILK REG_BIT(20) +#define PIPECONF_MSA_TIMING_DELAY_MASK REG_GENMASK(19, 18) /* ilk/snb/ivb */ +#define PIPECONF_MSA_TIMING_DELAY(x) REG_FIELD_PREP(PIPECONF_MSA_TIMING_DELAY_MASK, (x)) #define PIPECONF_CXSR_DOWNCLOCK REG_BIT(16) -#define PIPECONF_EDP_RR_MODE_SWITCH_VLV REG_BIT(14) +#define PIPECONF_REFRESH_RATE_ALT_VLV REG_BIT(14) #define PIPECONF_COLOR_RANGE_SELECT REG_BIT(13) #define PIPECONF_OUTPUT_COLORSPACE_MASK REG_GENMASK(12, 11) /* ilk-ivb */ #define PIPECONF_OUTPUT_COLORSPACE_RGB REG_FIELD_PREP(PIPECONF_OUTPUT_COLORSPACE_MASK, 0) /* ilk-ivb */ @@ -4849,6 +4856,7 @@ #define PLANE_CTL_TILED_X REG_FIELD_PREP(PLANE_CTL_TILED_MASK, 1) #define PLANE_CTL_TILED_Y REG_FIELD_PREP(PLANE_CTL_TILED_MASK, 4) #define PLANE_CTL_TILED_YF REG_FIELD_PREP(PLANE_CTL_TILED_MASK, 5) +#define PLANE_CTL_TILED_4 REG_FIELD_PREP(PLANE_CTL_TILED_MASK, 5) #define PLANE_CTL_ASYNC_FLIP REG_BIT(9) #define PLANE_CTL_FLIP_HORIZONTAL REG_BIT(8) #define PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE REG_BIT(4) /* TGL+ */ @@ -5490,27 +5498,6 @@ #define GAMMA_MODE_MODE_SPLIT (3 << 0) /* ivb-bdw */ #define GAMMA_MODE_MODE_12BIT_MULTI_SEGMENTED (3 << 0) /* icl + */ -/* DMC */ -#define DMC_PROGRAM(addr, i) _MMIO((addr) + (i) * 4) -#define DMC_SSP_BASE_ADDR_GEN9 0x00002FC0 -#define DMC_HTP_ADDR_SKL 0x00500034 -#define DMC_SSP_BASE _MMIO(0x8F074) -#define DMC_HTP_SKL _MMIO(0x8F004) -#define DMC_LAST_WRITE _MMIO(0x8F034) -#define DMC_LAST_WRITE_VALUE 0xc003b400 -/* MMIO address range for DMC program (0x80000 - 0x82FFF) */ -#define DMC_MMIO_START_RANGE 0x80000 -#define DMC_MMIO_END_RANGE 0x8FFFF -#define SKL_DMC_DC3_DC5_COUNT _MMIO(0x80030) -#define SKL_DMC_DC5_DC6_COUNT _MMIO(0x8002C) -#define BXT_DMC_DC3_DC5_COUNT _MMIO(0x80038) -#define TGL_DMC_DEBUG_DC5_COUNT _MMIO(0x101084) -#define TGL_DMC_DEBUG_DC6_COUNT _MMIO(0x101088) -#define DG1_DMC_DEBUG_DC5_COUNT _MMIO(0x134154) - -#define TGL_DMC_DEBUG3 _MMIO(0x101090) -#define DG1_DMC_DEBUG3 _MMIO(0x13415c) - /* Display Internal Timeout Register */ #define RM_TIMEOUT _MMIO(0x42060) #define MMIO_TIMEOUT_US(us) ((us) << 0) @@ -5925,6 +5912,7 @@ #define ICL_DELAY_PMRSP REG_BIT(22) #define DISABLE_FLR_SRC REG_BIT(15) #define MASK_WAKEMEM REG_BIT(13) +#define DDI_CLOCK_REG_ACCESS REG_BIT(7) #define GEN11_CHICKEN_DCPR_2 _MMIO(0x46434) #define DCPR_MASK_MAXLATENCY_MEMUP_CLR REG_BIT(27) @@ -6719,11 +6707,18 @@ #define ICL_PCODE_MEM_SS_READ_QGV_POINT_INFO(point) (((point) << 16) | (0x1 << 8)) #define ADL_PCODE_MEM_SS_READ_PSF_GV_INFO ((0) | (0x2 << 8)) #define ICL_PCODE_SAGV_DE_MEM_SS_CONFIG 0xe -#define ICL_PCODE_POINTS_RESTRICTED 0x0 -#define ICL_PCODE_POINTS_RESTRICTED_MASK 0xf -#define ADLS_PSF_PT_SHIFT 8 -#define ADLS_QGV_PT_MASK REG_GENMASK(7, 0) -#define ADLS_PSF_PT_MASK REG_GENMASK(10, 8) +#define ICL_PCODE_REP_QGV_MASK REG_GENMASK(1, 0) +#define ICL_PCODE_REP_QGV_SAFE REG_FIELD_PREP(ICL_PCODE_REP_QGV_MASK, 0) +#define ICL_PCODE_REP_QGV_POLL REG_FIELD_PREP(ICL_PCODE_REP_QGV_MASK, 1) +#define ICL_PCODE_REP_QGV_REJECTED REG_FIELD_PREP(ICL_PCODE_REP_QGV_MASK, 2) +#define ADLS_PCODE_REP_PSF_MASK REG_GENMASK(3, 2) +#define ADLS_PCODE_REP_PSF_SAFE REG_FIELD_PREP(ADLS_PCODE_REP_PSF_MASK, 0) +#define ADLS_PCODE_REP_PSF_POLL REG_FIELD_PREP(ADLS_PCODE_REP_PSF_MASK, 1) +#define ADLS_PCODE_REP_PSF_REJECTED REG_FIELD_PREP(ADLS_PCODE_REP_PSF_MASK, 2) +#define ICL_PCODE_REQ_QGV_PT_MASK REG_GENMASK(7, 0) +#define ICL_PCODE_REQ_QGV_PT(x) REG_FIELD_PREP(ICL_PCODE_REQ_QGV_PT_MASK, (x)) +#define ADLS_PCODE_REQ_PSF_PT_MASK REG_GENMASK(10, 8) +#define ADLS_PCODE_REQ_PSF_PT(x) REG_FIELD_PREP(ADLS_PCODE_REQ_PSF_PT_MASK, (x)) #define GEN6_PCODE_READ_D_COMP 0x10 #define GEN6_PCODE_WRITE_D_COMP 0x11 #define ICL_PCODE_EXIT_TCCOLD 0x12 diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 889f5b7dc78e..81def10eb58f 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -25,7 +25,6 @@ */ #include "display/intel_de.h" -#include "display/intel_fbc.h" #include "display/intel_gmbus.h" #include "display/intel_vga.h" @@ -119,9 +118,6 @@ void i915_restore_display(struct drm_i915_private *dev_priv) if (GRAPHICS_VER(dev_priv) <= 4) intel_de_write(dev_priv, DSPARB, dev_priv->regfile.saveDSPARB); - /* only restore FBC info on the platform that supports FBC*/ - intel_fbc_global_disable(dev_priv); - intel_vga_redisable(dev_priv); intel_gmbus_reset(dev_priv); diff --git a/drivers/gpu/drm/i915/i915_utils.c b/drivers/gpu/drm/i915/i915_utils.c index f9e780dee9de..29fd02bf5ea8 100644 --- a/drivers/gpu/drm/i915/i915_utils.c +++ b/drivers/gpu/drm/i915/i915_utils.c @@ -3,6 +3,8 @@ * Copyright © 2019 Intel Corporation */ +#include <linux/device.h> + #include <drm/drm_drv.h> #include "i915_drv.h" @@ -114,3 +116,12 @@ void set_timer_ms(struct timer_list *t, unsigned long timeout) /* Keep t->expires = 0 reserved to indicate a canceled timer. */ mod_timer(t, jiffies + timeout ?: 1); } + +bool i915_vtd_active(struct drm_i915_private *i915) +{ + if (device_iommu_mapped(i915->drm.dev)) + return true; + + /* Running as a guest, we assume the host is enforcing VT'd */ + return i915_run_as_guest(); +} diff --git a/drivers/gpu/drm/i915/i915_utils.h b/drivers/gpu/drm/i915/i915_utils.h index bfafd0afd117..ea7648e3aa0e 100644 --- a/drivers/gpu/drm/i915/i915_utils.h +++ b/drivers/gpu/drm/i915/i915_utils.h @@ -28,10 +28,15 @@ #include <linux/list.h> #include <linux/overflow.h> #include <linux/sched.h> +#include <linux/string_helpers.h> #include <linux/types.h> #include <linux/workqueue.h> #include <linux/sched/clock.h> +#ifdef CONFIG_X86 +#include <asm/hypervisor.h> +#endif + struct drm_i915_private; struct timer_list; @@ -399,26 +404,6 @@ wait_remaining_ms_from_jiffies(unsigned long timestamp_jiffies, int to_wait_ms) #define MBps(x) KBps(1000 * (x)) #define GBps(x) ((u64)1000 * MBps((x))) -static inline const char *yesno(bool v) -{ - return v ? "yes" : "no"; -} - -static inline const char *onoff(bool v) -{ - return v ? "on" : "off"; -} - -static inline const char *enabledisable(bool v) -{ - return v ? "enable" : "disable"; -} - -static inline const char *enableddisabled(bool v) -{ - return v ? "enabled" : "disabled"; -} - void add_taint_for_CI(struct drm_i915_private *i915, unsigned int taint); static inline void __add_taint_for_CI(unsigned int taint) { @@ -444,4 +429,16 @@ static inline bool timer_expired(const struct timer_list *t) return timer_active(t) && !timer_pending(t); } +static inline bool i915_run_as_guest(void) +{ +#if IS_ENABLED(CONFIG_X86) + return !hypervisor_is_type(X86_HYPER_NATIVE); +#else + /* Not supported yet */ + return false; +#endif +} + +bool i915_vtd_active(struct drm_i915_private *i915); + #endif /* !__I915_UTILS_H */ diff --git a/drivers/gpu/drm/i915/intel_device_info.c b/drivers/gpu/drm/i915/intel_device_info.c index 32c5f10e31db..41a5b98d1342 100644 --- a/drivers/gpu/drm/i915/intel_device_info.c +++ b/drivers/gpu/drm/i915/intel_device_info.c @@ -22,6 +22,8 @@ * */ +#include <linux/string_helpers.h> + #include <drm/drm_print.h> #include <drm/i915_pciids.h> @@ -29,6 +31,7 @@ #include "display/intel_de.h" #include "intel_device_info.h" #include "i915_drv.h" +#include "i915_utils.h" #define PLATFORM_NAME(x) [INTEL_##x] = #x static const char * const platform_names[] = { @@ -110,11 +113,11 @@ void intel_device_info_print_static(const struct intel_device_info *info, drm_printf(p, "ppgtt-type: %d\n", info->ppgtt_type); drm_printf(p, "dma_mask_size: %u\n", info->dma_mask_size); -#define PRINT_FLAG(name) drm_printf(p, "%s: %s\n", #name, yesno(info->name)) +#define PRINT_FLAG(name) drm_printf(p, "%s: %s\n", #name, str_yes_no(info->name)) DEV_INFO_FOR_EACH_FLAG(PRINT_FLAG); #undef PRINT_FLAG -#define PRINT_FLAG(name) drm_printf(p, "%s: %s\n", #name, yesno(info->display.name)) +#define PRINT_FLAG(name) drm_printf(p, "%s: %s\n", #name, str_yes_no(info->display.name)) DEV_INFO_DISPLAY_FOR_EACH_FLAG(PRINT_FLAG); #undef PRINT_FLAG } @@ -366,7 +369,7 @@ void intel_device_info_runtime_init(struct drm_i915_private *dev_priv) info->display.has_dsc = 0; } - if (GRAPHICS_VER(dev_priv) == 6 && intel_vtd_active(dev_priv)) { + if (GRAPHICS_VER(dev_priv) == 6 && i915_vtd_active(dev_priv)) { drm_info(&dev_priv->drm, "Disabling ppGTT for VT-d support\n"); info->ppgtt_type = INTEL_PPGTT_NONE; @@ -388,6 +391,6 @@ void intel_driver_caps_print(const struct intel_driver_caps *caps, struct drm_printer *p) { drm_printf(p, "Has logical contexts? %s\n", - yesno(caps->has_logical_contexts)); + str_yes_no(caps->has_logical_contexts)); drm_printf(p, "scheduler: %x\n", caps->scheduler); } diff --git a/drivers/gpu/drm/i915/intel_device_info.h b/drivers/gpu/drm/i915/intel_device_info.h index 291215d9da28..f9b955810593 100644 --- a/drivers/gpu/drm/i915/intel_device_info.h +++ b/drivers/gpu/drm/i915/intel_device_info.h @@ -137,6 +137,7 @@ enum intel_ppgtt_type { func(needs_compact_pt); \ func(gpu_reset_clobbers_display); \ func(has_reset_engine); \ + func(has_4tile); \ func(has_flat_ccs); \ func(has_global_mocs); \ func(has_gt_uc); \ diff --git a/drivers/gpu/drm/i915/intel_dram.c b/drivers/gpu/drm/i915/intel_dram.c index 174c95c3e10f..2b9e7833da96 100644 --- a/drivers/gpu/drm/i915/intel_dram.c +++ b/drivers/gpu/drm/i915/intel_dram.c @@ -3,6 +3,8 @@ * Copyright © 2020 Intel Corporation */ +#include <linux/string_helpers.h> + #include "i915_drv.h" #include "i915_reg.h" #include "intel_dram.h" @@ -136,7 +138,7 @@ skl_dram_get_dimm_info(struct drm_i915_private *i915, drm_dbg_kms(&i915->drm, "CH%u DIMM %c size: %u Gb, width: X%u, ranks: %u, 16Gb DIMMs: %s\n", channel, dimm_name, dimm->size, dimm->width, dimm->ranks, - yesno(skl_is_16gb_dimm(dimm))); + str_yes_no(skl_is_16gb_dimm(dimm))); } static int @@ -165,7 +167,7 @@ skl_dram_get_channel_info(struct drm_i915_private *i915, skl_is_16gb_dimm(&ch->dimm_s); drm_dbg_kms(&i915->drm, "CH%u ranks: %u, 16Gb DIMMs: %s\n", - channel, ch->ranks, yesno(ch->is_16gb_dimm)); + channel, ch->ranks, str_yes_no(ch->is_16gb_dimm)); return 0; } @@ -214,7 +216,7 @@ skl_dram_get_channels_info(struct drm_i915_private *i915) dram_info->symmetric_memory = intel_is_dram_symmetric(&ch0, &ch1); drm_dbg_kms(&i915->drm, "Memory configuration is symmetric? %s\n", - yesno(dram_info->symmetric_memory)); + str_yes_no(dram_info->symmetric_memory)); return 0; } @@ -492,7 +494,7 @@ void intel_dram_detect(struct drm_i915_private *i915) drm_dbg_kms(&i915->drm, "DRAM channels: %u\n", dram_info->num_channels); drm_dbg_kms(&i915->drm, "Watermark level 0 adjustment needed: %s\n", - yesno(dram_info->wm_lv_0_adjust_needed)); + str_yes_no(dram_info->wm_lv_0_adjust_needed)); } static u32 gen9_edram_size_mb(struct drm_i915_private *i915, u32 cap) diff --git a/drivers/gpu/drm/i915/intel_memory_region.c b/drivers/gpu/drm/i915/intel_memory_region.c index 1c841f68169a..ded78b83e0b5 100644 --- a/drivers/gpu/drm/i915/intel_memory_region.c +++ b/drivers/gpu/drm/i915/intel_memory_region.c @@ -5,6 +5,8 @@ #include <linux/prandom.h> +#include <uapi/drm/i915_drm.h> + #include "intel_memory_region.h" #include "i915_drv.h" #include "i915_ttm_buddy_manager.h" diff --git a/drivers/gpu/drm/i915/intel_memory_region.h b/drivers/gpu/drm/i915/intel_memory_region.h index 21dcbd620758..bbc35ec5c090 100644 --- a/drivers/gpu/drm/i915/intel_memory_region.h +++ b/drivers/gpu/drm/i915/intel_memory_region.h @@ -10,7 +10,7 @@ #include <linux/mutex.h> #include <linux/io-mapping.h> #include <drm/drm_mm.h> -#include <drm/i915_drm.h> +#include <uapi/drm/i915_drm.h> struct drm_i915_private; struct drm_i915_gem_object; diff --git a/drivers/gpu/drm/i915/intel_pch.c b/drivers/gpu/drm/i915/intel_pch.c index 4cce044efde2..e2b2bbdc0714 100644 --- a/drivers/gpu/drm/i915/intel_pch.c +++ b/drivers/gpu/drm/i915/intel_pch.c @@ -4,6 +4,7 @@ */ #include "i915_drv.h" +#include "i915_utils.h" #include "intel_pch.h" /* Map PCH device id to PCH type, or PCH_NONE if unknown. */ @@ -256,7 +257,7 @@ void intel_detect_pch(struct drm_i915_private *dev_priv) dev_priv->pch_type = PCH_NOP; dev_priv->pch_id = 0; } else if (!pch) { - if (run_as_guest() && HAS_DISPLAY(dev_priv)) { + if (i915_run_as_guest() && HAS_DISPLAY(dev_priv)) { intel_virt_detect_pch(dev_priv, &id, &pch_type); dev_priv->pch_type = pch_type; dev_priv->pch_id = id; diff --git a/drivers/gpu/drm/i915/intel_pcode.c b/drivers/gpu/drm/i915/intel_pcode.c index 391a37492ce5..ac727546868e 100644 --- a/drivers/gpu/drm/i915/intel_pcode.c +++ b/drivers/gpu/drm/i915/intel_pcode.c @@ -136,7 +136,7 @@ static bool skl_pcode_try_request(struct drm_i915_private *i915, u32 mbox, { *status = __snb_pcode_rw(i915, mbox, &request, NULL, 500, 0, true); - return *status || ((request & reply_mask) == reply); + return (*status == 0) && ((request & reply_mask) == reply); } /** @@ -202,7 +202,7 @@ int skl_pcode_request(struct drm_i915_private *i915, u32 mbox, u32 request, out: mutex_unlock(&i915->sb_lock); - return ret ? ret : status; + return status ? status : ret; #undef COND } diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 9333f732cda8..594ab59e4991 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -26,6 +26,7 @@ */ #include <linux/module.h> +#include <linux/string_helpers.h> #include <linux/pm_runtime.h> #include <drm/drm_atomic_helper.h> @@ -56,6 +57,8 @@ #include "vlv_sideband.h" #include "../../../platform/x86/intel_ips.h" +static void skl_sagv_disable(struct drm_i915_private *dev_priv); + struct drm_i915_clock_gating_funcs { void (*init_clock_gating)(struct drm_i915_private *i915); }; @@ -418,8 +421,8 @@ static bool _intel_set_memory_cxsr(struct drm_i915_private *dev_priv, bool enabl trace_intel_memory_cxsr(dev_priv, was_enabled, enable); drm_dbg_kms(&dev_priv->drm, "memory self-refresh is %s (was %s)\n", - enableddisabled(enable), - enableddisabled(was_enabled)); + str_enabled_disabled(enable), + str_enabled_disabled(was_enabled)); return was_enabled; } @@ -3669,8 +3672,8 @@ intel_has_sagv(struct drm_i915_private *dev_priv) dev_priv->sagv_status != I915_SAGV_NOT_CONTROLLED; } -static void -skl_setup_sagv_block_time(struct drm_i915_private *dev_priv) +static u32 +intel_sagv_block_time(struct drm_i915_private *dev_priv) { if (DISPLAY_VER(dev_priv) >= 12) { u32 val = 0; @@ -3679,26 +3682,48 @@ skl_setup_sagv_block_time(struct drm_i915_private *dev_priv) ret = snb_pcode_read(dev_priv, GEN12_PCODE_READ_SAGV_BLOCK_TIME_US, &val, NULL); - if (!ret) { - dev_priv->sagv_block_time_us = val; - return; + if (ret) { + drm_dbg_kms(&dev_priv->drm, "Couldn't read SAGV block time!\n"); + return 0; } - drm_dbg(&dev_priv->drm, "Couldn't read SAGV block time!\n"); + return val; } else if (DISPLAY_VER(dev_priv) == 11) { - dev_priv->sagv_block_time_us = 10; - return; - } else if (DISPLAY_VER(dev_priv) == 10) { - dev_priv->sagv_block_time_us = 20; - return; - } else if (DISPLAY_VER(dev_priv) == 9) { - dev_priv->sagv_block_time_us = 30; - return; + return 10; + } else if (DISPLAY_VER(dev_priv) == 9 && !IS_LP(dev_priv)) { + return 30; } else { - MISSING_CASE(DISPLAY_VER(dev_priv)); + return 0; } +} + +static void intel_sagv_init(struct drm_i915_private *i915) +{ + if (!intel_has_sagv(i915)) + i915->sagv_status = I915_SAGV_NOT_CONTROLLED; - dev_priv->sagv_block_time_us = 0; + /* + * Probe to see if we have working SAGV control. + * For icl+ this was already determined by intel_bw_init_hw(). + */ + if (DISPLAY_VER(i915) < 11) + skl_sagv_disable(i915); + + drm_WARN_ON(&i915->drm, i915->sagv_status == I915_SAGV_UNKNOWN); + + i915->sagv_block_time_us = intel_sagv_block_time(i915); + + drm_dbg_kms(&i915->drm, "SAGV supported: %s, original SAGV block time: %u us\n", + str_yes_no(intel_has_sagv(i915)), i915->sagv_block_time_us); + + /* avoid overflow when adding with wm0 latency/etc. */ + if (drm_WARN(&i915->drm, i915->sagv_block_time_us > U16_MAX, + "Excessive SAGV block time %u, ignoring\n", + i915->sagv_block_time_us)) + i915->sagv_block_time_us = 0; + + if (!intel_has_sagv(i915)) + i915->sagv_block_time_us = 0; } /* @@ -3712,16 +3737,15 @@ skl_setup_sagv_block_time(struct drm_i915_private *dev_priv) * - All planes can enable watermarks for latencies >= SAGV engine block time * - We're not using an interlaced display configuration */ -static int -intel_enable_sagv(struct drm_i915_private *dev_priv) +static void skl_sagv_enable(struct drm_i915_private *dev_priv) { int ret; if (!intel_has_sagv(dev_priv)) - return 0; + return; if (dev_priv->sagv_status == I915_SAGV_ENABLED) - return 0; + return; drm_dbg_kms(&dev_priv->drm, "Enabling SAGV\n"); ret = snb_pcode_write(dev_priv, GEN9_PCODE_SAGV_CONTROL, @@ -3736,26 +3760,24 @@ intel_enable_sagv(struct drm_i915_private *dev_priv) if (IS_SKYLAKE(dev_priv) && ret == -ENXIO) { drm_dbg(&dev_priv->drm, "No SAGV found on system, ignoring\n"); dev_priv->sagv_status = I915_SAGV_NOT_CONTROLLED; - return 0; + return; } else if (ret < 0) { drm_err(&dev_priv->drm, "Failed to enable SAGV\n"); - return ret; + return; } dev_priv->sagv_status = I915_SAGV_ENABLED; - return 0; } -static int -intel_disable_sagv(struct drm_i915_private *dev_priv) +static void skl_sagv_disable(struct drm_i915_private *dev_priv) { int ret; if (!intel_has_sagv(dev_priv)) - return 0; + return; if (dev_priv->sagv_status == I915_SAGV_DISABLED) - return 0; + return; drm_dbg_kms(&dev_priv->drm, "Disabling SAGV\n"); /* bspec says to keep retrying for at least 1 ms */ @@ -3770,14 +3792,13 @@ intel_disable_sagv(struct drm_i915_private *dev_priv) if (IS_SKYLAKE(dev_priv) && ret == -ENXIO) { drm_dbg(&dev_priv->drm, "No SAGV found on system, ignoring\n"); dev_priv->sagv_status = I915_SAGV_NOT_CONTROLLED; - return 0; + return; } else if (ret < 0) { drm_err(&dev_priv->drm, "Failed to disable SAGV (%d)\n", ret); - return ret; + return; } dev_priv->sagv_status = I915_SAGV_DISABLED; - return 0; } static void skl_sagv_pre_plane_update(struct intel_atomic_state *state) @@ -3790,7 +3811,7 @@ static void skl_sagv_pre_plane_update(struct intel_atomic_state *state) return; if (!intel_can_enable_sagv(i915, new_bw_state)) - intel_disable_sagv(i915); + skl_sagv_disable(i915); } static void skl_sagv_post_plane_update(struct intel_atomic_state *state) @@ -3803,7 +3824,7 @@ static void skl_sagv_post_plane_update(struct intel_atomic_state *state) return; if (intel_can_enable_sagv(i915, new_bw_state)) - intel_enable_sagv(i915); + skl_sagv_enable(i915); } static void icl_sagv_pre_plane_update(struct intel_atomic_state *state) @@ -4325,46 +4346,31 @@ static void skl_ddb_get_hw_plane_state(struct drm_i915_private *dev_priv, const enum pipe pipe, const enum plane_id plane_id, - struct skl_ddb_entry *ddb_y, - struct skl_ddb_entry *ddb_uv) + struct skl_ddb_entry *ddb, + struct skl_ddb_entry *ddb_y) { - u32 val, val2; - u32 fourcc = 0; + u32 val; /* Cursor doesn't support NV12/planar, so no extra calculation needed */ if (plane_id == PLANE_CURSOR) { val = intel_uncore_read(&dev_priv->uncore, CUR_BUF_CFG(pipe)); - skl_ddb_entry_init_from_hw(ddb_y, val); + skl_ddb_entry_init_from_hw(ddb, val); return; } - val = intel_uncore_read(&dev_priv->uncore, PLANE_CTL(pipe, plane_id)); - - /* No DDB allocated for disabled planes */ - if (val & PLANE_CTL_ENABLE) - fourcc = skl_format_to_fourcc(val & PLANE_CTL_FORMAT_MASK_SKL, - val & PLANE_CTL_ORDER_RGBX, - val & PLANE_CTL_ALPHA_MASK); - - if (DISPLAY_VER(dev_priv) >= 11) { - val = intel_uncore_read(&dev_priv->uncore, PLANE_BUF_CFG(pipe, plane_id)); - skl_ddb_entry_init_from_hw(ddb_y, val); - } else { - val = intel_uncore_read(&dev_priv->uncore, PLANE_BUF_CFG(pipe, plane_id)); - val2 = intel_uncore_read(&dev_priv->uncore, PLANE_NV12_BUF_CFG(pipe, plane_id)); + val = intel_uncore_read(&dev_priv->uncore, PLANE_BUF_CFG(pipe, plane_id)); + skl_ddb_entry_init_from_hw(ddb, val); - if (fourcc && - drm_format_info_is_yuv_semiplanar(drm_format_info(fourcc))) - swap(val, val2); + if (DISPLAY_VER(dev_priv) >= 11) + return; - skl_ddb_entry_init_from_hw(ddb_y, val); - skl_ddb_entry_init_from_hw(ddb_uv, val2); - } + val = intel_uncore_read(&dev_priv->uncore, PLANE_NV12_BUF_CFG(pipe, plane_id)); + skl_ddb_entry_init_from_hw(ddb_y, val); } void skl_pipe_ddb_get_hw_state(struct intel_crtc *crtc, - struct skl_ddb_entry *ddb_y, - struct skl_ddb_entry *ddb_uv) + struct skl_ddb_entry *ddb, + struct skl_ddb_entry *ddb_y) { struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); enum intel_display_power_domain power_domain; @@ -4380,8 +4386,8 @@ void skl_pipe_ddb_get_hw_state(struct intel_crtc *crtc, for_each_plane_id_on_crtc(crtc, plane_id) skl_ddb_get_hw_plane_state(dev_priv, pipe, plane_id, - &ddb_y[plane_id], - &ddb_uv[plane_id]); + &ddb[plane_id], + &ddb_y[plane_id]); intel_display_power_put(dev_priv, power_domain, wakeref); } @@ -4913,17 +4919,6 @@ static u8 skl_compute_dbuf_slices(struct intel_crtc *crtc, u8 active_pipes, bool } static bool -use_min_ddb(const struct intel_crtc_state *crtc_state, - struct intel_plane *plane) -{ - struct drm_i915_private *i915 = to_i915(plane->base.dev); - - return DISPLAY_VER(i915) >= 13 && - crtc_state->uapi.async_flip && - plane->async_flip; -} - -static bool use_minimal_wm0_only(const struct intel_crtc_state *crtc_state, struct intel_plane *plane) { @@ -4935,134 +4930,24 @@ use_minimal_wm0_only(const struct intel_crtc_state *crtc_state, } static u64 -skl_plane_relative_data_rate(const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state, - int color_plane) +skl_total_relative_data_rate(const struct intel_crtc_state *crtc_state) { - struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); - const struct drm_framebuffer *fb = plane_state->hw.fb; - int width, height; - - if (!plane_state->uapi.visible) - return 0; - - if (plane->id == PLANE_CURSOR) - return 0; - - /* - * We calculate extra ddb based on ratio plane rate/total data rate - * in case, in some cases we should not allocate extra ddb for the plane, - * so do not count its data rate, if this is the case. - */ - if (use_min_ddb(crtc_state, plane)) - return 0; - - if (color_plane == 1 && - !intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier)) - return 0; - - /* - * Src coordinates are already rotated by 270 degrees for - * the 90/270 degree plane rotation cases (to match the - * GTT mapping), hence no need to account for rotation here. - */ - width = drm_rect_width(&plane_state->uapi.src) >> 16; - height = drm_rect_height(&plane_state->uapi.src) >> 16; - - /* UV plane does 1/2 pixel sub-sampling */ - if (color_plane == 1) { - width /= 2; - height /= 2; - } - - return width * height * fb->format->cpp[color_plane]; -} - -static u64 -skl_get_total_relative_data_rate(struct intel_atomic_state *state, - struct intel_crtc *crtc) -{ - struct intel_crtc_state *crtc_state = - intel_atomic_get_new_crtc_state(state, crtc); - const struct intel_plane_state *plane_state; - struct intel_plane *plane; - u64 total_data_rate = 0; + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); enum plane_id plane_id; - int i; - - /* Calculate and cache data rate for each plane */ - for_each_new_intel_plane_in_state(state, plane, plane_state, i) { - if (plane->pipe != crtc->pipe) - continue; - - plane_id = plane->id; - - /* packed/y */ - crtc_state->plane_data_rate[plane_id] = - skl_plane_relative_data_rate(crtc_state, plane_state, 0); - - /* uv-plane */ - crtc_state->uv_plane_data_rate[plane_id] = - skl_plane_relative_data_rate(crtc_state, plane_state, 1); - } + u64 data_rate = 0; for_each_plane_id_on_crtc(crtc, plane_id) { - total_data_rate += crtc_state->plane_data_rate[plane_id]; - total_data_rate += crtc_state->uv_plane_data_rate[plane_id]; - } - - return total_data_rate; -} - -static u64 -icl_get_total_relative_data_rate(struct intel_atomic_state *state, - struct intel_crtc *crtc) -{ - struct intel_crtc_state *crtc_state = - intel_atomic_get_new_crtc_state(state, crtc); - const struct intel_plane_state *plane_state; - struct intel_plane *plane; - u64 total_data_rate = 0; - enum plane_id plane_id; - int i; - - /* Calculate and cache data rate for each plane */ - for_each_new_intel_plane_in_state(state, plane, plane_state, i) { - if (plane->pipe != crtc->pipe) + if (plane_id == PLANE_CURSOR) continue; - plane_id = plane->id; - - if (!plane_state->planar_linked_plane) { - crtc_state->plane_data_rate[plane_id] = - skl_plane_relative_data_rate(crtc_state, plane_state, 0); - } else { - enum plane_id y_plane_id; - - /* - * The slave plane might not iterate in - * intel_atomic_crtc_state_for_each_plane_state(), - * and needs the master plane state which may be - * NULL if we try get_new_plane_state(), so we - * always calculate from the master. - */ - if (plane_state->planar_slave) - continue; - - /* Y plane rate is calculated on the slave */ - y_plane_id = plane_state->planar_linked_plane->id; - crtc_state->plane_data_rate[y_plane_id] = - skl_plane_relative_data_rate(crtc_state, plane_state, 0); + data_rate += crtc_state->rel_data_rate[plane_id]; - crtc_state->plane_data_rate[plane_id] = - skl_plane_relative_data_rate(crtc_state, plane_state, 1); - } + if (DISPLAY_VER(i915) < 11) + data_rate += crtc_state->rel_data_rate_y[plane_id]; } - for_each_plane_id_on_crtc(crtc, plane_id) - total_data_rate += crtc_state->plane_data_rate[plane_id]; - - return total_data_rate; + return data_rate; } const struct skl_wm_level * @@ -5103,18 +4988,18 @@ skl_plane_trans_wm(const struct skl_pipe_wm *pipe_wm, * So this is actually safe to do. */ static void -skl_check_wm_level(struct skl_wm_level *wm, u64 total) +skl_check_wm_level(struct skl_wm_level *wm, const struct skl_ddb_entry *ddb) { - if (wm->min_ddb_alloc > total) + if (wm->min_ddb_alloc > skl_ddb_entry_size(ddb)) memset(wm, 0, sizeof(*wm)); } static void skl_check_nv12_wm_level(struct skl_wm_level *wm, struct skl_wm_level *uv_wm, - u64 total, u64 uv_total) + const struct skl_ddb_entry *ddb_y, const struct skl_ddb_entry *ddb) { - if (wm->min_ddb_alloc > total || - uv_wm->min_ddb_alloc > uv_total) { + if (wm->min_ddb_alloc > skl_ddb_entry_size(ddb_y) || + uv_wm->min_ddb_alloc > skl_ddb_entry_size(ddb)) { memset(wm, 0, sizeof(*wm)); memset(uv_wm, 0, sizeof(*uv_wm)); } @@ -5134,17 +5019,16 @@ static bool icl_need_wm1_wa(struct drm_i915_private *i915, struct skl_plane_ddb_iter { u64 data_rate; - u16 total[I915_MAX_PLANES]; - u16 uv_total[I915_MAX_PLANES]; u16 start, size; }; -static u16 +static void skl_allocate_plane_ddb(struct skl_plane_ddb_iter *iter, + struct skl_ddb_entry *ddb, const struct skl_wm_level *wm, u64 data_rate) { - u16 extra = 0; + u16 size, extra = 0; if (data_rate) { extra = min_t(u16, iter->size, @@ -5154,7 +5038,15 @@ skl_allocate_plane_ddb(struct skl_plane_ddb_iter *iter, iter->data_rate -= data_rate; } - return wm->min_ddb_alloc + extra; + /* + * Keep ddb entry of all disabled planes explicitly zeroed + * to avoid skl_ddb_add_affected_planes() adding them to + * the state when other planes change their allocations. + */ + size = wm->min_ddb_alloc + extra; + if (size) + iter->start = skl_ddb_entry_init(ddb, iter->start, + iter->start + size); } static int @@ -5168,32 +5060,31 @@ skl_crtc_allocate_plane_ddb(struct intel_atomic_state *state, intel_atomic_get_new_dbuf_state(state); const struct skl_ddb_entry *alloc = &dbuf_state->ddb[crtc->pipe]; int num_active = hweight8(dbuf_state->active_pipes); - struct skl_plane_ddb_iter iter = {}; + struct skl_plane_ddb_iter iter; enum plane_id plane_id; + u16 cursor_size; u32 blocks; int level; /* Clear the partitioning for disabled planes. */ + memset(crtc_state->wm.skl.plane_ddb, 0, sizeof(crtc_state->wm.skl.plane_ddb)); memset(crtc_state->wm.skl.plane_ddb_y, 0, sizeof(crtc_state->wm.skl.plane_ddb_y)); - memset(crtc_state->wm.skl.plane_ddb_uv, 0, sizeof(crtc_state->wm.skl.plane_ddb_uv)); if (!crtc_state->hw.active) return 0; - if (DISPLAY_VER(dev_priv) >= 11) - iter.data_rate = icl_get_total_relative_data_rate(state, crtc); - else - iter.data_rate = skl_get_total_relative_data_rate(state, crtc); - + iter.start = alloc->start; iter.size = skl_ddb_entry_size(alloc); if (iter.size == 0) return 0; /* Allocate fixed number of blocks for cursor. */ - iter.total[PLANE_CURSOR] = skl_cursor_allocation(crtc_state, num_active); - iter.size -= iter.total[PLANE_CURSOR]; - skl_ddb_entry_init(&crtc_state->wm.skl.plane_ddb_y[PLANE_CURSOR], - alloc->end - iter.total[PLANE_CURSOR], alloc->end); + cursor_size = skl_cursor_allocation(crtc_state, num_active); + iter.size -= cursor_size; + skl_ddb_entry_init(&crtc_state->wm.skl.plane_ddb[PLANE_CURSOR], + alloc->end - cursor_size, alloc->end); + + iter.data_rate = skl_total_relative_data_rate(crtc_state); /* * Find the highest watermark level for which we can satisfy the block @@ -5206,7 +5097,10 @@ skl_crtc_allocate_plane_ddb(struct intel_atomic_state *state, &crtc_state->wm.skl.optimal.planes[plane_id]; if (plane_id == PLANE_CURSOR) { - if (wm->wm[level].min_ddb_alloc > iter.total[PLANE_CURSOR]) { + const struct skl_ddb_entry *ddb = + &crtc_state->wm.skl.plane_ddb[plane_id]; + + if (wm->wm[level].min_ddb_alloc > skl_ddb_entry_size(ddb)) { drm_WARN_ON(&dev_priv->drm, wm->wm[level].min_ddb_alloc != U16_MAX); blocks = U32_MAX; @@ -5243,47 +5137,29 @@ skl_crtc_allocate_plane_ddb(struct intel_atomic_state *state, * proportional to its relative data rate. */ for_each_plane_id_on_crtc(crtc, plane_id) { + struct skl_ddb_entry *ddb = + &crtc_state->wm.skl.plane_ddb[plane_id]; + struct skl_ddb_entry *ddb_y = + &crtc_state->wm.skl.plane_ddb_y[plane_id]; const struct skl_plane_wm *wm = &crtc_state->wm.skl.optimal.planes[plane_id]; if (plane_id == PLANE_CURSOR) continue; - iter.total[plane_id] = - skl_allocate_plane_ddb(&iter, &wm->wm[level], - crtc_state->plane_data_rate[plane_id]); - - iter.uv_total[plane_id] = - skl_allocate_plane_ddb(&iter, &wm->uv_wm[level], - crtc_state->uv_plane_data_rate[plane_id]); + if (DISPLAY_VER(dev_priv) < 11 && + crtc_state->nv12_planes & BIT(plane_id)) { + skl_allocate_plane_ddb(&iter, ddb_y, &wm->wm[level], + crtc_state->rel_data_rate_y[plane_id]); + skl_allocate_plane_ddb(&iter, ddb, &wm->uv_wm[level], + crtc_state->rel_data_rate[plane_id]); + } else { + skl_allocate_plane_ddb(&iter, ddb, &wm->wm[level], + crtc_state->rel_data_rate[plane_id]); + } } drm_WARN_ON(&dev_priv->drm, iter.size != 0 || iter.data_rate != 0); - /* Set the actual DDB start/end points for each plane */ - iter.start = alloc->start; - for_each_plane_id_on_crtc(crtc, plane_id) { - struct skl_ddb_entry *plane_alloc = - &crtc_state->wm.skl.plane_ddb_y[plane_id]; - struct skl_ddb_entry *uv_plane_alloc = - &crtc_state->wm.skl.plane_ddb_uv[plane_id]; - - if (plane_id == PLANE_CURSOR) - continue; - - /* Gen11+ uses a separate plane for UV watermarks */ - drm_WARN_ON(&dev_priv->drm, - DISPLAY_VER(dev_priv) >= 11 && iter.uv_total[plane_id]); - - /* Leave disabled planes at (0,0) */ - if (iter.total[plane_id]) - iter.start = skl_ddb_entry_init(plane_alloc, iter.start, - iter.start + iter.total[plane_id]); - - if (iter.uv_total[plane_id]) - iter.start = skl_ddb_entry_init(uv_plane_alloc, iter.start, - iter.start + iter.uv_total[plane_id]); - } - /* * When we calculated watermark values we didn't know how high * of a level we'd actually be able to hit, so we just marked @@ -5292,12 +5168,20 @@ skl_crtc_allocate_plane_ddb(struct intel_atomic_state *state, */ for (level++; level <= ilk_wm_max_level(dev_priv); level++) { for_each_plane_id_on_crtc(crtc, plane_id) { + const struct skl_ddb_entry *ddb = + &crtc_state->wm.skl.plane_ddb[plane_id]; + const struct skl_ddb_entry *ddb_y = + &crtc_state->wm.skl.plane_ddb_y[plane_id]; struct skl_plane_wm *wm = &crtc_state->wm.skl.optimal.planes[plane_id]; - skl_check_nv12_wm_level(&wm->wm[level], &wm->uv_wm[level], - iter.total[plane_id], - iter.uv_total[plane_id]); + if (DISPLAY_VER(dev_priv) < 11 && + crtc_state->nv12_planes & BIT(plane_id)) + skl_check_nv12_wm_level(&wm->wm[level], + &wm->uv_wm[level], + ddb_y, ddb); + else + skl_check_wm_level(&wm->wm[level], ddb); if (icl_need_wm1_wa(dev_priv, plane_id) && level == 1 && wm->wm[0].enable) { @@ -5313,12 +5197,24 @@ skl_crtc_allocate_plane_ddb(struct intel_atomic_state *state, * if it turns out we don't have enough DDB blocks for them. */ for_each_plane_id_on_crtc(crtc, plane_id) { + const struct skl_ddb_entry *ddb = + &crtc_state->wm.skl.plane_ddb[plane_id]; + const struct skl_ddb_entry *ddb_y = + &crtc_state->wm.skl.plane_ddb_y[plane_id]; struct skl_plane_wm *wm = &crtc_state->wm.skl.optimal.planes[plane_id]; - skl_check_wm_level(&wm->trans_wm, iter.total[plane_id]); - skl_check_wm_level(&wm->sagv.wm0, iter.total[plane_id]); - skl_check_wm_level(&wm->sagv.trans_wm, iter.total[plane_id]); + if (DISPLAY_VER(dev_priv) < 11 && + crtc_state->nv12_planes & BIT(plane_id)) { + skl_check_wm_level(&wm->trans_wm, ddb_y); + } else { + WARN_ON(skl_ddb_entry_size(ddb_y)); + + skl_check_wm_level(&wm->trans_wm, ddb); + } + + skl_check_wm_level(&wm->sagv.wm0, ddb); + skl_check_wm_level(&wm->sagv.trans_wm, ddb); } return 0; @@ -5408,6 +5304,7 @@ skl_compute_wm_params(const struct intel_crtc_state *crtc_state, } wp->y_tiled = modifier == I915_FORMAT_MOD_Y_TILED || + modifier == I915_FORMAT_MOD_4_TILED || modifier == I915_FORMAT_MOD_Yf_TILED || modifier == I915_FORMAT_MOD_Y_TILED_CCS || modifier == I915_FORMAT_MOD_Yf_TILED_CCS; @@ -5926,7 +5823,7 @@ static void skl_write_wm_level(struct drm_i915_private *dev_priv, val |= PLANE_WM_EN; if (level->ignore_lines) val |= PLANE_WM_IGNORE_LINES; - val |= level->blocks; + val |= REG_FIELD_PREP(PLANE_WM_BLOCKS_MASK, level->blocks); val |= REG_FIELD_PREP(PLANE_WM_LINES_MASK, level->lines); intel_de_write_fw(dev_priv, reg, val); @@ -5940,11 +5837,10 @@ void skl_write_plane_wm(struct intel_plane *plane, enum plane_id plane_id = plane->id; enum pipe pipe = plane->pipe; const struct skl_pipe_wm *pipe_wm = &crtc_state->wm.skl.optimal; - const struct skl_plane_wm *wm = &pipe_wm->planes[plane_id]; + const struct skl_ddb_entry *ddb = + &crtc_state->wm.skl.plane_ddb[plane_id]; const struct skl_ddb_entry *ddb_y = &crtc_state->wm.skl.plane_ddb_y[plane_id]; - const struct skl_ddb_entry *ddb_uv = - &crtc_state->wm.skl.plane_ddb_uv[plane_id]; for (level = 0; level <= max_level; level++) skl_write_wm_level(dev_priv, PLANE_WM(pipe, plane_id, level), @@ -5954,25 +5850,20 @@ void skl_write_plane_wm(struct intel_plane *plane, skl_plane_trans_wm(pipe_wm, plane_id)); if (HAS_HW_SAGV_WM(dev_priv)) { + const struct skl_plane_wm *wm = &pipe_wm->planes[plane_id]; + skl_write_wm_level(dev_priv, PLANE_WM_SAGV(pipe, plane_id), &wm->sagv.wm0); skl_write_wm_level(dev_priv, PLANE_WM_SAGV_TRANS(pipe, plane_id), &wm->sagv.trans_wm); } - if (DISPLAY_VER(dev_priv) >= 11) { - skl_ddb_entry_write(dev_priv, - PLANE_BUF_CFG(pipe, plane_id), ddb_y); - return; - } - - if (wm->is_planar) - swap(ddb_y, ddb_uv); - - skl_ddb_entry_write(dev_priv, - PLANE_BUF_CFG(pipe, plane_id), ddb_y); skl_ddb_entry_write(dev_priv, - PLANE_NV12_BUF_CFG(pipe, plane_id), ddb_uv); + PLANE_BUF_CFG(pipe, plane_id), ddb); + + if (DISPLAY_VER(dev_priv) < 11) + skl_ddb_entry_write(dev_priv, + PLANE_NV12_BUF_CFG(pipe, plane_id), ddb_y); } void skl_write_cursor_wm(struct intel_plane *plane, @@ -5984,7 +5875,7 @@ void skl_write_cursor_wm(struct intel_plane *plane, enum pipe pipe = plane->pipe; const struct skl_pipe_wm *pipe_wm = &crtc_state->wm.skl.optimal; const struct skl_ddb_entry *ddb = - &crtc_state->wm.skl.plane_ddb_y[plane_id]; + &crtc_state->wm.skl.plane_ddb[plane_id]; for (level = 0; level <= max_level; level++) skl_write_wm_level(dev_priv, CUR_WM(pipe, level), @@ -6081,10 +5972,10 @@ skl_ddb_add_affected_planes(const struct intel_crtc_state *old_crtc_state, struct intel_plane_state *plane_state; enum plane_id plane_id = plane->id; - if (skl_ddb_entry_equal(&old_crtc_state->wm.skl.plane_ddb_y[plane_id], - &new_crtc_state->wm.skl.plane_ddb_y[plane_id]) && - skl_ddb_entry_equal(&old_crtc_state->wm.skl.plane_ddb_uv[plane_id], - &new_crtc_state->wm.skl.plane_ddb_uv[plane_id])) + if (skl_ddb_entry_equal(&old_crtc_state->wm.skl.plane_ddb[plane_id], + &new_crtc_state->wm.skl.plane_ddb[plane_id]) && + skl_ddb_entry_equal(&old_crtc_state->wm.skl.plane_ddb_y[plane_id], + &new_crtc_state->wm.skl.plane_ddb_y[plane_id])) continue; plane_state = intel_atomic_get_plane_state(state, plane); @@ -6147,7 +6038,7 @@ skl_compute_ddb(struct intel_atomic_state *state) return ret; } - if (IS_ALDERLAKE_P(dev_priv)) + if (HAS_MBUS_JOINING(dev_priv)) new_dbuf_state->joined_mbus = adlp_check_mbus_joined(new_dbuf_state->active_pipes); @@ -6186,8 +6077,8 @@ skl_compute_ddb(struct intel_atomic_state *state) old_dbuf_state->enabled_slices, new_dbuf_state->enabled_slices, INTEL_INFO(dev_priv)->dbuf.slice_mask, - yesno(old_dbuf_state->joined_mbus), - yesno(new_dbuf_state->joined_mbus)); + str_yes_no(old_dbuf_state->joined_mbus), + str_yes_no(new_dbuf_state->joined_mbus)); } for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { @@ -6253,8 +6144,8 @@ skl_print_wm_changes(struct intel_atomic_state *state) enum plane_id plane_id = plane->id; const struct skl_ddb_entry *old, *new; - old = &old_crtc_state->wm.skl.plane_ddb_y[plane_id]; - new = &new_crtc_state->wm.skl.plane_ddb_y[plane_id]; + old = &old_crtc_state->wm.skl.plane_ddb[plane_id]; + new = &new_crtc_state->wm.skl.plane_ddb[plane_id]; if (skl_ddb_entry_equal(old, new)) continue; @@ -6574,7 +6465,7 @@ static void skl_wm_level_from_reg_val(u32 val, struct skl_wm_level *level) { level->enable = val & PLANE_WM_EN; level->ignore_lines = val & PLANE_WM_IGNORE_LINES; - level->blocks = val & PLANE_WM_BLOCKS_MASK; + level->blocks = REG_FIELD_GET(PLANE_WM_BLOCKS_MASK, val); level->lines = REG_FIELD_GET(PLANE_WM_LINES_MASK, val); } @@ -6639,7 +6530,7 @@ void skl_wm_get_hw_state(struct drm_i915_private *dev_priv) to_intel_dbuf_state(dev_priv->dbuf.obj.state); struct intel_crtc *crtc; - if (IS_ALDERLAKE_P(dev_priv)) + if (HAS_MBUS_JOINING(dev_priv)) dbuf_state->joined_mbus = intel_de_read(dev_priv, MBUS_CTL) & MBUS_JOIN; for_each_intel_crtc(&dev_priv->drm, crtc) { @@ -6656,16 +6547,16 @@ void skl_wm_get_hw_state(struct drm_i915_private *dev_priv) memset(&dbuf_state->ddb[pipe], 0, sizeof(dbuf_state->ddb[pipe])); for_each_plane_id_on_crtc(crtc, plane_id) { + struct skl_ddb_entry *ddb = + &crtc_state->wm.skl.plane_ddb[plane_id]; struct skl_ddb_entry *ddb_y = &crtc_state->wm.skl.plane_ddb_y[plane_id]; - struct skl_ddb_entry *ddb_uv = - &crtc_state->wm.skl.plane_ddb_uv[plane_id]; skl_ddb_get_hw_plane_state(dev_priv, crtc->pipe, - plane_id, ddb_y, ddb_uv); + plane_id, ddb, ddb_y); + skl_ddb_entry_union(&dbuf_state->ddb[pipe], ddb); skl_ddb_entry_union(&dbuf_state->ddb[pipe], ddb_y); - skl_ddb_entry_union(&dbuf_state->ddb[pipe], ddb_uv); } dbuf_state->weight[pipe] = intel_crtc_ddb_weight(crtc_state); @@ -6689,7 +6580,7 @@ void skl_wm_get_hw_state(struct drm_i915_private *dev_priv) crtc->base.base.id, crtc->base.name, dbuf_state->slices[pipe], dbuf_state->ddb[pipe].start, dbuf_state->ddb[pipe].end, dbuf_state->active_pipes, - yesno(dbuf_state->joined_mbus)); + str_yes_no(dbuf_state->joined_mbus)); } dbuf_state->enabled_slices = dev_priv->dbuf.enabled_slices; @@ -7000,7 +6891,8 @@ void g4x_wm_get_hw_state(struct drm_i915_private *dev_priv) "Initial HPLL watermarks: plane=%d, SR cursor=%d fbc=%d\n", wm->hpll.plane, wm->hpll.cursor, wm->hpll.fbc); drm_dbg_kms(&dev_priv->drm, "Initial SR=%s HPLL=%s FBC=%s\n", - yesno(wm->cxsr), yesno(wm->hpll_en), yesno(wm->fbc_en)); + str_yes_no(wm->cxsr), str_yes_no(wm->hpll_en), + str_yes_no(wm->fbc_en)); } void g4x_wm_sanitize(struct drm_i915_private *dev_priv) @@ -7578,6 +7470,9 @@ static void adlp_init_clock_gating(struct drm_i915_private *dev_priv) /* Wa_22011091694:adlp */ intel_de_rmw(dev_priv, GEN9_CLKGATE_DIS_5, 0, DPCE_GATING_DIS); + + /* Bspec/49189 Initialize Sequence */ + intel_de_rmw(dev_priv, GEN8_CHICKEN_DCPR_1, DDI_CLOCK_REG_ACCESS, 0); } static void dg1_init_clock_gating(struct drm_i915_private *dev_priv) @@ -8175,8 +8070,7 @@ void intel_init_pm(struct drm_i915_private *dev_priv) else if (GRAPHICS_VER(dev_priv) == 5) ilk_get_mem_freq(dev_priv); - if (intel_has_sagv(dev_priv)) - skl_setup_sagv_block_time(dev_priv); + intel_sagv_init(dev_priv); /* For FIFO watermark updates */ if (DISPLAY_VER(dev_priv) >= 9) { @@ -8301,7 +8195,7 @@ static void update_mbus_pre_enable(struct intel_atomic_state *state) const struct intel_dbuf_state *dbuf_state = intel_atomic_get_new_dbuf_state(state); - if (!IS_ALDERLAKE_P(dev_priv)) + if (!HAS_MBUS_JOINING(dev_priv)) return; /* @@ -8367,3 +8261,55 @@ void intel_dbuf_post_plane_update(struct intel_atomic_state *state) gen9_dbuf_slices_update(dev_priv, new_dbuf_state->enabled_slices); } + +void intel_mbus_dbox_update(struct intel_atomic_state *state) +{ + struct drm_i915_private *i915 = to_i915(state->base.dev); + const struct intel_dbuf_state *new_dbuf_state, *old_dbuf_state; + const struct intel_crtc_state *new_crtc_state; + const struct intel_crtc *crtc; + u32 val = 0; + int i; + + if (DISPLAY_VER(i915) < 11) + return; + + new_dbuf_state = intel_atomic_get_new_dbuf_state(state); + old_dbuf_state = intel_atomic_get_old_dbuf_state(state); + if (!new_dbuf_state || + (new_dbuf_state->joined_mbus == old_dbuf_state->joined_mbus && + new_dbuf_state->active_pipes == old_dbuf_state->active_pipes)) + return; + + if (DISPLAY_VER(i915) >= 12) { + val |= MBUS_DBOX_B2B_TRANSACTIONS_MAX(16); + val |= MBUS_DBOX_B2B_TRANSACTIONS_DELAY(1); + val |= MBUS_DBOX_REGULATE_B2B_TRANSACTIONS_EN; + } + + /* Wa_22010947358:adl-p */ + if (IS_ALDERLAKE_P(i915)) + val |= new_dbuf_state->joined_mbus ? MBUS_DBOX_A_CREDIT(6) : + MBUS_DBOX_A_CREDIT(4); + else + val |= MBUS_DBOX_A_CREDIT(2); + + if (IS_ALDERLAKE_P(i915)) { + val |= MBUS_DBOX_BW_CREDIT(2); + val |= MBUS_DBOX_B_CREDIT(8); + } else if (DISPLAY_VER(i915) >= 12) { + val |= MBUS_DBOX_BW_CREDIT(2); + val |= MBUS_DBOX_B_CREDIT(12); + } else { + val |= MBUS_DBOX_BW_CREDIT(1); + val |= MBUS_DBOX_B_CREDIT(8); + } + + for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { + if (!new_crtc_state->hw.active || + !intel_crtc_needs_modeset(new_crtc_state)) + continue; + + intel_de_write(i915, PIPE_MBUS_DBOX_CTL(crtc->pipe), val); + } +} diff --git a/drivers/gpu/drm/i915/intel_pm.h b/drivers/gpu/drm/i915/intel_pm.h index 51705151b842..50604cf7398c 100644 --- a/drivers/gpu/drm/i915/intel_pm.h +++ b/drivers/gpu/drm/i915/intel_pm.h @@ -94,5 +94,6 @@ intel_atomic_get_dbuf_state(struct intel_atomic_state *state); int intel_dbuf_init(struct drm_i915_private *dev_priv); void intel_dbuf_pre_plane_update(struct intel_atomic_state *state); void intel_dbuf_post_plane_update(struct intel_atomic_state *state); +void intel_mbus_dbox_update(struct intel_atomic_state *state); #endif /* __INTEL_PM_H__ */ diff --git a/drivers/gpu/drm/i915/intel_step.c b/drivers/gpu/drm/i915/intel_step.c index 4fd69ecd1481..74e8e4680028 100644 --- a/drivers/gpu/drm/i915/intel_step.c +++ b/drivers/gpu/drm/i915/intel_step.c @@ -131,6 +131,10 @@ static const struct intel_step_info adls_rpls_revids[] = { [0xC] = { COMMON_GT_MEDIA_STEP(D0), .display_step = STEP_C0 }, }; +static const struct intel_step_info adlp_n_revids[] = { + [0x0] = { COMMON_GT_MEDIA_STEP(A0), .display_step = STEP_D0 }, +}; + void intel_step_init(struct drm_i915_private *i915) { const struct intel_step_info *revids = NULL; @@ -150,6 +154,9 @@ void intel_step_init(struct drm_i915_private *i915) } else if (IS_XEHPSDV(i915)) { revids = xehpsdv_revids; size = ARRAY_SIZE(xehpsdv_revids); + } else if (IS_ADLP_N(i915)) { + revids = adlp_n_revids; + size = ARRAY_SIZE(adlp_n_revids); } else if (IS_ALDERLAKE_P(i915)) { revids = adlp_revids; size = ARRAY_SIZE(adlp_revids); diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index dd8fdd5863de..24cd3c3729ca 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -1502,11 +1502,10 @@ ilk_dummy_write(struct intel_uncore *uncore) static void __unclaimed_reg_debug(struct intel_uncore *uncore, const i915_reg_t reg, - const bool read, - const bool before) + const bool read) { if (drm_WARN(&uncore->i915->drm, - check_for_unclaimed_mmio(uncore) && !before, + check_for_unclaimed_mmio(uncore), "Unclaimed %s register 0x%x\n", read ? "read from" : "write to", i915_mmio_reg_offset(reg))) @@ -1514,6 +1513,18 @@ __unclaimed_reg_debug(struct intel_uncore *uncore, uncore->i915->params.mmio_debug--; } +static void +__unclaimed_previous_reg_debug(struct intel_uncore *uncore, + const i915_reg_t reg, + const bool read) +{ + if (check_for_unclaimed_mmio(uncore)) + drm_dbg(&uncore->i915->drm, + "Unclaimed access detected before %s register 0x%x\n", + read ? "read from" : "write to", + i915_mmio_reg_offset(reg)); +} + static inline void unclaimed_reg_debug(struct intel_uncore *uncore, const i915_reg_t reg, @@ -1526,13 +1537,13 @@ unclaimed_reg_debug(struct intel_uncore *uncore, /* interrupts are disabled and re-enabled around uncore->lock usage */ lockdep_assert_held(&uncore->lock); - if (before) + if (before) { spin_lock(&uncore->debug->lock); - - __unclaimed_reg_debug(uncore, reg, read, before); - - if (!before) + __unclaimed_previous_reg_debug(uncore, reg, read); + } else { + __unclaimed_reg_debug(uncore, reg, read); spin_unlock(&uncore->debug->lock); + } } #define __vgpu_read(x) \ diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_debugfs.c b/drivers/gpu/drm/i915/pxp/intel_pxp_debugfs.c index 10e1e45471f1..c9da1015eb42 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_debugfs.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_debugfs.c @@ -4,6 +4,8 @@ */ #include <linux/debugfs.h> +#include <linux/string_helpers.h> + #include <drm/drm_print.h> #include "gt/intel_gt_debugfs.h" @@ -22,7 +24,7 @@ static int pxp_info_show(struct seq_file *m, void *data) return 0; } - drm_printf(&p, "active: %s\n", yesno(intel_pxp_is_active(pxp))); + drm_printf(&p, "active: %s\n", str_yes_no(intel_pxp_is_active(pxp))); drm_printf(&p, "instance counter: %u\n", pxp->key_instance); return 0; diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_session.c b/drivers/gpu/drm/i915/pxp/intel_pxp_session.c index 598840b73dfa..92b00b4de240 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_session.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_session.c @@ -3,8 +3,6 @@ * Copyright(c) 2020, Intel Corporation. All rights reserved. */ -#include <drm/i915_drm.h> - #include "i915_drv.h" #include "intel_pxp.h" diff --git a/drivers/gpu/drm/i915/selftests/i915_active.c b/drivers/gpu/drm/i915/selftests/i915_active.c index 2dac9be1de58..b61fe850e924 100644 --- a/drivers/gpu/drm/i915/selftests/i915_active.c +++ b/drivers/gpu/drm/i915/selftests/i915_active.c @@ -5,6 +5,7 @@ */ #include <linux/kref.h> +#include <linux/string_helpers.h> #include "gem/i915_gem_pm.h" #include "gt/intel_gt.h" @@ -280,7 +281,7 @@ void i915_active_print(struct i915_active *ref, struct drm_printer *m) drm_printf(m, "active %ps:%ps\n", ref->active, ref->retire); drm_printf(m, "\tcount: %d\n", atomic_read(&ref->count)); drm_printf(m, "\tpreallocated barriers? %s\n", - yesno(!llist_empty(&ref->preallocated_barriers))); + str_yes_no(!llist_empty(&ref->preallocated_barriers))); if (i915_active_acquire_if_busy(ref)) { struct active_node *it, *n; diff --git a/drivers/gpu/drm/i915/vlv_suspend.c b/drivers/gpu/drm/i915/vlv_suspend.c index 1d9da32195c2..664fde244f59 100644 --- a/drivers/gpu/drm/i915/vlv_suspend.c +++ b/drivers/gpu/drm/i915/vlv_suspend.c @@ -3,6 +3,7 @@ * Copyright © 2020 Intel Corporation */ +#include <linux/string_helpers.h> #include <linux/kernel.h> #include <drm/drm_print.h> @@ -375,7 +376,7 @@ static void vlv_wait_for_gt_wells(struct drm_i915_private *dev_priv, if (vlv_wait_for_pw_status(dev_priv, mask, val)) drm_dbg(&dev_priv->drm, "timeout waiting for GT wells to go %s\n", - onoff(wait_for_on)); + str_on_off(wait_for_on)); } static void vlv_check_no_gt_access(struct drm_i915_private *i915) diff --git a/drivers/gpu/drm/imx/dw_hdmi-imx.c b/drivers/gpu/drm/imx/dw_hdmi-imx.c index 87428fb23d9f..a2277a0d6d06 100644 --- a/drivers/gpu/drm/imx/dw_hdmi-imx.c +++ b/drivers/gpu/drm/imx/dw_hdmi-imx.c @@ -222,6 +222,7 @@ static int dw_hdmi_imx_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; const struct of_device_id *match = of_match_node(dw_hdmi_imx_dt_ids, np); struct imx_hdmi *hdmi; + int ret; hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL); if (!hdmi) @@ -243,10 +244,15 @@ static int dw_hdmi_imx_probe(struct platform_device *pdev) hdmi->bridge = of_drm_find_bridge(np); if (!hdmi->bridge) { dev_err(hdmi->dev, "Unable to find bridge\n"); + dw_hdmi_remove(hdmi->hdmi); return -ENODEV; } - return component_add(&pdev->dev, &dw_hdmi_imx_ops); + ret = component_add(&pdev->dev, &dw_hdmi_imx_ops); + if (ret) + dw_hdmi_remove(hdmi->hdmi); + + return ret; } static int dw_hdmi_imx_remove(struct platform_device *pdev) diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c index c8cf819f39ce..14a058a42854 100644 --- a/drivers/gpu/drm/imx/imx-ldb.c +++ b/drivers/gpu/drm/imx/imx-ldb.c @@ -571,6 +571,8 @@ static int imx_ldb_panel_ddc(struct device *dev, edidp = of_get_property(child, "edid", &edid_len); if (edidp) { channel->edid = kmemdup(edidp, edid_len, GFP_KERNEL); + if (!channel->edid) + return -ENOMEM; } else if (!channel->panel) { /* fallback to display-timings node */ ret = of_get_drm_display_mode(child, diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c index 06cb1a59b9bc..63ba2ad84679 100644 --- a/drivers/gpu/drm/imx/parallel-display.c +++ b/drivers/gpu/drm/imx/parallel-display.c @@ -75,8 +75,10 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector) ret = of_get_drm_display_mode(np, &imxpd->mode, &imxpd->bus_flags, OF_USE_NATIVE_MODE); - if (ret) + if (ret) { + drm_mode_destroy(connector->dev, mode); return ret; + } drm_mode_copy(mode, &imxpd->mode); mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm20b.c index e1772211b0a4..612310d5d481 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm20b.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm20b.c @@ -216,6 +216,7 @@ gm20b_pmu = { .intr = gt215_pmu_intr, .recv = gm20b_pmu_recv, .initmsg = gm20b_pmu_initmsg, + .reset = gf100_pmu_reset, }; #if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp102.c index 6bf7fc1bd1e3..1a6f9c3af5ec 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp102.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp102.c @@ -23,7 +23,7 @@ */ #include "priv.h" -static void +void gp102_pmu_reset(struct nvkm_pmu *pmu) { struct nvkm_device *device = pmu->subdev.device; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp10b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp10b.c index ba1583bb618b..94cfb1791af6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp10b.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp10b.c @@ -83,6 +83,7 @@ gp10b_pmu = { .intr = gt215_pmu_intr, .recv = gm20b_pmu_recv, .initmsg = gm20b_pmu_initmsg, + .reset = gp102_pmu_reset, }; #if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h index bcaade758ff7..21abf31f4442 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h @@ -41,6 +41,7 @@ int gt215_pmu_send(struct nvkm_pmu *, u32[2], u32, u32, u32, u32); bool gf100_pmu_enabled(struct nvkm_pmu *); void gf100_pmu_reset(struct nvkm_pmu *); +void gp102_pmu_reset(struct nvkm_pmu *pmu); void gk110_pmu_pgob(struct nvkm_pmu *, bool); diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9341.c b/drivers/gpu/drm/panel/panel-ilitek-ili9341.c index a07ef26234e5..6826f4d4826a 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9341.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9341.c @@ -612,8 +612,10 @@ static int ili9341_dbi_probe(struct spi_device *spi, struct gpio_desc *dc, int ret; vcc = devm_regulator_get_optional(dev, "vcc"); - if (IS_ERR(vcc)) + if (IS_ERR(vcc)) { dev_err(dev, "get optional vcc failed\n"); + vcc = NULL; + } dbidev = devm_drm_dev_alloc(dev, &ili9341_dbi_driver, struct mipi_dbi_dev, drm); diff --git a/drivers/gpu/drm/panel/panel-newvision-nv3052c.c b/drivers/gpu/drm/panel/panel-newvision-nv3052c.c index 127bcfdb59df..cf078f0d3cd3 100644 --- a/drivers/gpu/drm/panel/panel-newvision-nv3052c.c +++ b/drivers/gpu/drm/panel/panel-newvision-nv3052c.c @@ -416,15 +416,13 @@ static int nv3052c_probe(struct spi_device *spi) return 0; } -static int nv3052c_remove(struct spi_device *spi) +static void nv3052c_remove(struct spi_device *spi) { struct nv3052c *priv = spi_get_drvdata(spi); drm_panel_remove(&priv->panel); drm_panel_disable(&priv->panel); drm_panel_unprepare(&priv->panel); - - return 0; } static const struct drm_display_mode ltk035c5444t_modes[] = { diff --git a/drivers/gpu/ipu-v3/ipu-di.c b/drivers/gpu/ipu-v3/ipu-di.c index 666223c6bec4..0a34e0ab4fe6 100644 --- a/drivers/gpu/ipu-v3/ipu-di.c +++ b/drivers/gpu/ipu-v3/ipu-di.c @@ -447,8 +447,9 @@ static void ipu_di_config_clock(struct ipu_di *di, error = rate / (sig->mode.pixelclock / 1000); - dev_dbg(di->ipu->dev, " IPU clock can give %lu with divider %u, error %d.%u%%\n", - rate, div, (signed)(error - 1000) / 10, error % 10); + dev_dbg(di->ipu->dev, " IPU clock can give %lu with divider %u, error %c%d.%d%%\n", + rate, div, error < 1000 ? '-' : '+', + abs(error - 1000) / 10, abs(error - 1000) % 10); /* Allow a 1% error */ if (error < 1010 && error >= 990) { diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index 26d269ba947c..85a2142c9384 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -380,7 +380,7 @@ void vmbus_channel_map_relid(struct vmbus_channel *channel) * execute: * * (a) In the "normal (i.e., not resuming from hibernation)" path, - * the full barrier in smp_store_mb() guarantees that the store + * the full barrier in virt_store_mb() guarantees that the store * is propagated to all CPUs before the add_channel_work work * is queued. In turn, add_channel_work is queued before the * channel's ring buffer is allocated/initialized and the @@ -392,14 +392,14 @@ void vmbus_channel_map_relid(struct vmbus_channel *channel) * recv_int_page before retrieving the channel pointer from the * array of channels. * - * (b) In the "resuming from hibernation" path, the smp_store_mb() + * (b) In the "resuming from hibernation" path, the virt_store_mb() * guarantees that the store is propagated to all CPUs before * the VMBus connection is marked as ready for the resume event * (cf. check_ready_for_resume_event()). The interrupt handler * of the VMBus driver and vmbus_chan_sched() can not run before * vmbus_bus_resume() has completed execution (cf. resume_noirq). */ - smp_store_mb( + virt_store_mb( vmbus_connection.channels[channel->offermsg.child_relid], channel); } diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c index 439f99b8b5de..3248b48f37f6 100644 --- a/drivers/hv/hv_balloon.c +++ b/drivers/hv/hv_balloon.c @@ -17,6 +17,7 @@ #include <linux/slab.h> #include <linux/kthread.h> #include <linux/completion.h> +#include <linux/count_zeros.h> #include <linux/memory_hotplug.h> #include <linux/memory.h> #include <linux/notifier.h> @@ -1130,6 +1131,7 @@ static void post_status(struct hv_dynmem_device *dm) struct dm_status status; unsigned long now = jiffies; unsigned long last_post = last_post_time; + unsigned long num_pages_avail, num_pages_committed; if (pressure_report_delay > 0) { --pressure_report_delay; @@ -1154,16 +1156,21 @@ static void post_status(struct hv_dynmem_device *dm) * num_pages_onlined) as committed to the host, otherwise it can try * asking us to balloon them out. */ - status.num_avail = si_mem_available(); - status.num_committed = vm_memory_committed() + + num_pages_avail = si_mem_available(); + num_pages_committed = vm_memory_committed() + dm->num_pages_ballooned + (dm->num_pages_added > dm->num_pages_onlined ? dm->num_pages_added - dm->num_pages_onlined : 0) + compute_balloon_floor(); - trace_balloon_status(status.num_avail, status.num_committed, + trace_balloon_status(num_pages_avail, num_pages_committed, vm_memory_committed(), dm->num_pages_ballooned, dm->num_pages_added, dm->num_pages_onlined); + + /* Convert numbers of pages into numbers of HV_HYP_PAGEs. */ + status.num_avail = num_pages_avail * NR_HV_HYP_PAGES_IN_PAGE; + status.num_committed = num_pages_committed * NR_HV_HYP_PAGES_IN_PAGE; + /* * If our transaction ID is no longer current, just don't * send the status. This can happen if we were interrupted @@ -1653,6 +1660,38 @@ static void disable_page_reporting(void) } } +static int ballooning_enabled(void) +{ + /* + * Disable ballooning if the page size is not 4k (HV_HYP_PAGE_SIZE), + * since currently it's unclear to us whether an unballoon request can + * make sure all page ranges are guest page size aligned. + */ + if (PAGE_SIZE != HV_HYP_PAGE_SIZE) { + pr_info("Ballooning disabled because page size is not 4096 bytes\n"); + return 0; + } + + return 1; +} + +static int hot_add_enabled(void) +{ + /* + * Disable hot add on ARM64, because we currently rely on + * memory_add_physaddr_to_nid() to get a node id of a hot add range, + * however ARM64's memory_add_physaddr_to_nid() always return 0 and + * DM_MEM_HOT_ADD_REQUEST doesn't have the NUMA node information for + * add_memory(). + */ + if (IS_ENABLED(CONFIG_ARM64)) { + pr_info("Memory hot add disabled on ARM64\n"); + return 0; + } + + return 1; +} + static int balloon_connect_vsp(struct hv_device *dev) { struct dm_version_request version_req; @@ -1724,8 +1763,8 @@ static int balloon_connect_vsp(struct hv_device *dev) * currently still requires the bits to be set, so we have to add code * to fail the host's hot-add and balloon up/down requests, if any. */ - cap_msg.caps.cap_bits.balloon = 1; - cap_msg.caps.cap_bits.hot_add = 1; + cap_msg.caps.cap_bits.balloon = ballooning_enabled(); + cap_msg.caps.cap_bits.hot_add = hot_add_enabled(); /* * Specify our alignment requirements as it relates diff --git a/drivers/hv/hv_common.c b/drivers/hv/hv_common.c index c1dd21d0d7ef..ae68298c0dca 100644 --- a/drivers/hv/hv_common.c +++ b/drivers/hv/hv_common.c @@ -20,6 +20,7 @@ #include <linux/panic_notifier.h> #include <linux/ptrace.h> #include <linux/slab.h> +#include <linux/dma-map-ops.h> #include <asm/hyperv-tlfs.h> #include <asm/mshyperv.h> @@ -218,6 +219,16 @@ bool hv_query_ext_cap(u64 cap_query) } EXPORT_SYMBOL_GPL(hv_query_ext_cap); +void hv_setup_dma_ops(struct device *dev, bool coherent) +{ + /* + * Hyper-V does not offer a vIOMMU in the guest + * VM, so pass 0/NULL for the IOMMU settings + */ + arch_setup_dma_ops(dev, 0, 0, NULL, coherent); +} +EXPORT_SYMBOL_GPL(hv_setup_dma_ops); + bool hv_is_hibernation_supported(void) { return !hv_root_partition && acpi_sleep_state_supported(ACPI_STATE_S4); diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c index 71efacb90965..3d215d9dec43 100644 --- a/drivers/hv/ring_buffer.c +++ b/drivers/hv/ring_buffer.c @@ -439,7 +439,16 @@ int hv_ringbuffer_read(struct vmbus_channel *channel, static u32 hv_pkt_iter_avail(const struct hv_ring_buffer_info *rbi) { u32 priv_read_loc = rbi->priv_read_index; - u32 write_loc = READ_ONCE(rbi->ring_buffer->write_index); + u32 write_loc; + + /* + * The Hyper-V host writes the packet data, then uses + * store_release() to update the write_index. Use load_acquire() + * here to prevent loads of the packet data from being re-ordered + * before the read of the write_index and potentially getting + * stale data. + */ + write_loc = virt_load_acquire(&rbi->ring_buffer->write_index); if (write_loc >= priv_read_loc) return write_loc - priv_read_loc; diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 60ee8b329f9e..14de17087864 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -77,8 +77,8 @@ static int hyperv_panic_event(struct notifier_block *nb, unsigned long val, /* * Hyper-V should be notified only once about a panic. If we will be - * doing hyperv_report_panic_msg() later with kmsg data, don't do - * the notification here. + * doing hv_kmsg_dump() with kmsg data later, don't do the notification + * here. */ if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE && hyperv_report_reg()) { @@ -100,8 +100,8 @@ static int hyperv_die_event(struct notifier_block *nb, unsigned long val, /* * Hyper-V should be notified only once about a panic. If we will be - * doing hyperv_report_panic_msg() later with kmsg data, don't do - * the notification here. + * doing hv_kmsg_dump() with kmsg data later, don't do the notification + * here. */ if (hyperv_report_reg()) hyperv_report_panic(regs, val, true); @@ -921,6 +921,21 @@ static int vmbus_probe(struct device *child_device) } /* + * vmbus_dma_configure -- Configure DMA coherence for VMbus device + */ +static int vmbus_dma_configure(struct device *child_device) +{ + /* + * On ARM64, propagate the DMA coherence setting from the top level + * VMbus ACPI device to the child VMbus device being added here. + * On x86/x64 coherence is assumed and these calls have no effect. + */ + hv_setup_dma_ops(child_device, + device_get_dma_attr(&hv_acpi_dev->dev) == DEV_DMA_COHERENT); + return 0; +} + +/* * vmbus_remove - Remove a vmbus device */ static void vmbus_remove(struct device *child_device) @@ -1040,6 +1055,7 @@ static struct bus_type hv_bus = { .remove = vmbus_remove, .probe = vmbus_probe, .uevent = vmbus_uevent, + .dma_configure = vmbus_dma_configure, .dev_groups = vmbus_dev_groups, .drv_groups = vmbus_drv_groups, .bus_groups = vmbus_bus_groups, @@ -1546,14 +1562,20 @@ static int vmbus_bus_init(void) if (ret) goto err_connect; + if (hv_is_isolation_supported()) + sysctl_record_panic_msg = 0; + /* * Only register if the crash MSRs are available */ if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE) { u64 hyperv_crash_ctl; /* - * Sysctl registration is not fatal, since by default - * reporting is enabled. + * Panic message recording (sysctl_record_panic_msg) + * is enabled by default in non-isolated guests and + * disabled by default in isolated guests; the panic + * message recording won't be available in isolated + * guests should the following registration fail. */ hv_ctl_table_hdr = register_sysctl_table(hv_root_table); if (!hv_ctl_table_hdr) @@ -2097,6 +2119,10 @@ int vmbus_device_register(struct hv_device *child_device_obj) child_device_obj->device.parent = &hv_acpi_dev->dev; child_device_obj->device.release = vmbus_device_release; + child_device_obj->device.dma_parms = &child_device_obj->dma_parms; + child_device_obj->device.dma_mask = &child_device_obj->dma_mask; + dma_set_mask(&child_device_obj->device, DMA_BIT_MASK(64)); + /* * Register with the LDM. This will kick off the driver/device * binding...which will eventually call vmbus_match() and vmbus_probe() @@ -2122,9 +2148,6 @@ int vmbus_device_register(struct hv_device *child_device_obj) } hv_debug_add_dev_dir(child_device_obj); - child_device_obj->device.dma_parms = &child_device_obj->dma_parms; - child_device_obj->device.dma_mask = &child_device_obj->dma_mask; - dma_set_mask(&child_device_obj->device, DMA_BIT_MASK(64)); return 0; err_kset_unregister: @@ -2428,6 +2451,21 @@ static int vmbus_acpi_add(struct acpi_device *device) hv_acpi_dev = device; + /* + * Older versions of Hyper-V for ARM64 fail to include the _CCA + * method on the top level VMbus device in the DSDT. But devices + * are hardware coherent in all current Hyper-V use cases, so fix + * up the ACPI device to behave as if _CCA is present and indicates + * hardware coherence. + */ + ACPI_COMPANION_SET(&device->dev, device); + if (IS_ENABLED(CONFIG_ACPI_CCA_REQUIRED) && + device_get_dma_attr(&device->dev) == DEV_DMA_NOT_SUPPORTED) { + pr_info("No ACPI _CCA found; assuming coherent device I/O\n"); + device->flags.cca_seen = true; + device->flags.coherent_dma = true; + } + result = acpi_walk_resources(device->handle, METHOD_NAME__CRS, vmbus_walk_resources, NULL); @@ -2780,10 +2818,15 @@ static void __exit vmbus_exit(void) if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE) { kmsg_dump_unregister(&hv_kmsg_dumper); unregister_die_notifier(&hyperv_die_block); - atomic_notifier_chain_unregister(&panic_notifier_list, - &hyperv_panic_block); } + /* + * The panic notifier is always registered, hence we should + * also unconditionally unregister it here as well. + */ + atomic_notifier_chain_unregister(&panic_notifier_list, + &hyperv_panic_block); + free_page((unsigned long)hv_panic_page); unregister_sysctl_table(hv_ctl_table_hdr); hv_ctl_table_hdr = NULL; diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 35f0d5e7533d..1c107d6d03b9 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -2824,6 +2824,7 @@ static int cm_dreq_handler(struct cm_work *work) switch (cm_id_priv->id.state) { case IB_CM_REP_SENT: case IB_CM_DREQ_SENT: + case IB_CM_MRA_REP_RCVD: ib_cancel_mad(cm_id_priv->msg); break; case IB_CM_ESTABLISHED: @@ -2831,8 +2832,6 @@ static int cm_dreq_handler(struct cm_work *work) cm_id_priv->id.lap_state == IB_CM_MRA_LAP_RCVD) ib_cancel_mad(cm_id_priv->msg); break; - case IB_CM_MRA_REP_RCVD: - break; case IB_CM_TIMEWAIT: atomic_long_inc(&work->port->counters[CM_RECV_DUPLICATES] [CM_DREQ_COUNTER]); diff --git a/drivers/infiniband/hw/hfi1/mmu_rb.c b/drivers/infiniband/hw/hfi1/mmu_rb.c index 876cc78a22cc..7333646021bb 100644 --- a/drivers/infiniband/hw/hfi1/mmu_rb.c +++ b/drivers/infiniband/hw/hfi1/mmu_rb.c @@ -80,6 +80,9 @@ void hfi1_mmu_rb_unregister(struct mmu_rb_handler *handler) unsigned long flags; struct list_head del_list; + /* Prevent freeing of mm until we are completely finished. */ + mmgrab(handler->mn.mm); + /* Unregister first so we don't get any more notifications. */ mmu_notifier_unregister(&handler->mn, handler->mn.mm); @@ -102,6 +105,9 @@ void hfi1_mmu_rb_unregister(struct mmu_rb_handler *handler) do_remove(handler, &del_list); + /* Now the mm may be freed. */ + mmdrop(handler->mn.mm); + kfree(handler); } diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index 956f8e875daa..32ef67e9a6a7 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -574,8 +574,10 @@ static void __cache_work_func(struct mlx5_cache_ent *ent) spin_lock_irq(&ent->lock); if (ent->disabled) goto out; - if (need_delay) + if (need_delay) { queue_delayed_work(cache->wq, &ent->dwork, 300 * HZ); + goto out; + } remove_cache_mr_locked(ent); queue_adjust_cache_locked(ent); } @@ -625,6 +627,7 @@ static void mlx5_mr_cache_free(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr) { struct mlx5_cache_ent *ent = mr->cache_ent; + WRITE_ONCE(dev->cache.last_add, jiffies); spin_lock_irq(&ent->lock); list_add_tail(&mr->list, &ent->head); ent->available_mrs++; diff --git a/drivers/infiniband/sw/rdmavt/qp.c b/drivers/infiniband/sw/rdmavt/qp.c index ae50b56e8913..8ef112f883a7 100644 --- a/drivers/infiniband/sw/rdmavt/qp.c +++ b/drivers/infiniband/sw/rdmavt/qp.c @@ -3190,7 +3190,11 @@ serr_no_r_lock: spin_lock_irqsave(&sqp->s_lock, flags); rvt_send_complete(sqp, wqe, send_status); if (sqp->ibqp.qp_type == IB_QPT_RC) { - int lastwqe = rvt_error_qp(sqp, IB_WC_WR_FLUSH_ERR); + int lastwqe; + + spin_lock(&sqp->r_lock); + lastwqe = rvt_error_qp(sqp, IB_WC_WR_FLUSH_ERR); + spin_unlock(&sqp->r_lock); sqp->s_flags &= ~RVT_S_BUSY; spin_unlock_irqrestore(&sqp->s_lock, flags); diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c index df5c62ecf942..2200e3c5d506 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -5010,7 +5010,7 @@ static void quirk_igfx_skip_te_disable(struct pci_dev *dev) ver = (dev->device >> 8) & 0xff; if (ver != 0x45 && ver != 0x46 && ver != 0x4c && ver != 0x4e && ver != 0x8a && ver != 0x98 && - ver != 0x9a) + ver != 0x9a && ver != 0xa7) return; if (risky_device(dev)) diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c index 4aab631ef517..d9cf2820c02e 100644 --- a/drivers/iommu/omap-iommu.c +++ b/drivers/iommu/omap-iommu.c @@ -1661,7 +1661,7 @@ static struct iommu_device *omap_iommu_probe_device(struct device *dev) num_iommus = of_property_count_elems_of_size(dev->of_node, "iommus", sizeof(phandle)); if (num_iommus < 0) - return 0; + return ERR_PTR(-ENODEV); arch_data = kcalloc(num_iommus + 1, sizeof(*arch_data), GFP_KERNEL); if (!arch_data) diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 680d2fcf2686..15edb9a6fcae 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -433,6 +433,7 @@ config QCOM_PDC config QCOM_MPM tristate "QCOM MPM" depends on ARCH_QCOM + depends on MAILBOX select IRQ_DOMAIN_HIERARCHY help MSM Power Manager driver to manage and configure wakeup diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index cd772973114a..a0fc764ec9dc 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -3011,18 +3011,12 @@ static int __init allocate_lpi_tables(void) return 0; } -static u64 its_clear_vpend_valid(void __iomem *vlpi_base, u64 clr, u64 set) +static u64 read_vpend_dirty_clear(void __iomem *vlpi_base) { u32 count = 1000000; /* 1s! */ bool clean; u64 val; - val = gicr_read_vpendbaser(vlpi_base + GICR_VPENDBASER); - val &= ~GICR_VPENDBASER_Valid; - val &= ~clr; - val |= set; - gicr_write_vpendbaser(val, vlpi_base + GICR_VPENDBASER); - do { val = gicr_read_vpendbaser(vlpi_base + GICR_VPENDBASER); clean = !(val & GICR_VPENDBASER_Dirty); @@ -3033,10 +3027,26 @@ static u64 its_clear_vpend_valid(void __iomem *vlpi_base, u64 clr, u64 set) } } while (!clean && count); - if (unlikely(val & GICR_VPENDBASER_Dirty)) { + if (unlikely(!clean)) pr_err_ratelimited("ITS virtual pending table not cleaning\n"); + + return val; +} + +static u64 its_clear_vpend_valid(void __iomem *vlpi_base, u64 clr, u64 set) +{ + u64 val; + + /* Make sure we wait until the RD is done with the initial scan */ + val = read_vpend_dirty_clear(vlpi_base); + val &= ~GICR_VPENDBASER_Valid; + val &= ~clr; + val |= set; + gicr_write_vpendbaser(val, vlpi_base + GICR_VPENDBASER); + + val = read_vpend_dirty_clear(vlpi_base); + if (unlikely(val & GICR_VPENDBASER_Dirty)) val |= GICR_VPENDBASER_PendingLast; - } return val; } diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 0efe1a9a9f3b..b252d5534547 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -206,11 +206,11 @@ static inline void __iomem *gic_dist_base(struct irq_data *d) } } -static void gic_do_wait_for_rwp(void __iomem *base) +static void gic_do_wait_for_rwp(void __iomem *base, u32 bit) { u32 count = 1000000; /* 1s! */ - while (readl_relaxed(base + GICD_CTLR) & GICD_CTLR_RWP) { + while (readl_relaxed(base + GICD_CTLR) & bit) { count--; if (!count) { pr_err_ratelimited("RWP timeout, gone fishing\n"); @@ -224,13 +224,13 @@ static void gic_do_wait_for_rwp(void __iomem *base) /* Wait for completion of a distributor change */ static void gic_dist_wait_for_rwp(void) { - gic_do_wait_for_rwp(gic_data.dist_base); + gic_do_wait_for_rwp(gic_data.dist_base, GICD_CTLR_RWP); } /* Wait for completion of a redistributor change */ static void gic_redist_wait_for_rwp(void) { - gic_do_wait_for_rwp(gic_data_rdist_rd_base()); + gic_do_wait_for_rwp(gic_data_rdist_rd_base(), GICR_CTLR_RWP); } #ifdef CONFIG_ARM64 @@ -1466,6 +1466,12 @@ static int gic_irq_domain_translate(struct irq_domain *d, if(fwspec->param_count != 2) return -EINVAL; + if (fwspec->param[0] < 16) { + pr_err(FW_BUG "Illegal GSI%d translation request\n", + fwspec->param[0]); + return -EINVAL; + } + *hwirq = fwspec->param[0]; *type = fwspec->param[1]; diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 58ba835bee1f..09c710ecc387 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -1123,6 +1123,12 @@ static int gic_irq_domain_translate(struct irq_domain *d, if(fwspec->param_count != 2) return -EINVAL; + if (fwspec->param[0] < 16) { + pr_err(FW_BUG "Illegal GSI%d translation request\n", + fwspec->param[0]); + return -EINVAL; + } + *hwirq = fwspec->param[0]; *type = fwspec->param[1]; diff --git a/drivers/irqchip/irq-qcom-mpm.c b/drivers/irqchip/irq-qcom-mpm.c index eea5a753618c..d30614661eea 100644 --- a/drivers/irqchip/irq-qcom-mpm.c +++ b/drivers/irqchip/irq-qcom-mpm.c @@ -375,7 +375,7 @@ static int qcom_mpm_init(struct device_node *np, struct device_node *parent) raw_spin_lock_init(&priv->lock); priv->base = devm_platform_ioremap_resource(pdev, 0); - if (!priv->base) + if (IS_ERR(priv->base)) return PTR_ERR(priv->base); for (i = 0; i < priv->reg_stride; i++) { diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index e90adfa57950..9b3ba2df71c7 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -6658,13 +6658,13 @@ static int mpt_summary_proc_show(struct seq_file *m, void *v) static int mpt_version_proc_show(struct seq_file *m, void *v) { u8 cb_idx; - int scsi, fc, sas, lan, ctl, targ, dmp; + int scsi, fc, sas, lan, ctl, targ; char *drvname; seq_printf(m, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON); seq_printf(m, " Fusion MPT base driver\n"); - scsi = fc = sas = lan = ctl = targ = dmp = 0; + scsi = fc = sas = lan = ctl = targ = 0; for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { drvname = NULL; if (MptCallbacks[cb_idx]) { diff --git a/drivers/misc/habanalabs/common/memory.c b/drivers/misc/habanalabs/common/memory.c index e008d82e4ba3..a13506dd8119 100644 --- a/drivers/misc/habanalabs/common/memory.c +++ b/drivers/misc/habanalabs/common/memory.c @@ -111,10 +111,10 @@ static int alloc_device_memory(struct hl_ctx *ctx, struct hl_mem_in *args, if (contiguous) { if (is_power_of_2(page_size)) - paddr = (u64) (uintptr_t) gen_pool_dma_alloc_align(vm->dram_pg_pool, - total_size, NULL, page_size); + paddr = (uintptr_t) gen_pool_dma_alloc_align(vm->dram_pg_pool, + total_size, NULL, page_size); else - paddr = (u64) (uintptr_t) gen_pool_alloc(vm->dram_pg_pool, total_size); + paddr = gen_pool_alloc(vm->dram_pg_pool, total_size); if (!paddr) { dev_err(hdev->dev, "failed to allocate %llu contiguous pages with total size of %llu\n", @@ -150,12 +150,12 @@ static int alloc_device_memory(struct hl_ctx *ctx, struct hl_mem_in *args, for (i = 0 ; i < num_pgs ; i++) { if (is_power_of_2(page_size)) phys_pg_pack->pages[i] = - (u64) gen_pool_dma_alloc_align(vm->dram_pg_pool, - page_size, NULL, - page_size); + (uintptr_t)gen_pool_dma_alloc_align(vm->dram_pg_pool, + page_size, NULL, + page_size); else - phys_pg_pack->pages[i] = (u64) gen_pool_alloc(vm->dram_pg_pool, - page_size); + phys_pg_pack->pages[i] = gen_pool_alloc(vm->dram_pg_pool, + page_size); if (!phys_pg_pack->pages[i]) { dev_err(hdev->dev, "Failed to allocate device memory (out of memory)\n"); diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 4e67c1403cc9..506dc900f5c7 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -993,7 +993,7 @@ static int mmc_blk_reset(struct mmc_blk_data *md, struct mmc_host *host, return -EEXIST; md->reset_done |= type; - err = mmc_hw_reset(host); + err = mmc_hw_reset(host->card); /* Ensure we switch back to the correct partition */ if (err) { struct mmc_blk_data *main_md = @@ -1880,6 +1880,31 @@ static inline bool mmc_blk_rq_error(struct mmc_blk_request *brq) brq->data.error || brq->cmd.resp[0] & CMD_ERRORS; } +static int mmc_spi_err_check(struct mmc_card *card) +{ + u32 status = 0; + int err; + + /* + * SPI does not have a TRAN state we have to wait on, instead the + * card is ready again when it no longer holds the line LOW. + * We still have to ensure two things here before we know the write + * was successful: + * 1. The card has not disconnected during busy and we actually read our + * own pull-up, thinking it was still connected, so ensure it + * still responds. + * 2. Check for any error bits, in particular R1_SPI_IDLE to catch a + * just reconnected card after being disconnected during busy. + */ + err = __mmc_send_status(card, &status, 0); + if (err) + return err; + /* All R1 and R2 bits of SPI are errors in our case */ + if (status) + return -EIO; + return 0; +} + static int mmc_blk_busy_cb(void *cb_data, bool *busy) { struct mmc_blk_busy_data *data = cb_data; @@ -1903,9 +1928,16 @@ static int mmc_blk_card_busy(struct mmc_card *card, struct request *req) struct mmc_blk_busy_data cb_data; int err; - if (mmc_host_is_spi(card->host) || rq_data_dir(req) == READ) + if (rq_data_dir(req) == READ) return 0; + if (mmc_host_is_spi(card->host)) { + err = mmc_spi_err_check(card); + if (err) + mqrq->brq.data.bytes_xfered = 0; + return err; + } + cb_data.card = card; cb_data.status = 0; err = __mmc_poll_for_busy(card->host, 0, MMC_BLK_TIMEOUT_MS, @@ -2350,6 +2382,8 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, struct mmc_blk_data *md; int devidx, ret; char cap_str[10]; + bool cache_enabled = false; + bool fua_enabled = false; devidx = ida_simple_get(&mmc_blk_ida, 0, max_devices, GFP_KERNEL); if (devidx < 0) { @@ -2429,13 +2463,17 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, md->flags |= MMC_BLK_CMD23; } - if (mmc_card_mmc(card) && - md->flags & MMC_BLK_CMD23 && + if (md->flags & MMC_BLK_CMD23 && ((card->ext_csd.rel_param & EXT_CSD_WR_REL_PARAM_EN) || card->ext_csd.rel_sectors)) { md->flags |= MMC_BLK_REL_WR; - blk_queue_write_cache(md->queue.queue, true, true); + fua_enabled = true; + cache_enabled = true; } + if (mmc_cache_enabled(card->host)) + cache_enabled = true; + + blk_queue_write_cache(md->queue.queue, cache_enabled, fua_enabled); string_get_size((u64)size, 512, STRING_UNITS_2, cap_str, sizeof(cap_str)); diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 368f10405e13..c6ae16d40766 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1995,7 +1995,7 @@ static void mmc_hw_reset_for_init(struct mmc_host *host) /** * mmc_hw_reset - reset the card in hardware - * @host: MMC host to which the card is attached + * @card: card to be reset * * Hard reset the card. This function is only for upper layers, like the * block layer or card drivers. You cannot use it in host drivers (struct @@ -2003,8 +2003,9 @@ static void mmc_hw_reset_for_init(struct mmc_host *host) * * Return: 0 on success, -errno on failure */ -int mmc_hw_reset(struct mmc_host *host) +int mmc_hw_reset(struct mmc_card *card) { + struct mmc_host *host = card->host; int ret; ret = host->bus_ops->hw_reset(host); diff --git a/drivers/mmc/core/mmc_test.c b/drivers/mmc/core/mmc_test.c index e6a2fd2c6d5c..8d9bceeff986 100644 --- a/drivers/mmc/core/mmc_test.c +++ b/drivers/mmc/core/mmc_test.c @@ -2325,10 +2325,9 @@ static int mmc_test_profile_sglen_r_nonblock_perf(struct mmc_test_card *test) static int mmc_test_reset(struct mmc_test_card *test) { struct mmc_card *card = test->card; - struct mmc_host *host = card->host; int err; - err = mmc_hw_reset(host); + err = mmc_hw_reset(card); if (!err) { /* * Reset will re-enable the card's command queue, but tests diff --git a/drivers/mmc/host/mmci_stm32_sdmmc.c b/drivers/mmc/host/mmci_stm32_sdmmc.c index 9c13f2c31365..4566d7fc9055 100644 --- a/drivers/mmc/host/mmci_stm32_sdmmc.c +++ b/drivers/mmc/host/mmci_stm32_sdmmc.c @@ -62,8 +62,8 @@ static int sdmmc_idma_validate_data(struct mmci_host *host, * excepted the last element which has no constraint on idmasize */ for_each_sg(data->sg, sg, data->sg_len - 1, i) { - if (!IS_ALIGNED(data->sg->offset, sizeof(u32)) || - !IS_ALIGNED(data->sg->length, SDMMC_IDMA_BURST)) { + if (!IS_ALIGNED(sg->offset, sizeof(u32)) || + !IS_ALIGNED(sg->length, SDMMC_IDMA_BURST)) { dev_err(mmc_dev(host->mmc), "unaligned scatterlist: ofst:%x length:%d\n", data->sg->offset, data->sg->length); @@ -71,7 +71,7 @@ static int sdmmc_idma_validate_data(struct mmci_host *host, } } - if (!IS_ALIGNED(data->sg->offset, sizeof(u32))) { + if (!IS_ALIGNED(sg->offset, sizeof(u32))) { dev_err(mmc_dev(host->mmc), "unaligned last scatterlist: ofst:%x length:%d\n", data->sg->offset, data->sg->length); diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index 2797a9c0f17d..ddb5ca2f559e 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -144,9 +144,9 @@ static unsigned int renesas_sdhi_clk_update(struct tmio_mmc_host *host, return clk_get_rate(priv->clk); if (priv->clkh) { + /* HS400 with 4TAP needs different clock settings */ bool use_4tap = priv->quirks && priv->quirks->hs400_4taps; - bool need_slow_clkh = (host->mmc->ios.timing == MMC_TIMING_UHS_SDR104) || - (host->mmc->ios.timing == MMC_TIMING_MMC_HS400); + bool need_slow_clkh = host->mmc->ios.timing == MMC_TIMING_MMC_HS400; clkh_shift = use_4tap && need_slow_clkh ? 1 : 2; ref_clk = priv->clkh; } @@ -396,10 +396,10 @@ static void renesas_sdhi_hs400_complete(struct mmc_host *mmc) SH_MOBILE_SDHI_SCC_TMPPORT2_HS400OSEL) | sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2)); - /* Set the sampling clock selection range of HS400 mode */ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL, SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN | - 0x4 << SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT); + sd_scc_read32(host, priv, + SH_MOBILE_SDHI_SCC_DTCNTL)); /* Avoid bad TAP */ if (bad_taps & BIT(priv->tap_set)) { diff --git a/drivers/mmc/host/sdhci-xenon.c b/drivers/mmc/host/sdhci-xenon.c index 666cee4c7f7c..08e838400b52 100644 --- a/drivers/mmc/host/sdhci-xenon.c +++ b/drivers/mmc/host/sdhci-xenon.c @@ -241,16 +241,6 @@ static void xenon_voltage_switch(struct sdhci_host *host) { /* Wait for 5ms after set 1.8V signal enable bit */ usleep_range(5000, 5500); - - /* - * For some reason the controller's Host Control2 register reports - * the bit representing 1.8V signaling as 0 when read after it was - * written as 1. Subsequent read reports 1. - * - * Since this may cause some issues, do an empty read of the Host - * Control2 register here to circumvent this. - */ - sdhci_readw(host, SDHCI_HOST_CONTROL2); } static unsigned int xenon_get_max_clock(struct sdhci_host *host) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 1c28495875cf..874fad0a5cf8 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -3253,6 +3253,7 @@ static int bnxt_alloc_tx_rings(struct bnxt *bp) } qidx = bp->tc_to_qidx[j]; ring->queue_id = bp->q_info[qidx].queue_id; + spin_lock_init(&txr->xdp_tx_lock); if (i < bp->tx_nr_rings_xdp) continue; if (i % bp->tx_nr_rings_per_tc == (bp->tx_nr_rings_per_tc - 1)) @@ -10338,6 +10339,12 @@ static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init) if (irq_re_init) udp_tunnel_nic_reset_ntf(bp->dev); + if (bp->tx_nr_rings_xdp < num_possible_cpus()) { + if (!static_key_enabled(&bnxt_xdp_locking_key)) + static_branch_enable(&bnxt_xdp_locking_key); + } else if (static_key_enabled(&bnxt_xdp_locking_key)) { + static_branch_disable(&bnxt_xdp_locking_key); + } set_bit(BNXT_STATE_OPEN, &bp->state); bnxt_enable_int(bp); /* Enable TX queues */ diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 61aa3e8c5952..98453a78cbd0 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -593,7 +593,8 @@ struct nqe_cn { #define BNXT_MAX_MTU 9500 #define BNXT_MAX_PAGE_MODE_MTU \ ((unsigned int)PAGE_SIZE - VLAN_ETH_HLEN - NET_IP_ALIGN - \ - XDP_PACKET_HEADROOM) + XDP_PACKET_HEADROOM - \ + SKB_DATA_ALIGN((unsigned int)sizeof(struct skb_shared_info))) #define BNXT_MIN_PKT_SIZE 52 @@ -800,6 +801,8 @@ struct bnxt_tx_ring_info { u32 dev_state; struct bnxt_ring_struct tx_ring_struct; + /* Synchronize simultaneous xdp_xmit on same ring */ + spinlock_t xdp_tx_lock; }; #define BNXT_LEGACY_COAL_CMPL_PARAMS \ diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c index 52fad0fdeacf..03b1d6c04504 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c @@ -20,6 +20,8 @@ #include "bnxt.h" #include "bnxt_xdp.h" +DEFINE_STATIC_KEY_FALSE(bnxt_xdp_locking_key); + struct bnxt_sw_tx_bd *bnxt_xmit_bd(struct bnxt *bp, struct bnxt_tx_ring_info *txr, dma_addr_t mapping, u32 len) @@ -227,11 +229,16 @@ int bnxt_xdp_xmit(struct net_device *dev, int num_frames, ring = smp_processor_id() % bp->tx_nr_rings_xdp; txr = &bp->tx_ring[ring]; + if (READ_ONCE(txr->dev_state) == BNXT_DEV_STATE_CLOSING) + return -EINVAL; + + if (static_branch_unlikely(&bnxt_xdp_locking_key)) + spin_lock(&txr->xdp_tx_lock); + for (i = 0; i < num_frames; i++) { struct xdp_frame *xdp = frames[i]; - if (!txr || !bnxt_tx_avail(bp, txr) || - !(bp->bnapi[ring]->flags & BNXT_NAPI_FLAG_XDP)) + if (!bnxt_tx_avail(bp, txr)) break; mapping = dma_map_single(&pdev->dev, xdp->data, xdp->len, @@ -250,6 +257,9 @@ int bnxt_xdp_xmit(struct net_device *dev, int num_frames, bnxt_db_write(bp, &txr->tx_db, txr->tx_prod); } + if (static_branch_unlikely(&bnxt_xdp_locking_key)) + spin_unlock(&txr->xdp_tx_lock); + return nxmit; } diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.h index 0df40c3beb05..067bb5e821f5 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.h @@ -10,6 +10,8 @@ #ifndef BNXT_XDP_H #define BNXT_XDP_H +DECLARE_STATIC_KEY_FALSE(bnxt_xdp_locking_key); + struct bnxt_sw_tx_bd *bnxt_xmit_bd(struct bnxt *bp, struct bnxt_tx_ring_info *txr, dma_addr_t mapping, u32 len); diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ptp.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ptp.c index 5f5f8c53c4a0..c8cb541572ff 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ptp.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ptp.c @@ -167,7 +167,7 @@ static int dpaa2_ptp_probe(struct fsl_mc_device *mc_dev) base = of_iomap(node, 0); if (!base) { err = -ENOMEM; - goto err_close; + goto err_put; } err = fsl_mc_allocate_irqs(mc_dev); @@ -210,6 +210,8 @@ err_free_mc_irq: fsl_mc_free_irqs(mc_dev); err_unmap: iounmap(base); +err_put: + of_node_put(node); err_close: dprtc_close(mc_dev->mc_io, 0, mc_dev->mc_handle); err_free_mcp: diff --git a/drivers/net/ethernet/fungible/funcore/fun_dev.c b/drivers/net/ethernet/fungible/funcore/fun_dev.c index 5d7aef73df61..fb5120d90f26 100644 --- a/drivers/net/ethernet/fungible/funcore/fun_dev.c +++ b/drivers/net/ethernet/fungible/funcore/fun_dev.c @@ -586,8 +586,8 @@ static int fun_get_dev_limits(struct fun_dev *fdev) /* Calculate the max QID based on SQ/CQ/doorbell counts. * SQ/CQ doorbells alternate. */ - num_dbs = (pci_resource_len(pdev, 0) - NVME_REG_DBS) / - (fdev->db_stride * 4); + num_dbs = (pci_resource_len(pdev, 0) - NVME_REG_DBS) >> + (2 + NVME_CAP_STRIDE(fdev->cap_reg)); fdev->max_qid = min3(cq_count, sq_count, num_dbs / 2) - 1; fdev->kern_end_qid = fdev->max_qid + 1; return 0; diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index d4f1874df7d0..8ed3c9ab7ff7 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -301,7 +301,6 @@ enum ice_vsi_state { ICE_VSI_NETDEV_REGISTERED, ICE_VSI_UMAC_FLTR_CHANGED, ICE_VSI_MMAC_FLTR_CHANGED, - ICE_VSI_VLAN_FLTR_CHANGED, ICE_VSI_PROMISC_CHANGED, ICE_VSI_STATE_NBITS /* must be last */ }; @@ -672,7 +671,7 @@ static inline struct ice_pf *ice_netdev_to_pf(struct net_device *netdev) static inline bool ice_is_xdp_ena_vsi(struct ice_vsi *vsi) { - return !!vsi->xdp_prog; + return !!READ_ONCE(vsi->xdp_prog); } static inline void ice_set_ring_xdp(struct ice_tx_ring *ring) diff --git a/drivers/net/ethernet/intel/ice/ice_fltr.c b/drivers/net/ethernet/intel/ice/ice_fltr.c index af57eb114966..85a94483c2ed 100644 --- a/drivers/net/ethernet/intel/ice/ice_fltr.c +++ b/drivers/net/ethernet/intel/ice/ice_fltr.c @@ -58,7 +58,16 @@ int ice_fltr_set_vlan_vsi_promisc(struct ice_hw *hw, struct ice_vsi *vsi, u8 promisc_mask) { - return ice_set_vlan_vsi_promisc(hw, vsi->idx, promisc_mask, false); + struct ice_pf *pf = hw->back; + int result; + + result = ice_set_vlan_vsi_promisc(hw, vsi->idx, promisc_mask, false); + if (result) + dev_err(ice_pf_to_dev(pf), + "Error setting promisc mode on VSI %i (rc=%d)\n", + vsi->vsi_num, result); + + return result; } /** @@ -73,7 +82,16 @@ int ice_fltr_clear_vlan_vsi_promisc(struct ice_hw *hw, struct ice_vsi *vsi, u8 promisc_mask) { - return ice_set_vlan_vsi_promisc(hw, vsi->idx, promisc_mask, true); + struct ice_pf *pf = hw->back; + int result; + + result = ice_set_vlan_vsi_promisc(hw, vsi->idx, promisc_mask, true); + if (result) + dev_err(ice_pf_to_dev(pf), + "Error clearing promisc mode on VSI %i (rc=%d)\n", + vsi->vsi_num, result); + + return result; } /** @@ -87,7 +105,16 @@ int ice_fltr_clear_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask, u16 vid) { - return ice_clear_vsi_promisc(hw, vsi_handle, promisc_mask, vid); + struct ice_pf *pf = hw->back; + int result; + + result = ice_clear_vsi_promisc(hw, vsi_handle, promisc_mask, vid); + if (result) + dev_err(ice_pf_to_dev(pf), + "Error clearing promisc mode on VSI %i for VID %u (rc=%d)\n", + ice_get_hw_vsi_num(hw, vsi_handle), vid, result); + + return result; } /** @@ -101,7 +128,16 @@ int ice_fltr_set_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask, u16 vid) { - return ice_set_vsi_promisc(hw, vsi_handle, promisc_mask, vid); + struct ice_pf *pf = hw->back; + int result; + + result = ice_set_vsi_promisc(hw, vsi_handle, promisc_mask, vid); + if (result) + dev_err(ice_pf_to_dev(pf), + "Error setting promisc mode on VSI %i for VID %u (rc=%d)\n", + ice_get_hw_vsi_num(hw, vsi_handle), vid, result); + + return result; } /** diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index b897926f817d..2774cbd5b12a 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -1480,6 +1480,7 @@ static int ice_vsi_alloc_rings(struct ice_vsi *vsi) ring->tx_tstamps = &pf->ptp.port.tx; ring->dev = dev; ring->count = vsi->num_tx_desc; + ring->txq_teid = ICE_INVAL_TEID; if (dvm_ena) ring->flags |= ICE_TX_FLAGS_RING_VLAN_L2TAG2; else @@ -2983,6 +2984,8 @@ int ice_vsi_release(struct ice_vsi *vsi) } } + if (ice_is_vsi_dflt_vsi(pf->first_sw, vsi)) + ice_clear_dflt_vsi(pf->first_sw); ice_fltr_remove_all(vsi); ice_rm_vsi_lan_cfg(vsi->port_info, vsi->idx); err = ice_rm_vsi_rdma_cfg(vsi->port_info, vsi->idx); diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index b588d7995631..d768925785ca 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -243,8 +243,7 @@ static int ice_add_mac_to_unsync_list(struct net_device *netdev, const u8 *addr) static bool ice_vsi_fltr_changed(struct ice_vsi *vsi) { return test_bit(ICE_VSI_UMAC_FLTR_CHANGED, vsi->state) || - test_bit(ICE_VSI_MMAC_FLTR_CHANGED, vsi->state) || - test_bit(ICE_VSI_VLAN_FLTR_CHANGED, vsi->state); + test_bit(ICE_VSI_MMAC_FLTR_CHANGED, vsi->state); } /** @@ -260,10 +259,15 @@ static int ice_set_promisc(struct ice_vsi *vsi, u8 promisc_m) if (vsi->type != ICE_VSI_PF) return 0; - if (ice_vsi_has_non_zero_vlans(vsi)) - status = ice_fltr_set_vlan_vsi_promisc(&vsi->back->hw, vsi, promisc_m); - else - status = ice_fltr_set_vsi_promisc(&vsi->back->hw, vsi->idx, promisc_m, 0); + if (ice_vsi_has_non_zero_vlans(vsi)) { + promisc_m |= (ICE_PROMISC_VLAN_RX | ICE_PROMISC_VLAN_TX); + status = ice_fltr_set_vlan_vsi_promisc(&vsi->back->hw, vsi, + promisc_m); + } else { + status = ice_fltr_set_vsi_promisc(&vsi->back->hw, vsi->idx, + promisc_m, 0); + } + return status; } @@ -280,10 +284,15 @@ static int ice_clear_promisc(struct ice_vsi *vsi, u8 promisc_m) if (vsi->type != ICE_VSI_PF) return 0; - if (ice_vsi_has_non_zero_vlans(vsi)) - status = ice_fltr_clear_vlan_vsi_promisc(&vsi->back->hw, vsi, promisc_m); - else - status = ice_fltr_clear_vsi_promisc(&vsi->back->hw, vsi->idx, promisc_m, 0); + if (ice_vsi_has_non_zero_vlans(vsi)) { + promisc_m |= (ICE_PROMISC_VLAN_RX | ICE_PROMISC_VLAN_TX); + status = ice_fltr_clear_vlan_vsi_promisc(&vsi->back->hw, vsi, + promisc_m); + } else { + status = ice_fltr_clear_vsi_promisc(&vsi->back->hw, vsi->idx, + promisc_m, 0); + } + return status; } @@ -302,7 +311,6 @@ static int ice_vsi_sync_fltr(struct ice_vsi *vsi) struct ice_pf *pf = vsi->back; struct ice_hw *hw = &pf->hw; u32 changed_flags = 0; - u8 promisc_m; int err; if (!vsi->netdev) @@ -320,7 +328,6 @@ static int ice_vsi_sync_fltr(struct ice_vsi *vsi) if (ice_vsi_fltr_changed(vsi)) { clear_bit(ICE_VSI_UMAC_FLTR_CHANGED, vsi->state); clear_bit(ICE_VSI_MMAC_FLTR_CHANGED, vsi->state); - clear_bit(ICE_VSI_VLAN_FLTR_CHANGED, vsi->state); /* grab the netdev's addr_list_lock */ netif_addr_lock_bh(netdev); @@ -369,29 +376,15 @@ static int ice_vsi_sync_fltr(struct ice_vsi *vsi) /* check for changes in promiscuous modes */ if (changed_flags & IFF_ALLMULTI) { if (vsi->current_netdev_flags & IFF_ALLMULTI) { - if (ice_vsi_has_non_zero_vlans(vsi)) - promisc_m = ICE_MCAST_VLAN_PROMISC_BITS; - else - promisc_m = ICE_MCAST_PROMISC_BITS; - - err = ice_set_promisc(vsi, promisc_m); + err = ice_set_promisc(vsi, ICE_MCAST_PROMISC_BITS); if (err) { - netdev_err(netdev, "Error setting Multicast promiscuous mode on VSI %i\n", - vsi->vsi_num); vsi->current_netdev_flags &= ~IFF_ALLMULTI; goto out_promisc; } } else { /* !(vsi->current_netdev_flags & IFF_ALLMULTI) */ - if (ice_vsi_has_non_zero_vlans(vsi)) - promisc_m = ICE_MCAST_VLAN_PROMISC_BITS; - else - promisc_m = ICE_MCAST_PROMISC_BITS; - - err = ice_clear_promisc(vsi, promisc_m); + err = ice_clear_promisc(vsi, ICE_MCAST_PROMISC_BITS); if (err) { - netdev_err(netdev, "Error clearing Multicast promiscuous mode on VSI %i\n", - vsi->vsi_num); vsi->current_netdev_flags |= IFF_ALLMULTI; goto out_promisc; } @@ -2569,7 +2562,7 @@ static int ice_xdp_alloc_setup_rings(struct ice_vsi *vsi) spin_lock_init(&xdp_ring->tx_lock); for (j = 0; j < xdp_ring->count; j++) { tx_desc = ICE_TX_DESC(xdp_ring, j); - tx_desc->cmd_type_offset_bsz = cpu_to_le64(ICE_TX_DESC_DTYPE_DESC_DONE); + tx_desc->cmd_type_offset_bsz = 0; } } @@ -2765,8 +2758,10 @@ free_qmap: ice_for_each_xdp_txq(vsi, i) if (vsi->xdp_rings[i]) { - if (vsi->xdp_rings[i]->desc) + if (vsi->xdp_rings[i]->desc) { + synchronize_rcu(); ice_free_tx_ring(vsi->xdp_rings[i]); + } kfree_rcu(vsi->xdp_rings[i], rcu); vsi->xdp_rings[i] = NULL; } @@ -3488,6 +3483,20 @@ ice_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid) if (!vid) return 0; + while (test_and_set_bit(ICE_CFG_BUSY, vsi->state)) + usleep_range(1000, 2000); + + /* Add multicast promisc rule for the VLAN ID to be added if + * all-multicast is currently enabled. + */ + if (vsi->current_netdev_flags & IFF_ALLMULTI) { + ret = ice_fltr_set_vsi_promisc(&vsi->back->hw, vsi->idx, + ICE_MCAST_VLAN_PROMISC_BITS, + vid); + if (ret) + goto finish; + } + vlan_ops = ice_get_compat_vsi_vlan_ops(vsi); /* Add a switch rule for this VLAN ID so its corresponding VLAN tagged @@ -3495,8 +3504,23 @@ ice_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid) */ vlan = ICE_VLAN(be16_to_cpu(proto), vid, 0); ret = vlan_ops->add_vlan(vsi, &vlan); - if (!ret) - set_bit(ICE_VSI_VLAN_FLTR_CHANGED, vsi->state); + if (ret) + goto finish; + + /* If all-multicast is currently enabled and this VLAN ID is only one + * besides VLAN-0 we have to update look-up type of multicast promisc + * rule for VLAN-0 from ICE_SW_LKUP_PROMISC to ICE_SW_LKUP_PROMISC_VLAN. + */ + if ((vsi->current_netdev_flags & IFF_ALLMULTI) && + ice_vsi_num_non_zero_vlans(vsi) == 1) { + ice_fltr_clear_vsi_promisc(&vsi->back->hw, vsi->idx, + ICE_MCAST_PROMISC_BITS, 0); + ice_fltr_set_vsi_promisc(&vsi->back->hw, vsi->idx, + ICE_MCAST_VLAN_PROMISC_BITS, 0); + } + +finish: + clear_bit(ICE_CFG_BUSY, vsi->state); return ret; } @@ -3522,6 +3546,9 @@ ice_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid) if (!vid) return 0; + while (test_and_set_bit(ICE_CFG_BUSY, vsi->state)) + usleep_range(1000, 2000); + vlan_ops = ice_get_compat_vsi_vlan_ops(vsi); /* Make sure VLAN delete is successful before updating VLAN @@ -3530,10 +3557,33 @@ ice_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid) vlan = ICE_VLAN(be16_to_cpu(proto), vid, 0); ret = vlan_ops->del_vlan(vsi, &vlan); if (ret) - return ret; + goto finish; - set_bit(ICE_VSI_VLAN_FLTR_CHANGED, vsi->state); - return 0; + /* Remove multicast promisc rule for the removed VLAN ID if + * all-multicast is enabled. + */ + if (vsi->current_netdev_flags & IFF_ALLMULTI) + ice_fltr_clear_vsi_promisc(&vsi->back->hw, vsi->idx, + ICE_MCAST_VLAN_PROMISC_BITS, vid); + + if (!ice_vsi_has_non_zero_vlans(vsi)) { + /* Update look-up type of multicast promisc rule for VLAN 0 + * from ICE_SW_LKUP_PROMISC_VLAN to ICE_SW_LKUP_PROMISC when + * all-multicast is enabled and VLAN 0 is the only VLAN rule. + */ + if (vsi->current_netdev_flags & IFF_ALLMULTI) { + ice_fltr_clear_vsi_promisc(&vsi->back->hw, vsi->idx, + ICE_MCAST_VLAN_PROMISC_BITS, + 0); + ice_fltr_set_vsi_promisc(&vsi->back->hw, vsi->idx, + ICE_MCAST_PROMISC_BITS, 0); + } + } + +finish: + clear_bit(ICE_CFG_BUSY, vsi->state); + + return ret; } /** @@ -5475,16 +5525,19 @@ static int ice_set_mac_address(struct net_device *netdev, void *pi) /* Add filter for new MAC. If filter exists, return success */ err = ice_fltr_add_mac(vsi, mac, ICE_FWD_TO_VSI); - if (err == -EEXIST) + if (err == -EEXIST) { /* Although this MAC filter is already present in hardware it's * possible in some cases (e.g. bonding) that dev_addr was * modified outside of the driver and needs to be restored back * to this value. */ netdev_dbg(netdev, "filter for MAC %pM already exists\n", mac); - else if (err) + + return 0; + } else if (err) { /* error if the new filter addition failed */ err = -EADDRNOTAVAIL; + } err_update_filters: if (err) { diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl.c b/drivers/net/ethernet/intel/ice/ice_virtchnl.c index 3f1a63815bac..69ff4b929772 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl.c +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl.c @@ -1358,9 +1358,9 @@ static int ice_vc_dis_qs_msg(struct ice_vf *vf, u8 *msg) goto error_param; } - /* Skip queue if not enabled */ if (!test_bit(vf_q_id, vf->txq_ena)) - continue; + dev_dbg(ice_pf_to_dev(vsi->back), "Queue %u on VSI %u is not enabled, but stopping it anyway\n", + vf_q_id, vsi->vsi_num); ice_fill_txq_meta(vsi, ring, &txq_meta); diff --git a/drivers/net/ethernet/intel/ice/ice_xsk.c b/drivers/net/ethernet/intel/ice/ice_xsk.c index dfbcaf08520e..866ee4df9671 100644 --- a/drivers/net/ethernet/intel/ice/ice_xsk.c +++ b/drivers/net/ethernet/intel/ice/ice_xsk.c @@ -41,8 +41,10 @@ static void ice_qp_reset_stats(struct ice_vsi *vsi, u16 q_idx) static void ice_qp_clean_rings(struct ice_vsi *vsi, u16 q_idx) { ice_clean_tx_ring(vsi->tx_rings[q_idx]); - if (ice_is_xdp_ena_vsi(vsi)) + if (ice_is_xdp_ena_vsi(vsi)) { + synchronize_rcu(); ice_clean_tx_ring(vsi->xdp_rings[q_idx]); + } ice_clean_rx_ring(vsi->rx_rings[q_idx]); } @@ -918,7 +920,7 @@ ice_xsk_wakeup(struct net_device *netdev, u32 queue_id, struct ice_vsi *vsi = np->vsi; struct ice_tx_ring *ring; - if (test_bit(ICE_DOWN, vsi->state)) + if (test_bit(ICE_VSI_DOWN, vsi->state)) return -ENETDOWN; if (!ice_is_xdp_ena_vsi(vsi)) diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c index 5f9ab1842d49..c18801490649 100644 --- a/drivers/net/ethernet/marvell/mv643xx_eth.c +++ b/drivers/net/ethernet/marvell/mv643xx_eth.c @@ -2751,7 +2751,7 @@ static int mv643xx_eth_shared_of_add_port(struct platform_device *pdev, } ret = of_get_mac_address(pnp, ppd.mac_addr); - if (ret) + if (ret == -EPROBE_DEFER) return ret; mv643xx_eth_property(pnp, "tx-queue-size", ppd.tx_queue_size); diff --git a/drivers/net/ethernet/micrel/Kconfig b/drivers/net/ethernet/micrel/Kconfig index 93df3049cdc0..830363bafcce 100644 --- a/drivers/net/ethernet/micrel/Kconfig +++ b/drivers/net/ethernet/micrel/Kconfig @@ -28,6 +28,7 @@ config KS8842 config KS8851 tristate "Micrel KS8851 SPI" depends on SPI + depends on PTP_1588_CLOCK_OPTIONAL select MII select CRC32 select EEPROM_93CX6 @@ -39,6 +40,7 @@ config KS8851 config KS8851_MLL tristate "Micrel KS8851 MLL" depends on HAS_IOMEM + depends on PTP_1588_CLOCK_OPTIONAL select MII select CRC32 select EEPROM_93CX6 diff --git a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c index 50ac3ee2577a..21d2645885ce 100644 --- a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c +++ b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c @@ -2903,11 +2903,9 @@ static netdev_tx_t myri10ge_sw_tso(struct sk_buff *skb, status = myri10ge_xmit(curr, dev); if (status != 0) { dev_kfree_skb_any(curr); - if (segs != NULL) { - curr = segs; - segs = next; + skb_list_walk_safe(next, curr, next) { curr->next = NULL; - dev_kfree_skb_any(segs); + dev_kfree_skb_any(curr); } goto drop; } diff --git a/drivers/net/ethernet/qlogic/qed/qed_debug.c b/drivers/net/ethernet/qlogic/qed/qed_debug.c index e3edca187ddf..5250d1d1e49c 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_debug.c +++ b/drivers/net/ethernet/qlogic/qed/qed_debug.c @@ -489,7 +489,7 @@ struct split_type_defs { #define STATIC_DEBUG_LINE_DWORDS 9 -#define NUM_COMMON_GLOBAL_PARAMS 11 +#define NUM_COMMON_GLOBAL_PARAMS 10 #define MAX_RECURSION_DEPTH 10 diff --git a/drivers/net/ethernet/qlogic/qede/qede_fp.c b/drivers/net/ethernet/qlogic/qede/qede_fp.c index b242000a77fd..b7cc36589f59 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_fp.c +++ b/drivers/net/ethernet/qlogic/qede/qede_fp.c @@ -748,6 +748,9 @@ qede_build_skb(struct qede_rx_queue *rxq, buf = page_address(bd->data) + bd->page_offset; skb = build_skb(buf, rxq->rx_buf_seg_size); + if (unlikely(!skb)) + return NULL; + skb_reserve(skb, pad); skb_put(skb, len); diff --git a/drivers/net/ethernet/sfc/efx_channels.c b/drivers/net/ethernet/sfc/efx_channels.c index f9064532beb6..377df8b7f015 100644 --- a/drivers/net/ethernet/sfc/efx_channels.c +++ b/drivers/net/ethernet/sfc/efx_channels.c @@ -786,6 +786,85 @@ void efx_remove_channels(struct efx_nic *efx) kfree(efx->xdp_tx_queues); } +static int efx_set_xdp_tx_queue(struct efx_nic *efx, int xdp_queue_number, + struct efx_tx_queue *tx_queue) +{ + if (xdp_queue_number >= efx->xdp_tx_queue_count) + return -EINVAL; + + netif_dbg(efx, drv, efx->net_dev, + "Channel %u TXQ %u is XDP %u, HW %u\n", + tx_queue->channel->channel, tx_queue->label, + xdp_queue_number, tx_queue->queue); + efx->xdp_tx_queues[xdp_queue_number] = tx_queue; + return 0; +} + +static void efx_set_xdp_channels(struct efx_nic *efx) +{ + struct efx_tx_queue *tx_queue; + struct efx_channel *channel; + unsigned int next_queue = 0; + int xdp_queue_number = 0; + int rc; + + /* We need to mark which channels really have RX and TX + * queues, and adjust the TX queue numbers if we have separate + * RX-only and TX-only channels. + */ + efx_for_each_channel(channel, efx) { + if (channel->channel < efx->tx_channel_offset) + continue; + + if (efx_channel_is_xdp_tx(channel)) { + efx_for_each_channel_tx_queue(tx_queue, channel) { + tx_queue->queue = next_queue++; + rc = efx_set_xdp_tx_queue(efx, xdp_queue_number, + tx_queue); + if (rc == 0) + xdp_queue_number++; + } + } else { + efx_for_each_channel_tx_queue(tx_queue, channel) { + tx_queue->queue = next_queue++; + netif_dbg(efx, drv, efx->net_dev, + "Channel %u TXQ %u is HW %u\n", + channel->channel, tx_queue->label, + tx_queue->queue); + } + + /* If XDP is borrowing queues from net stack, it must + * use the queue with no csum offload, which is the + * first one of the channel + * (note: tx_queue_by_type is not initialized yet) + */ + if (efx->xdp_txq_queues_mode == + EFX_XDP_TX_QUEUES_BORROWED) { + tx_queue = &channel->tx_queue[0]; + rc = efx_set_xdp_tx_queue(efx, xdp_queue_number, + tx_queue); + if (rc == 0) + xdp_queue_number++; + } + } + } + WARN_ON(efx->xdp_txq_queues_mode == EFX_XDP_TX_QUEUES_DEDICATED && + xdp_queue_number != efx->xdp_tx_queue_count); + WARN_ON(efx->xdp_txq_queues_mode != EFX_XDP_TX_QUEUES_DEDICATED && + xdp_queue_number > efx->xdp_tx_queue_count); + + /* If we have more CPUs than assigned XDP TX queues, assign the already + * existing queues to the exceeding CPUs + */ + next_queue = 0; + while (xdp_queue_number < efx->xdp_tx_queue_count) { + tx_queue = efx->xdp_tx_queues[next_queue++]; + rc = efx_set_xdp_tx_queue(efx, xdp_queue_number, tx_queue); + if (rc == 0) + xdp_queue_number++; + } +} + int efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries) { struct efx_channel *other_channel[EFX_MAX_CHANNELS], *channel; @@ -857,6 +936,7 @@ int efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries) efx_init_napi_channel(efx->channel[i]); } + efx_set_xdp_channels(efx); out: /* Destroy unused channel structures */ for (i = 0; i < efx->n_channels; i++) { @@ -889,26 +969,9 @@ rollback: goto out; } -static inline int -efx_set_xdp_tx_queue(struct efx_nic *efx, int xdp_queue_number, - struct efx_tx_queue *tx_queue) -{ - if (xdp_queue_number >= efx->xdp_tx_queue_count) - return -EINVAL; - - netif_dbg(efx, drv, efx->net_dev, "Channel %u TXQ %u is XDP %u, HW %u\n", - tx_queue->channel->channel, tx_queue->label, - xdp_queue_number, tx_queue->queue); - efx->xdp_tx_queues[xdp_queue_number] = tx_queue; - return 0; -} - int efx_set_channels(struct efx_nic *efx) { - struct efx_tx_queue *tx_queue; struct efx_channel *channel; - unsigned int next_queue = 0; - int xdp_queue_number; int rc; efx->tx_channel_offset = @@ -926,61 +989,14 @@ int efx_set_channels(struct efx_nic *efx) return -ENOMEM; } - /* We need to mark which channels really have RX and TX - * queues, and adjust the TX queue numbers if we have separate - * RX-only and TX-only channels. - */ - xdp_queue_number = 0; efx_for_each_channel(channel, efx) { if (channel->channel < efx->n_rx_channels) channel->rx_queue.core_index = channel->channel; else channel->rx_queue.core_index = -1; - - if (channel->channel >= efx->tx_channel_offset) { - if (efx_channel_is_xdp_tx(channel)) { - efx_for_each_channel_tx_queue(tx_queue, channel) { - tx_queue->queue = next_queue++; - rc = efx_set_xdp_tx_queue(efx, xdp_queue_number, tx_queue); - if (rc == 0) - xdp_queue_number++; - } - } else { - efx_for_each_channel_tx_queue(tx_queue, channel) { - tx_queue->queue = next_queue++; - netif_dbg(efx, drv, efx->net_dev, "Channel %u TXQ %u is HW %u\n", - channel->channel, tx_queue->label, - tx_queue->queue); - } - - /* If XDP is borrowing queues from net stack, it must use the queue - * with no csum offload, which is the first one of the channel - * (note: channel->tx_queue_by_type is not initialized yet) - */ - if (efx->xdp_txq_queues_mode == EFX_XDP_TX_QUEUES_BORROWED) { - tx_queue = &channel->tx_queue[0]; - rc = efx_set_xdp_tx_queue(efx, xdp_queue_number, tx_queue); - if (rc == 0) - xdp_queue_number++; - } - } - } } - WARN_ON(efx->xdp_txq_queues_mode == EFX_XDP_TX_QUEUES_DEDICATED && - xdp_queue_number != efx->xdp_tx_queue_count); - WARN_ON(efx->xdp_txq_queues_mode != EFX_XDP_TX_QUEUES_DEDICATED && - xdp_queue_number > efx->xdp_tx_queue_count); - /* If we have more CPUs than assigned XDP TX queues, assign the already - * existing queues to the exceeding CPUs - */ - next_queue = 0; - while (xdp_queue_number < efx->xdp_tx_queue_count) { - tx_queue = efx->xdp_tx_queues[next_queue++]; - rc = efx_set_xdp_tx_queue(efx, xdp_queue_number, tx_queue); - if (rc == 0) - xdp_queue_number++; - } + efx_set_xdp_channels(efx); rc = netif_set_real_num_tx_queues(efx->net_dev, efx->n_tx_channels); if (rc) @@ -1124,7 +1140,7 @@ void efx_start_channels(struct efx_nic *efx) struct efx_rx_queue *rx_queue; struct efx_channel *channel; - efx_for_each_channel(channel, efx) { + efx_for_each_channel_rev(channel, efx) { efx_for_each_channel_tx_queue(tx_queue, channel) { efx_init_tx_queue(tx_queue); atomic_inc(&efx->active_queues); diff --git a/drivers/net/ethernet/sfc/rx_common.c b/drivers/net/ethernet/sfc/rx_common.c index 1b22c7be0088..fa8b9aacca11 100644 --- a/drivers/net/ethernet/sfc/rx_common.c +++ b/drivers/net/ethernet/sfc/rx_common.c @@ -150,6 +150,9 @@ static void efx_fini_rx_recycle_ring(struct efx_rx_queue *rx_queue) struct efx_nic *efx = rx_queue->efx; int i; + if (unlikely(!rx_queue->page_ring)) + return; + /* Unmap and release the pages in the recycle ring. Remove the ring. */ for (i = 0; i <= rx_queue->page_ptr_mask; i++) { struct page *page = rx_queue->page_ring[i]; diff --git a/drivers/net/ethernet/sfc/tx.c b/drivers/net/ethernet/sfc/tx.c index d16e031e95f4..6983799e1c05 100644 --- a/drivers/net/ethernet/sfc/tx.c +++ b/drivers/net/ethernet/sfc/tx.c @@ -443,6 +443,9 @@ int efx_xdp_tx_buffers(struct efx_nic *efx, int n, struct xdp_frame **xdpfs, if (unlikely(!tx_queue)) return -EINVAL; + if (!tx_queue->initialised) + return -EINVAL; + if (efx->xdp_txq_queues_mode != EFX_XDP_TX_QUEUES_DEDICATED) HARD_TX_LOCK(efx->net_dev, tx_queue->core_txq, cpu); diff --git a/drivers/net/ethernet/sfc/tx_common.c b/drivers/net/ethernet/sfc/tx_common.c index d530cde2b864..9bc8281b7f5b 100644 --- a/drivers/net/ethernet/sfc/tx_common.c +++ b/drivers/net/ethernet/sfc/tx_common.c @@ -101,6 +101,8 @@ void efx_fini_tx_queue(struct efx_tx_queue *tx_queue) netif_dbg(tx_queue->efx, drv, tx_queue->efx->net_dev, "shutting down TX queue %d\n", tx_queue->queue); + tx_queue->initialised = false; + if (!tx_queue->buffer) return; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c index ecf759ee1c9f..017dbbda0c1c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c @@ -205,7 +205,7 @@ static const struct pci_device_id loongson_dwmac_id_table[] = { }; MODULE_DEVICE_TABLE(pci, loongson_dwmac_id_table); -struct pci_driver loongson_dwmac_driver = { +static struct pci_driver loongson_dwmac_driver = { .name = "dwmac-loongson-pci", .id_table = loongson_dwmac_id_table, .probe = loongson_dwmac_probe, diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 5d29f336315b..11e1055e8260 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -431,8 +431,7 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac) plat->phylink_node = np; /* Get max speed of operation from device tree */ - if (of_property_read_u32(np, "max-speed", &plat->max_speed)) - plat->max_speed = -1; + of_property_read_u32(np, "max-speed", &plat->max_speed); plat->bus_id = of_alias_get_id(np, "ethernet"); if (plat->bus_id < 0) diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h index 0f9c88dd1a4a..d5c1e5c4a508 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet.h +++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h @@ -433,8 +433,6 @@ struct axienet_local { struct net_device *ndev; struct device *dev; - struct device_node *phy_node; - struct phylink *phylink; struct phylink_config phylink_config; diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index c7eb05e4a6bf..d6fc3f7acdf0 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c @@ -2064,25 +2064,33 @@ static int axienet_probe(struct platform_device *pdev) if (ret) goto cleanup_clk; - lp->phy_node = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0); - if (lp->phy_node) { - ret = axienet_mdio_setup(lp); - if (ret) - dev_warn(&pdev->dev, - "error registering MDIO bus: %d\n", ret); - } + ret = axienet_mdio_setup(lp); + if (ret) + dev_warn(&pdev->dev, + "error registering MDIO bus: %d\n", ret); + if (lp->phy_mode == PHY_INTERFACE_MODE_SGMII || lp->phy_mode == PHY_INTERFACE_MODE_1000BASEX) { - if (!lp->phy_node) { - dev_err(&pdev->dev, "phy-handle required for 1000BaseX/SGMII\n"); + np = of_parse_phandle(pdev->dev.of_node, "pcs-handle", 0); + if (!np) { + /* Deprecated: Always use "pcs-handle" for pcs_phy. + * Falling back to "phy-handle" here is only for + * backward compatibility with old device trees. + */ + np = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0); + } + if (!np) { + dev_err(&pdev->dev, "pcs-handle (preferred) or phy-handle required for 1000BaseX/SGMII\n"); ret = -EINVAL; goto cleanup_mdio; } - lp->pcs_phy = of_mdio_find_device(lp->phy_node); + lp->pcs_phy = of_mdio_find_device(np); if (!lp->pcs_phy) { ret = -EPROBE_DEFER; + of_node_put(np); goto cleanup_mdio; } + of_node_put(np); lp->pcs.ops = &axienet_pcs_ops; lp->pcs.poll = true; } @@ -2125,8 +2133,6 @@ cleanup_mdio: put_device(&lp->pcs_phy->dev); if (lp->mii_bus) axienet_mdio_teardown(lp); - of_node_put(lp->phy_node); - cleanup_clk: clk_bulk_disable_unprepare(XAE_NUM_MISC_CLOCKS, lp->misc_clks); clk_disable_unprepare(lp->axi_clk); @@ -2155,9 +2161,6 @@ static int axienet_remove(struct platform_device *pdev) clk_bulk_disable_unprepare(XAE_NUM_MISC_CLOCKS, lp->misc_clks); clk_disable_unprepare(lp->axi_clk); - of_node_put(lp->phy_node); - lp->phy_node = NULL; - free_netdev(ndev); return 0; diff --git a/drivers/net/mctp/mctp-i2c.c b/drivers/net/mctp/mctp-i2c.c index baf7afac7857..53846c6b56ca 100644 --- a/drivers/net/mctp/mctp-i2c.c +++ b/drivers/net/mctp/mctp-i2c.c @@ -553,7 +553,7 @@ static int mctp_i2c_header_create(struct sk_buff *skb, struct net_device *dev, hdr->source_slave = ((llsrc << 1) & 0xff) | 0x01; mhdr->ver = 0x01; - return 0; + return sizeof(struct mctp_i2c_hdr); } static int mctp_i2c_tx_thread(void *data) diff --git a/drivers/net/mdio/mdio-mscc-miim.c b/drivers/net/mdio/mdio-mscc-miim.c index c483ba67c21f..582969751b4c 100644 --- a/drivers/net/mdio/mdio-mscc-miim.c +++ b/drivers/net/mdio/mdio-mscc-miim.c @@ -102,6 +102,9 @@ static int mscc_miim_read(struct mii_bus *bus, int mii_id, int regnum) u32 val; int ret; + if (regnum & MII_ADDR_C45) + return -EOPNOTSUPP; + ret = mscc_miim_wait_pending(bus); if (ret) goto out; @@ -145,6 +148,9 @@ static int mscc_miim_write(struct mii_bus *bus, int mii_id, struct mscc_miim_dev *miim = bus->priv; int ret; + if (regnum & MII_ADDR_C45) + return -EOPNOTSUPP; + ret = mscc_miim_wait_pending(bus); if (ret < 0) goto out; diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 19b11e896460..fc53b71dc872 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -99,15 +99,6 @@ #define PTP_TIMESTAMP_EN_PDREQ_ BIT(2) #define PTP_TIMESTAMP_EN_PDRES_ BIT(3) -#define PTP_RX_LATENCY_1000 0x0224 -#define PTP_TX_LATENCY_1000 0x0225 - -#define PTP_RX_LATENCY_100 0x0222 -#define PTP_TX_LATENCY_100 0x0223 - -#define PTP_RX_LATENCY_10 0x0220 -#define PTP_TX_LATENCY_10 0x0221 - #define PTP_TX_PARSE_L2_ADDR_EN 0x0284 #define PTP_RX_PARSE_L2_ADDR_EN 0x0244 @@ -268,15 +259,6 @@ struct lan8814_ptp_rx_ts { u16 seq_id; }; -struct kszphy_latencies { - u16 rx_10; - u16 tx_10; - u16 rx_100; - u16 tx_100; - u16 rx_1000; - u16 tx_1000; -}; - struct kszphy_ptp_priv { struct mii_timestamper mii_ts; struct phy_device *phydev; @@ -296,7 +278,6 @@ struct kszphy_ptp_priv { struct kszphy_priv { struct kszphy_ptp_priv ptp_priv; - struct kszphy_latencies latencies; const struct kszphy_type *type; int led_mode; bool rmii_ref_clk_sel; @@ -304,14 +285,6 @@ struct kszphy_priv { u64 stats[ARRAY_SIZE(kszphy_hw_stats)]; }; -static struct kszphy_latencies lan8814_latencies = { - .rx_10 = 0x22AA, - .tx_10 = 0x2E4A, - .rx_100 = 0x092A, - .tx_100 = 0x02C1, - .rx_1000 = 0x01AD, - .tx_1000 = 0x00C9, -}; static const struct kszphy_type ksz8021_type = { .led_mode_reg = MII_KSZPHY_CTRL_2, .has_broadcast_disable = true, @@ -2618,55 +2591,6 @@ static int lan8814_ptp_probe_once(struct phy_device *phydev) return 0; } -static int lan8814_read_status(struct phy_device *phydev) -{ - struct kszphy_priv *priv = phydev->priv; - struct kszphy_latencies *latencies = &priv->latencies; - int err; - int regval; - - err = genphy_read_status(phydev); - if (err) - return err; - - switch (phydev->speed) { - case SPEED_1000: - lanphy_write_page_reg(phydev, 5, PTP_RX_LATENCY_1000, - latencies->rx_1000); - lanphy_write_page_reg(phydev, 5, PTP_TX_LATENCY_1000, - latencies->tx_1000); - break; - case SPEED_100: - lanphy_write_page_reg(phydev, 5, PTP_RX_LATENCY_100, - latencies->rx_100); - lanphy_write_page_reg(phydev, 5, PTP_TX_LATENCY_100, - latencies->tx_100); - break; - case SPEED_10: - lanphy_write_page_reg(phydev, 5, PTP_RX_LATENCY_10, - latencies->rx_10); - lanphy_write_page_reg(phydev, 5, PTP_TX_LATENCY_10, - latencies->tx_10); - break; - default: - break; - } - - /* Make sure the PHY is not broken. Read idle error count, - * and reset the PHY if it is maxed out. - */ - regval = phy_read(phydev, MII_STAT1000); - if ((regval & 0xFF) == 0xFF) { - phy_init_hw(phydev); - phydev->link = 0; - if (phydev->drv->config_intr && phy_interrupt_is_valid(phydev)) - phydev->drv->config_intr(phydev); - return genphy_config_aneg(phydev); - } - - return 0; -} - static int lan8814_config_init(struct phy_device *phydev) { int val; @@ -2690,30 +2614,8 @@ static int lan8814_config_init(struct phy_device *phydev) return 0; } -static void lan8814_parse_latency(struct phy_device *phydev) -{ - const struct device_node *np = phydev->mdio.dev.of_node; - struct kszphy_priv *priv = phydev->priv; - struct kszphy_latencies *latency = &priv->latencies; - u32 val; - - if (!of_property_read_u32(np, "lan8814,latency_rx_10", &val)) - latency->rx_10 = val; - if (!of_property_read_u32(np, "lan8814,latency_tx_10", &val)) - latency->tx_10 = val; - if (!of_property_read_u32(np, "lan8814,latency_rx_100", &val)) - latency->rx_100 = val; - if (!of_property_read_u32(np, "lan8814,latency_tx_100", &val)) - latency->tx_100 = val; - if (!of_property_read_u32(np, "lan8814,latency_rx_1000", &val)) - latency->rx_1000 = val; - if (!of_property_read_u32(np, "lan8814,latency_tx_1000", &val)) - latency->tx_1000 = val; -} - static int lan8814_probe(struct phy_device *phydev) { - const struct device_node *np = phydev->mdio.dev.of_node; struct kszphy_priv *priv; u16 addr; int err; @@ -2724,13 +2626,10 @@ static int lan8814_probe(struct phy_device *phydev) priv->led_mode = -1; - priv->latencies = lan8814_latencies; - phydev->priv = priv; if (!IS_ENABLED(CONFIG_PTP_1588_CLOCK) || - !IS_ENABLED(CONFIG_NETWORK_PHY_TIMESTAMPING) || - of_property_read_bool(np, "lan8814,ignore-ts")) + !IS_ENABLED(CONFIG_NETWORK_PHY_TIMESTAMPING)) return 0; /* Strap-in value for PHY address, below register read gives starting @@ -2746,7 +2645,6 @@ static int lan8814_probe(struct phy_device *phydev) return err; } - lan8814_parse_latency(phydev); lan8814_ptp_init(phydev); return 0; @@ -2928,7 +2826,7 @@ static struct phy_driver ksphy_driver[] = { .config_init = lan8814_config_init, .probe = lan8814_probe, .soft_reset = genphy_soft_reset, - .read_status = lan8814_read_status, + .read_status = ksz9031_read_status, .get_sset_count = kszphy_get_sset_count, .get_strings = kszphy_get_strings, .get_stats = kszphy_get_stats, diff --git a/drivers/net/slip/slip.c b/drivers/net/slip/slip.c index 88396ff99f03..6865d32270e5 100644 --- a/drivers/net/slip/slip.c +++ b/drivers/net/slip/slip.c @@ -469,7 +469,7 @@ static void sl_tx_timeout(struct net_device *dev, unsigned int txqueue) spin_lock(&sl->lock); if (netif_queue_stopped(dev)) { - if (!netif_running(dev)) + if (!netif_running(dev) || !sl->tty) goto out; /* May be we must check transmitter timeout here ? diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c index ea06d10e1c21..ca409d450a29 100644 --- a/drivers/net/usb/aqc111.c +++ b/drivers/net/usb/aqc111.c @@ -1102,10 +1102,15 @@ static int aqc111_rx_fixup(struct usbnet *dev, struct sk_buff *skb) if (start_of_descs != desc_offset) goto err; - /* self check desc_offset from header*/ - if (desc_offset >= skb_len) + /* self check desc_offset from header and make sure that the + * bounds of the metadata array are inside the SKB + */ + if (pkt_count * 2 + desc_offset >= skb_len) goto err; + /* Packets must not overlap the metadata array */ + skb_trim(skb, desc_offset); + if (pkt_count == 0) goto err; diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c index 85e362461d71..cfc30ce4c6e1 100644 --- a/drivers/net/vrf.c +++ b/drivers/net/vrf.c @@ -1265,6 +1265,7 @@ static int vrf_prepare_mac_header(struct sk_buff *skb, eth = (struct ethhdr *)skb->data; skb_reset_mac_header(skb); + skb_reset_mac_len(skb); /* we set the ethernet destination and the source addresses to the * address of the VRF device. @@ -1294,9 +1295,9 @@ static int vrf_prepare_mac_header(struct sk_buff *skb, */ static int vrf_add_mac_header_if_unset(struct sk_buff *skb, struct net_device *vrf_dev, - u16 proto) + u16 proto, struct net_device *orig_dev) { - if (skb_mac_header_was_set(skb)) + if (skb_mac_header_was_set(skb) && dev_has_header(orig_dev)) return 0; return vrf_prepare_mac_header(skb, vrf_dev, proto); @@ -1402,6 +1403,8 @@ static struct sk_buff *vrf_ip6_rcv(struct net_device *vrf_dev, /* if packet is NDISC then keep the ingress interface */ if (!is_ndisc) { + struct net_device *orig_dev = skb->dev; + vrf_rx_stats(vrf_dev, skb->len); skb->dev = vrf_dev; skb->skb_iif = vrf_dev->ifindex; @@ -1410,7 +1413,8 @@ static struct sk_buff *vrf_ip6_rcv(struct net_device *vrf_dev, int err; err = vrf_add_mac_header_if_unset(skb, vrf_dev, - ETH_P_IPV6); + ETH_P_IPV6, + orig_dev); if (likely(!err)) { skb_push(skb, skb->mac_len); dev_queue_xmit_nit(skb, vrf_dev); @@ -1440,6 +1444,8 @@ static struct sk_buff *vrf_ip6_rcv(struct net_device *vrf_dev, static struct sk_buff *vrf_ip_rcv(struct net_device *vrf_dev, struct sk_buff *skb) { + struct net_device *orig_dev = skb->dev; + skb->dev = vrf_dev; skb->skb_iif = vrf_dev->ifindex; IPCB(skb)->flags |= IPSKB_L3SLAVE; @@ -1460,7 +1466,8 @@ static struct sk_buff *vrf_ip_rcv(struct net_device *vrf_dev, if (!list_empty(&vrf_dev->ptype_all)) { int err; - err = vrf_add_mac_header_if_unset(skb, vrf_dev, ETH_P_IP); + err = vrf_add_mac_header_if_unset(skb, vrf_dev, ETH_P_IP, + orig_dev); if (likely(!err)) { skb_push(skb, skb->mac_len); dev_queue_xmit_nit(skb, vrf_dev); diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c index 63e1c2d783c5..73693c66cef1 100644 --- a/drivers/net/wireless/ath/ath10k/sdio.c +++ b/drivers/net/wireless/ath/ath10k/sdio.c @@ -1633,7 +1633,7 @@ static void ath10k_sdio_hif_power_down(struct ath10k *ar) return; } - ret = mmc_hw_reset(ar_sdio->func->card->host); + ret = mmc_hw_reset(ar_sdio->func->card); if (ret) ath10k_warn(ar, "unable to reset sdio: %d\n", ret); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index ba3c159111d3..55285cad527f 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -4165,7 +4165,7 @@ static int brcmf_sdio_bus_reset(struct device *dev) /* reset the adapter */ sdio_claim_host(sdiodev->func1); - mmc_hw_reset(sdiodev->func1->card->host); + mmc_hw_reset(sdiodev->func1->card); sdio_release_host(sdiodev->func1); brcmf_bus_change_state(sdiodev->bus_if, BRCMF_BUS_DOWN); diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c b/drivers/net/wireless/marvell/mwifiex/sdio.c index bde9e4bbfffe..4f3238d2a171 100644 --- a/drivers/net/wireless/marvell/mwifiex/sdio.c +++ b/drivers/net/wireless/marvell/mwifiex/sdio.c @@ -2639,7 +2639,7 @@ static void mwifiex_sdio_card_reset_work(struct mwifiex_adapter *adapter) /* Run a HW reset of the SDIO interface. */ sdio_claim_host(func); - ret = mmc_hw_reset(func->card->host); + ret = mmc_hw_reset(func->card); sdio_release_host(func); switch (ret) { diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c index 72fc41ac83c0..9140b0163474 100644 --- a/drivers/net/wireless/ti/wlcore/sdio.c +++ b/drivers/net/wireless/ti/wlcore/sdio.c @@ -146,7 +146,7 @@ static int wl12xx_sdio_power_on(struct wl12xx_sdio_glue *glue) * To guarantee that the SDIO card is power cycled, as required to make * the FW programming to succeed, let's do a brute force HW reset. */ - mmc_hw_reset(card->host); + mmc_hw_reset(card); sdio_enable_func(func); sdio_release_host(func); diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c index 558b35aba610..d270a204324e 100644 --- a/drivers/pci/controller/pci-hyperv.c +++ b/drivers/pci/controller/pci-hyperv.c @@ -3407,6 +3407,15 @@ static int hv_pci_probe(struct hv_device *hdev, hbus->bridge->domain_nr = dom; #ifdef CONFIG_X86 hbus->sysdata.domain = dom; +#elif defined(CONFIG_ARM64) + /* + * Set the PCI bus parent to be the corresponding VMbus + * device. Then the VMbus device will be assigned as the + * ACPI companion in pcibios_root_bridge_prepare() and + * pci_dma_configure() will propagate device coherence + * information to devices created on the bus. + */ + hbus->sysdata.parent = hdev->device.parent; #endif hbus->hdev = hdev; diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig index afdcb91601d2..1e2d69453771 100644 --- a/drivers/perf/Kconfig +++ b/drivers/perf/Kconfig @@ -187,7 +187,7 @@ source "drivers/perf/hisilicon/Kconfig" config MARVELL_CN10K_DDR_PMU tristate "Enable MARVELL CN10K DRAM Subsystem(DSS) PMU Support" - depends on ARM64 || (COMPILE_TEST && 64BIT) + depends on ARCH_THUNDER || (COMPILE_TEST && 64BIT) help Enable perf support for Marvell DDR Performance monitoring event on CN10K platform. diff --git a/drivers/perf/fsl_imx8_ddr_perf.c b/drivers/perf/fsl_imx8_ddr_perf.c index 94ebc1ecace7..b1b2a55de77f 100644 --- a/drivers/perf/fsl_imx8_ddr_perf.c +++ b/drivers/perf/fsl_imx8_ddr_perf.c @@ -29,7 +29,7 @@ #define CNTL_OVER_MASK 0xFFFFFFFE #define CNTL_CSV_SHIFT 24 -#define CNTL_CSV_MASK (0xFF << CNTL_CSV_SHIFT) +#define CNTL_CSV_MASK (0xFFU << CNTL_CSV_SHIFT) #define EVENT_CYCLES_ID 0 #define EVENT_CYCLES_COUNTER 0 diff --git a/drivers/perf/qcom_l2_pmu.c b/drivers/perf/qcom_l2_pmu.c index 7640491aab12..30234c261b05 100644 --- a/drivers/perf/qcom_l2_pmu.c +++ b/drivers/perf/qcom_l2_pmu.c @@ -736,7 +736,7 @@ static struct cluster_pmu *l2_cache_associate_cpu_with_cluster( { u64 mpidr; int cpu_cluster_id; - struct cluster_pmu *cluster = NULL; + struct cluster_pmu *cluster; /* * This assumes that the cluster_id is in MPIDR[aff1] for @@ -758,10 +758,10 @@ static struct cluster_pmu *l2_cache_associate_cpu_with_cluster( cluster->cluster_id); cpumask_set_cpu(cpu, &cluster->cluster_cpus); *per_cpu_ptr(l2cache_pmu->pmu_cluster, cpu) = cluster; - break; + return cluster; } - return cluster; + return NULL; } static int l2cache_pmu_online_cpu(unsigned int cpu, struct hlist_node *node) diff --git a/drivers/regulator/atc260x-regulator.c b/drivers/regulator/atc260x-regulator.c index 05147d2c3842..485e58b264c0 100644 --- a/drivers/regulator/atc260x-regulator.c +++ b/drivers/regulator/atc260x-regulator.c @@ -292,6 +292,7 @@ enum atc2603c_reg_ids { .bypass_mask = BIT(5), \ .active_discharge_reg = ATC2603C_PMU_SWITCH_CTL, \ .active_discharge_mask = BIT(1), \ + .active_discharge_on = BIT(1), \ .owner = THIS_MODULE, \ } diff --git a/drivers/regulator/rtq2134-regulator.c b/drivers/regulator/rtq2134-regulator.c index f21e3f8b21f2..8e13dea354a2 100644 --- a/drivers/regulator/rtq2134-regulator.c +++ b/drivers/regulator/rtq2134-regulator.c @@ -285,6 +285,7 @@ static const unsigned int rtq2134_buck_ramp_delay_table[] = { .enable_mask = RTQ2134_VOUTEN_MASK, \ .active_discharge_reg = RTQ2134_REG_BUCK##_id##_CFG0, \ .active_discharge_mask = RTQ2134_ACTDISCHG_MASK, \ + .active_discharge_on = RTQ2134_ACTDISCHG_MASK, \ .ramp_reg = RTQ2134_REG_BUCK##_id##_RSPCFG, \ .ramp_mask = RTQ2134_RSPUP_MASK, \ .ramp_delay_table = rtq2134_buck_ramp_delay_table, \ diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c index cadea0344486..40befdd9dfa9 100644 --- a/drivers/regulator/wm8994-regulator.c +++ b/drivers/regulator/wm8994-regulator.c @@ -82,6 +82,35 @@ static const struct regulator_desc wm8994_ldo_desc[] = { .min_uV = 2400000, .uV_step = 100000, .enable_time = 3000, + .off_on_delay = 36000, + .owner = THIS_MODULE, + }, + { + .name = "LDO2", + .id = 2, + .type = REGULATOR_VOLTAGE, + .n_voltages = WM8994_LDO2_MAX_SELECTOR + 1, + .vsel_reg = WM8994_LDO_2, + .vsel_mask = WM8994_LDO2_VSEL_MASK, + .ops = &wm8994_ldo2_ops, + .enable_time = 3000, + .off_on_delay = 36000, + .owner = THIS_MODULE, + }, +}; + +static const struct regulator_desc wm8958_ldo_desc[] = { + { + .name = "LDO1", + .id = 1, + .type = REGULATOR_VOLTAGE, + .n_voltages = WM8994_LDO1_MAX_SELECTOR + 1, + .vsel_reg = WM8994_LDO_1, + .vsel_mask = WM8994_LDO1_VSEL_MASK, + .ops = &wm8994_ldo1_ops, + .min_uV = 2400000, + .uV_step = 100000, + .enable_time = 3000, .owner = THIS_MODULE, }, { @@ -172,9 +201,16 @@ static int wm8994_ldo_probe(struct platform_device *pdev) * regulator core and we need not worry about it on the * error path. */ - ldo->regulator = devm_regulator_register(&pdev->dev, - &wm8994_ldo_desc[id], - &config); + if (ldo->wm8994->type == WM8994) { + ldo->regulator = devm_regulator_register(&pdev->dev, + &wm8994_ldo_desc[id], + &config); + } else { + ldo->regulator = devm_regulator_register(&pdev->dev, + &wm8958_ldo_desc[id], + &config); + } + if (IS_ERR(ldo->regulator)) { ret = PTR_ERR(ldo->regulator); dev_err(wm8994->dev, "Failed to register LDO%d: %d\n", diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index 5f554a3a0f62..caeebfb67149 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -317,14 +317,18 @@ enum { }; struct aha152x_cmd_priv { - struct scsi_pointer scsi_pointer; + char *ptr; + int this_residual; + struct scatterlist *buffer; + int status; + int message; + int sent_command; + int phase; }; -static struct scsi_pointer *aha152x_scsi_pointer(struct scsi_cmnd *cmd) +static struct aha152x_cmd_priv *aha152x_priv(struct scsi_cmnd *cmd) { - struct aha152x_cmd_priv *acmd = scsi_cmd_priv(cmd); - - return &acmd->scsi_pointer; + return scsi_cmd_priv(cmd); } MODULE_AUTHOR("Jürgen Fischer"); @@ -890,17 +894,16 @@ void aha152x_release(struct Scsi_Host *shpnt) static int setup_expected_interrupts(struct Scsi_Host *shpnt) { if(CURRENT_SC) { - struct scsi_pointer *scsi_pointer = - aha152x_scsi_pointer(CURRENT_SC); + struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC); - scsi_pointer->phase |= 1 << 16; + acp->phase |= 1 << 16; - if (scsi_pointer->phase & selecting) { + if (acp->phase & selecting) { SETPORT(SSTAT1, SELTO); SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0)); SETPORT(SIMODE1, ENSELTIMO); } else { - SETPORT(SIMODE0, (scsi_pointer->phase & spiordy) ? ENSPIORDY : 0); + SETPORT(SIMODE0, (acp->phase & spiordy) ? ENSPIORDY : 0); SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE); } } else if(STATE==seldi) { @@ -924,17 +927,16 @@ static int setup_expected_interrupts(struct Scsi_Host *shpnt) static int aha152x_internal_queue(struct scsi_cmnd *SCpnt, struct completion *complete, int phase) { - struct scsi_pointer *scsi_pointer = aha152x_scsi_pointer(SCpnt); + struct aha152x_cmd_priv *acp = aha152x_priv(SCpnt); struct Scsi_Host *shpnt = SCpnt->device->host; unsigned long flags; - scsi_pointer->phase = not_issued | phase; - scsi_pointer->Status = 0x1; /* Ilegal status by SCSI standard */ - scsi_pointer->Message = 0; - scsi_pointer->have_data_in = 0; - scsi_pointer->sent_command = 0; + acp->phase = not_issued | phase; + acp->status = 0x1; /* Illegal status by SCSI standard */ + acp->message = 0; + acp->sent_command = 0; - if (scsi_pointer->phase & (resetting | check_condition)) { + if (acp->phase & (resetting | check_condition)) { if (!SCpnt->host_scribble || SCSEM(SCpnt) || SCNEXT(SCpnt)) { scmd_printk(KERN_ERR, SCpnt, "cannot reuse command\n"); return FAILED; @@ -957,15 +959,15 @@ static int aha152x_internal_queue(struct scsi_cmnd *SCpnt, SCp.phase : current state of the command */ if ((phase & resetting) || !scsi_sglist(SCpnt)) { - scsi_pointer->ptr = NULL; - scsi_pointer->this_residual = 0; + acp->ptr = NULL; + acp->this_residual = 0; scsi_set_resid(SCpnt, 0); - scsi_pointer->buffer = NULL; + acp->buffer = NULL; } else { scsi_set_resid(SCpnt, scsi_bufflen(SCpnt)); - scsi_pointer->buffer = scsi_sglist(SCpnt); - scsi_pointer->ptr = SG_ADDRESS(scsi_pointer->buffer); - scsi_pointer->this_residual = scsi_pointer->buffer->length; + acp->buffer = scsi_sglist(SCpnt); + acp->ptr = SG_ADDRESS(acp->buffer); + acp->this_residual = acp->buffer->length; } DO_LOCK(flags); @@ -1015,7 +1017,7 @@ static void reset_done(struct scsi_cmnd *SCpnt) static void aha152x_scsi_done(struct scsi_cmnd *SCpnt) { - if (aha152x_scsi_pointer(SCpnt)->phase & resetting) + if (aha152x_priv(SCpnt)->phase & resetting) reset_done(SCpnt); else scsi_done(SCpnt); @@ -1101,7 +1103,7 @@ static int aha152x_device_reset(struct scsi_cmnd * SCpnt) DO_LOCK(flags); - if (aha152x_scsi_pointer(SCpnt)->phase & resetted) { + if (aha152x_priv(SCpnt)->phase & resetted) { HOSTDATA(shpnt)->commands--; if (!HOSTDATA(shpnt)->commands) SETPORT(PORTA, 0); @@ -1395,31 +1397,30 @@ static void busfree_run(struct Scsi_Host *shpnt) SETPORT(SSTAT1, CLRBUSFREE); if(CURRENT_SC) { - struct scsi_pointer *scsi_pointer = - aha152x_scsi_pointer(CURRENT_SC); + struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC); #if defined(AHA152X_STAT) action++; #endif - scsi_pointer->phase &= ~syncneg; + acp->phase &= ~syncneg; - if (scsi_pointer->phase & completed) { + if (acp->phase & completed) { /* target sent COMMAND COMPLETE */ - done(shpnt, scsi_pointer->Status, DID_OK); + done(shpnt, acp->status, DID_OK); - } else if (scsi_pointer->phase & aborted) { - done(shpnt, scsi_pointer->Status, DID_ABORT); + } else if (acp->phase & aborted) { + done(shpnt, acp->status, DID_ABORT); - } else if (scsi_pointer->phase & resetted) { - done(shpnt, scsi_pointer->Status, DID_RESET); + } else if (acp->phase & resetted) { + done(shpnt, acp->status, DID_RESET); - } else if (scsi_pointer->phase & disconnected) { + } else if (acp->phase & disconnected) { /* target sent DISCONNECT */ #if defined(AHA152X_STAT) HOSTDATA(shpnt)->disconnections++; #endif append_SC(&DISCONNECTED_SC, CURRENT_SC); - scsi_pointer->phase |= 1 << 16; + acp->phase |= 1 << 16; CURRENT_SC = NULL; } else { @@ -1438,24 +1439,23 @@ static void busfree_run(struct Scsi_Host *shpnt) action++; #endif - if (aha152x_scsi_pointer(DONE_SC)->phase & check_condition) { + if (aha152x_priv(DONE_SC)->phase & check_condition) { struct scsi_cmnd *cmd = HOSTDATA(shpnt)->done_SC; struct aha152x_scdata *sc = SCDATA(cmd); scsi_eh_restore_cmnd(cmd, &sc->ses); - aha152x_scsi_pointer(cmd)->Status = SAM_STAT_CHECK_CONDITION; + aha152x_priv(cmd)->status = SAM_STAT_CHECK_CONDITION; HOSTDATA(shpnt)->commands--; if (!HOSTDATA(shpnt)->commands) SETPORT(PORTA, 0); /* turn led off */ - } else if (aha152x_scsi_pointer(DONE_SC)->Status == - SAM_STAT_CHECK_CONDITION) { + } else if (aha152x_priv(DONE_SC)->status == SAM_STAT_CHECK_CONDITION) { #if defined(AHA152X_STAT) HOSTDATA(shpnt)->busfree_with_check_condition++; #endif - if(!(aha152x_scsi_pointer(DONE_SC)->phase & not_issued)) { + if (!(aha152x_priv(DONE_SC)->phase & not_issued)) { struct aha152x_scdata *sc; struct scsi_cmnd *ptr = DONE_SC; DONE_SC=NULL; @@ -1480,7 +1480,7 @@ static void busfree_run(struct Scsi_Host *shpnt) if (!HOSTDATA(shpnt)->commands) SETPORT(PORTA, 0); /* turn led off */ - if (!(aha152x_scsi_pointer(ptr)->phase & resetting)) { + if (!(aha152x_priv(ptr)->phase & resetting)) { kfree(ptr->host_scribble); ptr->host_scribble=NULL; } @@ -1503,13 +1503,12 @@ static void busfree_run(struct Scsi_Host *shpnt) DO_UNLOCK(flags); if(CURRENT_SC) { - struct scsi_pointer *scsi_pointer = - aha152x_scsi_pointer(CURRENT_SC); + struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC); #if defined(AHA152X_STAT) action++; #endif - scsi_pointer->phase |= selecting; + acp->phase |= selecting; /* clear selection timeout */ SETPORT(SSTAT1, SELTO); @@ -1537,13 +1536,13 @@ static void busfree_run(struct Scsi_Host *shpnt) */ static void seldo_run(struct Scsi_Host *shpnt) { - struct scsi_pointer *scsi_pointer = aha152x_scsi_pointer(CURRENT_SC); + struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC); SETPORT(SCSISIG, 0); SETPORT(SSTAT1, CLRBUSFREE); SETPORT(SSTAT1, CLRPHASECHG); - scsi_pointer->phase &= ~(selecting | not_issued); + acp->phase &= ~(selecting | not_issued); SETPORT(SCSISEQ, 0); @@ -1558,12 +1557,12 @@ static void seldo_run(struct Scsi_Host *shpnt) ADDMSGO(IDENTIFY(RECONNECT, CURRENT_SC->device->lun)); - if (scsi_pointer->phase & aborting) { + if (acp->phase & aborting) { ADDMSGO(ABORT); - } else if (scsi_pointer->phase & resetting) { + } else if (acp->phase & resetting) { ADDMSGO(BUS_DEVICE_RESET); } else if (SYNCNEG==0 && SYNCHRONOUS) { - scsi_pointer->phase |= syncneg; + acp->phase |= syncneg; MSGOLEN += spi_populate_sync_msg(&MSGO(MSGOLEN), 50, 8); SYNCNEG=1; /* negotiation in progress */ } @@ -1578,7 +1577,7 @@ static void seldo_run(struct Scsi_Host *shpnt) */ static void selto_run(struct Scsi_Host *shpnt) { - struct scsi_pointer *scsi_pointer = aha152x_scsi_pointer(CURRENT_SC); + struct aha152x_cmd_priv *acp; SETPORT(SCSISEQ, 0); SETPORT(SSTAT1, CLRSELTIMO); @@ -1586,9 +1585,10 @@ static void selto_run(struct Scsi_Host *shpnt) if (!CURRENT_SC) return; - scsi_pointer->phase &= ~selecting; + acp = aha152x_priv(CURRENT_SC); + acp->phase &= ~selecting; - if (scsi_pointer->phase & aborted) + if (acp->phase & aborted) done(shpnt, SAM_STAT_GOOD, DID_ABORT); else if (TESTLO(SSTAT0, SELINGO)) done(shpnt, SAM_STAT_GOOD, DID_BUS_BUSY); @@ -1616,10 +1616,9 @@ static void seldi_run(struct Scsi_Host *shpnt) SETPORT(SSTAT1, CLRPHASECHG); if(CURRENT_SC) { - struct scsi_pointer *scsi_pointer = - aha152x_scsi_pointer(CURRENT_SC); + struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC); - if (!(scsi_pointer->phase & not_issued)) + if (!(acp->phase & not_issued)) scmd_printk(KERN_ERR, CURRENT_SC, "command should not have been issued yet\n"); @@ -1676,7 +1675,7 @@ static void seldi_run(struct Scsi_Host *shpnt) static void msgi_run(struct Scsi_Host *shpnt) { for(;;) { - struct scsi_pointer *scsi_pointer; + struct aha152x_cmd_priv *acp; int sstat1 = GETPORT(SSTAT1); if(sstat1 & (PHASECHG|PHASEMIS|BUSFREE) || !(sstat1 & REQINIT)) @@ -1714,9 +1713,9 @@ static void msgi_run(struct Scsi_Host *shpnt) continue; } - scsi_pointer = aha152x_scsi_pointer(CURRENT_SC); - scsi_pointer->Message = MSGI(0); - scsi_pointer->phase &= ~disconnected; + acp = aha152x_priv(CURRENT_SC); + acp->message = MSGI(0); + acp->phase &= ~disconnected; MSGILEN=0; @@ -1724,8 +1723,8 @@ static void msgi_run(struct Scsi_Host *shpnt) continue; } - scsi_pointer = aha152x_scsi_pointer(CURRENT_SC); - scsi_pointer->Message = MSGI(0); + acp = aha152x_priv(CURRENT_SC); + acp->message = MSGI(0); switch (MSGI(0)) { case DISCONNECT: @@ -1733,11 +1732,11 @@ static void msgi_run(struct Scsi_Host *shpnt) scmd_printk(KERN_WARNING, CURRENT_SC, "target was not allowed to disconnect\n"); - scsi_pointer->phase |= disconnected; + acp->phase |= disconnected; break; case COMMAND_COMPLETE: - scsi_pointer->phase |= completed; + acp->phase |= completed; break; case MESSAGE_REJECT: @@ -1867,11 +1866,9 @@ static void msgi_end(struct Scsi_Host *shpnt) */ static void msgo_init(struct Scsi_Host *shpnt) { - struct scsi_pointer *scsi_pointer = aha152x_scsi_pointer(CURRENT_SC); - if(MSGOLEN==0) { - if ((scsi_pointer->phase & syncneg) && SYNCNEG==2 && - SYNCRATE==0) { + if ((aha152x_priv(CURRENT_SC)->phase & syncneg) && + SYNCNEG == 2 && SYNCRATE == 0) { ADDMSGO(IDENTIFY(RECONNECT, CURRENT_SC->device->lun)); } else { scmd_printk(KERN_INFO, CURRENT_SC, @@ -1888,7 +1885,7 @@ static void msgo_init(struct Scsi_Host *shpnt) */ static void msgo_run(struct Scsi_Host *shpnt) { - struct scsi_pointer *scsi_pointer = aha152x_scsi_pointer(CURRENT_SC); + struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC); while(MSGO_I<MSGOLEN) { if (TESTLO(SSTAT0, SPIORDY)) @@ -1901,13 +1898,13 @@ static void msgo_run(struct Scsi_Host *shpnt) if (MSGO(MSGO_I) & IDENTIFY_BASE) - scsi_pointer->phase |= identified; + acp->phase |= identified; if (MSGO(MSGO_I)==ABORT) - scsi_pointer->phase |= aborted; + acp->phase |= aborted; if (MSGO(MSGO_I)==BUS_DEVICE_RESET) - scsi_pointer->phase |= resetted; + acp->phase |= resetted; SETPORT(SCSIDAT, MSGO(MSGO_I++)); } @@ -1936,7 +1933,7 @@ static void msgo_end(struct Scsi_Host *shpnt) */ static void cmd_init(struct Scsi_Host *shpnt) { - if (aha152x_scsi_pointer(CURRENT_SC)->sent_command) { + if (aha152x_priv(CURRENT_SC)->sent_command) { scmd_printk(KERN_ERR, CURRENT_SC, "command already sent\n"); done(shpnt, SAM_STAT_GOOD, DID_ERROR); @@ -1967,7 +1964,7 @@ static void cmd_end(struct Scsi_Host *shpnt) "command sent incompletely (%d/%d)\n", CMD_I, CURRENT_SC->cmd_len); else - aha152x_scsi_pointer(CURRENT_SC)->sent_command++; + aha152x_priv(CURRENT_SC)->sent_command++; } /* @@ -1979,7 +1976,7 @@ static void status_run(struct Scsi_Host *shpnt) if (TESTLO(SSTAT0, SPIORDY)) return; - aha152x_scsi_pointer(CURRENT_SC)->Status = GETPORT(SCSIDAT); + aha152x_priv(CURRENT_SC)->status = GETPORT(SCSIDAT); } @@ -2003,7 +2000,7 @@ static void datai_init(struct Scsi_Host *shpnt) static void datai_run(struct Scsi_Host *shpnt) { - struct scsi_pointer *scsi_pointer; + struct aha152x_cmd_priv *acp; unsigned long the_time; int fifodata, data_count; @@ -2041,36 +2038,35 @@ static void datai_run(struct Scsi_Host *shpnt) fifodata = GETPORT(FIFOSTAT); } - scsi_pointer = aha152x_scsi_pointer(CURRENT_SC); - if (scsi_pointer->this_residual > 0) { - while (fifodata > 0 && scsi_pointer->this_residual > 0) { - data_count = fifodata > scsi_pointer->this_residual ? - scsi_pointer->this_residual : - fifodata; + acp = aha152x_priv(CURRENT_SC); + if (acp->this_residual > 0) { + while (fifodata > 0 && acp->this_residual > 0) { + data_count = fifodata > acp->this_residual ? + acp->this_residual : fifodata; fifodata -= data_count; if (data_count & 1) { SETPORT(DMACNTRL0, ENDMA|_8BIT); - *scsi_pointer->ptr++ = GETPORT(DATAPORT); - scsi_pointer->this_residual--; + *acp->ptr++ = GETPORT(DATAPORT); + acp->this_residual--; DATA_LEN++; SETPORT(DMACNTRL0, ENDMA); } if (data_count > 1) { data_count >>= 1; - insw(DATAPORT, scsi_pointer->ptr, data_count); - scsi_pointer->ptr += 2 * data_count; - scsi_pointer->this_residual -= 2 * data_count; + insw(DATAPORT, acp->ptr, data_count); + acp->ptr += 2 * data_count; + acp->this_residual -= 2 * data_count; DATA_LEN += 2 * data_count; } - if (scsi_pointer->this_residual == 0 && - !sg_is_last(scsi_pointer->buffer)) { + if (acp->this_residual == 0 && + !sg_is_last(acp->buffer)) { /* advance to next buffer */ - scsi_pointer->buffer = sg_next(scsi_pointer->buffer); - scsi_pointer->ptr = SG_ADDRESS(scsi_pointer->buffer); - scsi_pointer->this_residual = scsi_pointer->buffer->length; + acp->buffer = sg_next(acp->buffer); + acp->ptr = SG_ADDRESS(acp->buffer); + acp->this_residual = acp->buffer->length; } } } else if (fifodata > 0) { @@ -2138,15 +2134,15 @@ static void datao_init(struct Scsi_Host *shpnt) static void datao_run(struct Scsi_Host *shpnt) { - struct scsi_pointer *scsi_pointer = aha152x_scsi_pointer(CURRENT_SC); + struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC); unsigned long the_time; int data_count; /* until phase changes or all data sent */ - while (TESTLO(DMASTAT, INTSTAT) && scsi_pointer->this_residual > 0) { + while (TESTLO(DMASTAT, INTSTAT) && acp->this_residual > 0) { data_count = 128; - if (data_count > scsi_pointer->this_residual) - data_count = scsi_pointer->this_residual; + if (data_count > acp->this_residual) + data_count = acp->this_residual; if(TESTLO(DMASTAT, DFIFOEMP)) { scmd_printk(KERN_ERR, CURRENT_SC, @@ -2157,26 +2153,25 @@ static void datao_run(struct Scsi_Host *shpnt) if(data_count & 1) { SETPORT(DMACNTRL0,WRITE_READ|ENDMA|_8BIT); - SETPORT(DATAPORT, *scsi_pointer->ptr++); - scsi_pointer->this_residual--; + SETPORT(DATAPORT, *acp->ptr++); + acp->this_residual--; CMD_INC_RESID(CURRENT_SC, -1); SETPORT(DMACNTRL0,WRITE_READ|ENDMA); } if(data_count > 1) { data_count >>= 1; - outsw(DATAPORT, scsi_pointer->ptr, data_count); - scsi_pointer->ptr += 2 * data_count; - scsi_pointer->this_residual -= 2 * data_count; + outsw(DATAPORT, acp->ptr, data_count); + acp->ptr += 2 * data_count; + acp->this_residual -= 2 * data_count; CMD_INC_RESID(CURRENT_SC, -2 * data_count); } - if (scsi_pointer->this_residual == 0 && - !sg_is_last(scsi_pointer->buffer)) { + if (acp->this_residual == 0 && !sg_is_last(acp->buffer)) { /* advance to next buffer */ - scsi_pointer->buffer = sg_next(scsi_pointer->buffer); - scsi_pointer->ptr = SG_ADDRESS(scsi_pointer->buffer); - scsi_pointer->this_residual = scsi_pointer->buffer->length; + acp->buffer = sg_next(acp->buffer); + acp->ptr = SG_ADDRESS(acp->buffer); + acp->this_residual = acp->buffer->length; } the_time=jiffies + 100*HZ; @@ -2192,7 +2187,7 @@ static void datao_run(struct Scsi_Host *shpnt) static void datao_end(struct Scsi_Host *shpnt) { - struct scsi_pointer *scsi_pointer = aha152x_scsi_pointer(CURRENT_SC); + struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC); if(TESTLO(DMASTAT, DFIFOEMP)) { u32 datao_cnt = GETSTCNT(); @@ -2211,10 +2206,9 @@ static void datao_end(struct Scsi_Host *shpnt) sg = sg_next(sg); } - scsi_pointer->buffer = sg; - scsi_pointer->ptr = SG_ADDRESS(scsi_pointer->buffer) + done; - scsi_pointer->this_residual = scsi_pointer->buffer->length - - done; + acp->buffer = sg; + acp->ptr = SG_ADDRESS(acp->buffer) + done; + acp->this_residual = acp->buffer->length - done; } SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT); @@ -2229,7 +2223,6 @@ static void datao_end(struct Scsi_Host *shpnt) */ static int update_state(struct Scsi_Host *shpnt) { - struct scsi_pointer *scsi_pointer = aha152x_scsi_pointer(CURRENT_SC); int dataphase=0; unsigned int stat0 = GETPORT(SSTAT0); unsigned int stat1 = GETPORT(SSTAT1); @@ -2244,7 +2237,7 @@ static int update_state(struct Scsi_Host *shpnt) } else if (stat0 & SELDI && PREVSTATE == busfree) { STATE=seldi; } else if (stat0 & SELDO && CURRENT_SC && - (scsi_pointer->phase & selecting)) { + (aha152x_priv(CURRENT_SC)->phase & selecting)) { STATE=seldo; } else if(stat1 & SELTO) { STATE=selto; @@ -2376,8 +2369,7 @@ static void is_complete(struct Scsi_Host *shpnt) SETPORT(SXFRCTL0, CH1); SETPORT(DMACNTRL0, 0); if(CURRENT_SC) - aha152x_scsi_pointer(CURRENT_SC)->phase &= - ~spiordy; + aha152x_priv(CURRENT_SC)->phase &= ~spiordy; } /* @@ -2399,8 +2391,7 @@ static void is_complete(struct Scsi_Host *shpnt) SETPORT(DMACNTRL0, 0); SETPORT(SXFRCTL0, CH1|SPIOEN); if(CURRENT_SC) - aha152x_scsi_pointer(CURRENT_SC)->phase |= - spiordy; + aha152x_priv(CURRENT_SC)->phase |= spiordy; } /* @@ -2490,7 +2481,7 @@ static void disp_enintr(struct Scsi_Host *shpnt) */ static void show_command(struct scsi_cmnd *ptr) { - const int phase = aha152x_scsi_pointer(ptr)->phase; + const int phase = aha152x_priv(ptr)->phase; scsi_print_command(ptr); scmd_printk(KERN_DEBUG, ptr, @@ -2538,8 +2529,8 @@ static void show_queues(struct Scsi_Host *shpnt) static void get_command(struct seq_file *m, struct scsi_cmnd * ptr) { - struct scsi_pointer *scsi_pointer = aha152x_scsi_pointer(ptr); - const int phase = scsi_pointer->phase; + struct aha152x_cmd_priv *acp = aha152x_priv(ptr); + const int phase = acp->phase; int i; seq_printf(m, "%p: target=%d; lun=%d; cmnd=( ", @@ -2549,8 +2540,8 @@ static void get_command(struct seq_file *m, struct scsi_cmnd * ptr) seq_printf(m, "0x%02x ", ptr->cmnd[i]); seq_printf(m, "); resid=%d; residual=%d; buffers=%d; phase |", - scsi_get_resid(ptr), scsi_pointer->this_residual, - sg_nents(scsi_pointer->buffer) - 1); + scsi_get_resid(ptr), acp->this_residual, + sg_nents(acp->buffer) - 1); if (phase & not_issued) seq_puts(m, "not issued|"); diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h index 679a4fd13874..793fe19993a9 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.h +++ b/drivers/scsi/aic7xxx/aic79xx_osm.h @@ -420,8 +420,6 @@ ahd_unlock(struct ahd_softc *ahd, unsigned long *flags) /* config registers for header type 0 devices */ #define PCIR_MAPS 0x10 -#define PCIR_SUBVEND_0 0x2c -#define PCIR_SUBDEV_0 0x2e /****************************** PCI-X definitions *****************************/ #define PCIXR_COMMAND 0x96 diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c index 2f0bdb9225a4..5fad41b1ab58 100644 --- a/drivers/scsi/aic7xxx/aic79xx_pci.c +++ b/drivers/scsi/aic7xxx/aic79xx_pci.c @@ -260,8 +260,8 @@ ahd_find_pci_device(ahd_dev_softc_t pci) vendor = ahd_pci_read_config(pci, PCIR_DEVVENDOR, /*bytes*/2); device = ahd_pci_read_config(pci, PCIR_DEVICE, /*bytes*/2); - subvendor = ahd_pci_read_config(pci, PCIR_SUBVEND_0, /*bytes*/2); - subdevice = ahd_pci_read_config(pci, PCIR_SUBDEV_0, /*bytes*/2); + subvendor = ahd_pci_read_config(pci, PCI_SUBSYSTEM_VENDOR_ID, /*bytes*/2); + subdevice = ahd_pci_read_config(pci, PCI_SUBSYSTEM_ID, /*bytes*/2); full_id = ahd_compose_id(device, vendor, subdevice, @@ -298,7 +298,7 @@ ahd_pci_config(struct ahd_softc *ahd, const struct ahd_pci_identity *entry) * Record if this is an HP board. */ subvendor = ahd_pci_read_config(ahd->dev_softc, - PCIR_SUBVEND_0, /*bytes*/2); + PCI_SUBSYSTEM_VENDOR_ID, /*bytes*/2); if (subvendor == SUBID_HP) ahd->flags |= AHD_HP_BOARD; diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h index 4782a304e93c..51d9f4de0734 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.h +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h @@ -433,8 +433,6 @@ ahc_unlock(struct ahc_softc *ahc, unsigned long *flags) /* config registers for header type 0 devices */ #define PCIR_MAPS 0x10 -#define PCIR_SUBVEND_0 0x2c -#define PCIR_SUBDEV_0 0x2e typedef enum { diff --git a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c index dab3a6d12c4d..2d4c85426dc3 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_pci.c +++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c @@ -673,8 +673,8 @@ ahc_find_pci_device(ahc_dev_softc_t pci) vendor = ahc_pci_read_config(pci, PCIR_DEVVENDOR, /*bytes*/2); device = ahc_pci_read_config(pci, PCIR_DEVICE, /*bytes*/2); - subvendor = ahc_pci_read_config(pci, PCIR_SUBVEND_0, /*bytes*/2); - subdevice = ahc_pci_read_config(pci, PCIR_SUBDEV_0, /*bytes*/2); + subvendor = ahc_pci_read_config(pci, PCI_SUBSYSTEM_VENDOR_ID, /*bytes*/2); + subdevice = ahc_pci_read_config(pci, PCI_SUBSYSTEM_ID, /*bytes*/2); full_id = ahc_compose_id(device, vendor, subdevice, subvendor); /* diff --git a/drivers/scsi/bnx2fc/bnx2fc_hwi.c b/drivers/scsi/bnx2fc/bnx2fc_hwi.c index 0103f811cc25..776544385598 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_hwi.c +++ b/drivers/scsi/bnx2fc/bnx2fc_hwi.c @@ -1169,7 +1169,7 @@ static void bnx2fc_process_ofld_cmpl(struct bnx2fc_hba *hba, ofld_kcqe->fcoe_conn_context_id); interface = tgt->port->priv; if (hba != interface->hba) { - printk(KERN_ERR PFX "ERROR:ofld_cmpl: HBA mis-match\n"); + printk(KERN_ERR PFX "ERROR:ofld_cmpl: HBA mismatch\n"); goto ofld_cmpl_err; } /* @@ -1226,12 +1226,12 @@ static void bnx2fc_process_enable_conn_cmpl(struct bnx2fc_hba *hba, * and enable */ if (tgt->context_id != context_id) { - printk(KERN_ERR PFX "context id mis-match\n"); + printk(KERN_ERR PFX "context id mismatch\n"); return; } interface = tgt->port->priv; if (hba != interface->hba) { - printk(KERN_ERR PFX "bnx2fc-enbl_cmpl: HBA mis-match\n"); + printk(KERN_ERR PFX "bnx2fc-enbl_cmpl: HBA mismatch\n"); goto enbl_cmpl_err; } if (!ofld_kcqe->completion_status) diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c index 5521469ce678..7fe7f53a41c0 100644 --- a/drivers/scsi/bnx2i/bnx2i_hwi.c +++ b/drivers/scsi/bnx2i/bnx2i_hwi.c @@ -2398,7 +2398,7 @@ static void bnx2i_process_conn_destroy_cmpl(struct bnx2i_hba *hba, } if (hba != ep->hba) { - printk(KERN_ALERT "conn destroy- error hba mis-match\n"); + printk(KERN_ALERT "conn destroy- error hba mismatch\n"); return; } @@ -2432,7 +2432,7 @@ static void bnx2i_process_ofld_cmpl(struct bnx2i_hba *hba, } if (hba != ep->hba) { - printk(KERN_ALERT "ofld_cmpl: error hba mis-match\n"); + printk(KERN_ALERT "ofld_cmpl: error hba mismatch\n"); return; } diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 461ef8a76c4c..4bda2f6cb352 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -442,7 +442,6 @@ void hisi_sas_task_deliver(struct hisi_hba *hisi_hba, case SAS_PROTOCOL_INTERNAL_ABORT: hisi_sas_task_prep_abort(hisi_hba, slot); break; - fallthrough; default: return; } diff --git a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c index 80238e6a3c98..eee1a24f7e15 100644 --- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c +++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c @@ -36,7 +36,7 @@ #define IBMVSCSIS_VERSION "v0.2" -#define INITIAL_SRP_LIMIT 800 +#define INITIAL_SRP_LIMIT 1024 #define DEFAULT_MAX_SECTORS 256 #define MAX_TXU 1024 * 1024 diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c index d690d9cf7eb1..35589b6af90d 100644 --- a/drivers/scsi/isci/host.c +++ b/drivers/scsi/isci/host.c @@ -413,7 +413,7 @@ static void sci_controller_event_completion(struct isci_host *ihost, u32 ent) dev_warn(&ihost->pdev->dev, "%s: SCIC Controller 0x%p received " "event 0x%x for io request object " - "that doesnt exist.\n", + "that doesn't exist.\n", __func__, ihost, ent); @@ -428,7 +428,7 @@ static void sci_controller_event_completion(struct isci_host *ihost, u32 ent) dev_warn(&ihost->pdev->dev, "%s: SCIC Controller 0x%p received " "event 0x%x for remote device object " - "that doesnt exist.\n", + "that doesn't exist.\n", __func__, ihost, ent); @@ -462,7 +462,7 @@ static void sci_controller_event_completion(struct isci_host *ihost, u32 ent) } else dev_err(&ihost->pdev->dev, "%s: SCIC Controller 0x%p received event 0x%x " - "for remote device object 0x%0x that doesnt " + "for remote device object 0x%0x that doesn't " "exist.\n", __func__, ihost, diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index d09926e6c8a8..cf4211c6500d 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -3045,7 +3045,6 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size, if (!cls_conn) return NULL; conn = cls_conn->dd_data; - memset(conn, 0, sizeof(*conn) + dd_size); conn->dd_data = cls_conn->dd_data + sizeof(*conn); conn->session = session; diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index f0cf8ffdc5f3..0025760230e5 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -897,6 +897,11 @@ enum lpfc_irq_chann_mode { NHT_MODE, }; +enum lpfc_hba_bit_flags { + FABRIC_COMANDS_BLOCKED, + HBA_PCI_ERR, +}; + struct lpfc_hba { /* SCSI interface function jump table entries */ struct lpfc_io_buf * (*lpfc_get_scsi_buf) @@ -1043,7 +1048,6 @@ struct lpfc_hba { * Firmware supports Forced Link Speed * capability */ -#define HBA_PCI_ERR 0x80000 /* The PCI slot is offline */ #define HBA_FLOGI_ISSUED 0x100000 /* FLOGI was issued */ #define HBA_SHORT_CMF 0x200000 /* shorter CMF timer routine */ #define HBA_CGN_DAY_WRAP 0x400000 /* HBA Congestion info day wraps */ @@ -1350,7 +1354,6 @@ struct lpfc_hba { atomic_t fabric_iocb_count; struct timer_list fabric_block_timer; unsigned long bit_flags; -#define FABRIC_COMANDS_BLOCKED 0 atomic_t num_rsrc_err; atomic_t num_cmd_success; unsigned long last_rsrc_error_time; diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 96408cd6c4c8..9897a1aa387b 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -670,3 +670,6 @@ struct lpfc_vmid *lpfc_get_vmid_from_hashtable(struct lpfc_vport *vport, uint32_t hash, uint8_t *buf); void lpfc_vmid_vport_cleanup(struct lpfc_vport *vport); int lpfc_issue_els_qfpa(struct lpfc_vport *vport); + +void lpfc_sli_rpi_release(struct lpfc_vport *vport, + struct lpfc_nodelist *ndlp); diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 0144da30e3db..2b877dff5ed4 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -109,8 +109,8 @@ lpfc_rport_invalid(struct fc_rport *rport) ndlp = rdata->pnode; if (!rdata->pnode) { - pr_err("**** %s: NULL ndlp on rport x%px SID x%x\n", - __func__, rport, rport->scsi_target_id); + pr_info("**** %s: NULL ndlp on rport x%px SID x%x\n", + __func__, rport, rport->scsi_target_id); return -EINVAL; } @@ -169,9 +169,10 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, "3181 dev_loss_callbk x%06x, rport x%px flg x%x " - "load_flag x%x refcnt %d\n", + "load_flag x%x refcnt %d state %d xpt x%x\n", ndlp->nlp_DID, ndlp->rport, ndlp->nlp_flag, - vport->load_flag, kref_read(&ndlp->kref)); + vport->load_flag, kref_read(&ndlp->kref), + ndlp->nlp_state, ndlp->fc4_xpt_flags); /* Don't schedule a worker thread event if the vport is going down. * The teardown process cleans up the node via lpfc_drop_node. @@ -181,6 +182,11 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) ndlp->rport = NULL; ndlp->fc4_xpt_flags &= ~SCSI_XPT_REGD; + /* clear the NLP_XPT_REGD if the node is not registered + * with nvme-fc + */ + if (ndlp->fc4_xpt_flags == NLP_XPT_REGD) + ndlp->fc4_xpt_flags &= ~NLP_XPT_REGD; /* Remove the node reference from remote_port_add now. * The driver will not call remote_port_delete. @@ -225,18 +231,36 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) ndlp->rport = NULL; spin_unlock_irqrestore(&ndlp->lock, iflags); - /* We need to hold the node by incrementing the reference - * count until this queued work is done - */ - evtp->evt_arg1 = lpfc_nlp_get(ndlp); + if (phba->worker_thread) { + /* We need to hold the node by incrementing the reference + * count until this queued work is done + */ + evtp->evt_arg1 = lpfc_nlp_get(ndlp); + + spin_lock_irqsave(&phba->hbalock, iflags); + if (evtp->evt_arg1) { + evtp->evt = LPFC_EVT_DEV_LOSS; + list_add_tail(&evtp->evt_listp, &phba->work_list); + lpfc_worker_wake_up(phba); + } + spin_unlock_irqrestore(&phba->hbalock, iflags); + } else { + lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, + "3188 worker thread is stopped %s x%06x, " + " rport x%px flg x%x load_flag x%x refcnt " + "%d\n", __func__, ndlp->nlp_DID, + ndlp->rport, ndlp->nlp_flag, + vport->load_flag, kref_read(&ndlp->kref)); + if (!(ndlp->fc4_xpt_flags & NVME_XPT_REGD)) { + spin_lock_irqsave(&ndlp->lock, iflags); + /* Node is in dev loss. No further transaction. */ + ndlp->nlp_flag &= ~NLP_IN_DEV_LOSS; + spin_unlock_irqrestore(&ndlp->lock, iflags); + lpfc_disc_state_machine(vport, ndlp, NULL, + NLP_EVT_DEVICE_RM); + } - spin_lock_irqsave(&phba->hbalock, iflags); - if (evtp->evt_arg1) { - evtp->evt = LPFC_EVT_DEV_LOSS; - list_add_tail(&evtp->evt_listp, &phba->work_list); - lpfc_worker_wake_up(phba); } - spin_unlock_irqrestore(&phba->hbalock, iflags); return; } @@ -503,11 +527,12 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0203 Devloss timeout on " "WWPN %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x " - "NPort x%06x Data: x%x x%x x%x\n", + "NPort x%06x Data: x%x x%x x%x refcnt %d\n", *name, *(name+1), *(name+2), *(name+3), *(name+4), *(name+5), *(name+6), *(name+7), ndlp->nlp_DID, ndlp->nlp_flag, - ndlp->nlp_state, ndlp->nlp_rpi); + ndlp->nlp_state, ndlp->nlp_rpi, + kref_read(&ndlp->kref)); } else { lpfc_printf_vlog(vport, KERN_INFO, LOG_TRACE_EVENT, "0204 Devloss timeout on " @@ -755,18 +780,22 @@ lpfc_work_list_done(struct lpfc_hba *phba) int free_evt; int fcf_inuse; uint32_t nlp_did; + bool hba_pci_err; spin_lock_irq(&phba->hbalock); while (!list_empty(&phba->work_list)) { list_remove_head((&phba->work_list), evtp, typeof(*evtp), evt_listp); spin_unlock_irq(&phba->hbalock); + hba_pci_err = test_bit(HBA_PCI_ERR, &phba->bit_flags); free_evt = 1; switch (evtp->evt) { case LPFC_EVT_ELS_RETRY: ndlp = (struct lpfc_nodelist *) (evtp->evt_arg1); - lpfc_els_retry_delay_handler(ndlp); - free_evt = 0; /* evt is part of ndlp */ + if (!hba_pci_err) { + lpfc_els_retry_delay_handler(ndlp); + free_evt = 0; /* evt is part of ndlp */ + } /* decrement the node reference count held * for this queued work */ @@ -788,8 +817,10 @@ lpfc_work_list_done(struct lpfc_hba *phba) break; case LPFC_EVT_RECOVER_PORT: ndlp = (struct lpfc_nodelist *)(evtp->evt_arg1); - lpfc_sli_abts_recover_port(ndlp->vport, ndlp); - free_evt = 0; + if (!hba_pci_err) { + lpfc_sli_abts_recover_port(ndlp->vport, ndlp); + free_evt = 0; + } /* decrement the node reference count held for * this queued work */ @@ -859,14 +890,18 @@ lpfc_work_done(struct lpfc_hba *phba) struct lpfc_vport **vports; struct lpfc_vport *vport; int i; + bool hba_pci_err; + hba_pci_err = test_bit(HBA_PCI_ERR, &phba->bit_flags); spin_lock_irq(&phba->hbalock); ha_copy = phba->work_ha; phba->work_ha = 0; spin_unlock_irq(&phba->hbalock); + if (hba_pci_err) + ha_copy = 0; /* First, try to post the next mailbox command to SLI4 device */ - if (phba->pci_dev_grp == LPFC_PCI_DEV_OC) + if (phba->pci_dev_grp == LPFC_PCI_DEV_OC && !hba_pci_err) lpfc_sli4_post_async_mbox(phba); if (ha_copy & HA_ERATT) { @@ -886,7 +921,7 @@ lpfc_work_done(struct lpfc_hba *phba) lpfc_handle_latt(phba); /* Handle VMID Events */ - if (lpfc_is_vmid_enabled(phba)) { + if (lpfc_is_vmid_enabled(phba) && !hba_pci_err) { if (phba->pport->work_port_events & WORKER_CHECK_VMID_ISSUE_QFPA) { lpfc_check_vmid_qfpa_issue(phba); @@ -936,6 +971,8 @@ lpfc_work_done(struct lpfc_hba *phba) work_port_events = vport->work_port_events; vport->work_port_events &= ~work_port_events; spin_unlock_irq(&vport->work_port_lock); + if (hba_pci_err) + continue; if (work_port_events & WORKER_DISC_TMO) lpfc_disc_timeout_handler(vport); if (work_port_events & WORKER_ELS_TMO) @@ -1173,12 +1210,14 @@ lpfc_linkdown(struct lpfc_hba *phba) struct lpfc_vport **vports; LPFC_MBOXQ_t *mb; int i; + int offline; if (phba->link_state == LPFC_LINK_DOWN) return 0; /* Block all SCSI stack I/Os */ lpfc_scsi_dev_block(phba); + offline = pci_channel_offline(phba->pcidev); phba->defer_flogi_acc_flag = false; @@ -1219,7 +1258,7 @@ lpfc_linkdown(struct lpfc_hba *phba) lpfc_destroy_vport_work_array(phba, vports); /* Clean up any SLI3 firmware default rpi's */ - if (phba->sli_rev > LPFC_SLI_REV3) + if (phba->sli_rev > LPFC_SLI_REV3 || offline) goto skip_unreg_did; mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); @@ -4712,6 +4751,11 @@ lpfc_nlp_unreg_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) spin_lock_irqsave(&ndlp->lock, iflags); if (!(ndlp->fc4_xpt_flags & NLP_XPT_REGD)) { spin_unlock_irqrestore(&ndlp->lock, iflags); + lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI, + "0999 %s Not regd: ndlp x%px rport x%px DID " + "x%x FLG x%x XPT x%x\n", + __func__, ndlp, ndlp->rport, ndlp->nlp_DID, + ndlp->nlp_flag, ndlp->fc4_xpt_flags); return; } @@ -4722,6 +4766,13 @@ lpfc_nlp_unreg_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) ndlp->fc4_xpt_flags & SCSI_XPT_REGD) { vport->phba->nport_event_cnt++; lpfc_unregister_remote_port(ndlp); + } else if (!ndlp->rport) { + lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI, + "1999 %s NDLP in devloss x%px DID x%x FLG x%x" + " XPT x%x refcnt %d\n", + __func__, ndlp, ndlp->nlp_DID, ndlp->nlp_flag, + ndlp->fc4_xpt_flags, + kref_read(&ndlp->kref)); } if (ndlp->fc4_xpt_flags & NVME_XPT_REGD) { @@ -5371,6 +5422,7 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) ndlp->nlp_flag &= ~NLP_UNREG_INP; mempool_free(mbox, phba->mbox_mem_pool); acc_plogi = 1; + lpfc_nlp_put(ndlp); } } else { lpfc_printf_vlog(vport, KERN_INFO, @@ -6097,12 +6149,34 @@ lpfc_disc_flush_list(struct lpfc_vport *vport) } } +/* + * lpfc_notify_xport_npr - notifies xport of node disappearance + * @vport: Pointer to Virtual Port object. + * + * Transitions all ndlps to NPR state. When lpfc_nlp_set_state + * calls lpfc_nlp_state_cleanup, the ndlp->rport is unregistered + * and transport notified that the node is gone. + * Return Code: + * none + */ +static void +lpfc_notify_xport_npr(struct lpfc_vport *vport) +{ + struct lpfc_nodelist *ndlp, *next_ndlp; + + list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, + nlp_listp) { + lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); + } +} void lpfc_cleanup_discovery_resources(struct lpfc_vport *vport) { lpfc_els_flush_rscn(vport); lpfc_els_flush_cmd(vport); lpfc_disc_flush_list(vport); + if (pci_channel_offline(vport->phba->pcidev)) + lpfc_notify_xport_npr(vport); } /*****************************************************************************/ diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index eed6464bd880..461d333b1b3a 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -95,6 +95,7 @@ static void lpfc_sli4_oas_verify(struct lpfc_hba *phba); static uint16_t lpfc_find_cpu_handle(struct lpfc_hba *, uint16_t, int); static void lpfc_setup_bg(struct lpfc_hba *, struct Scsi_Host *); static int lpfc_sli4_cgn_parm_chg_evt(struct lpfc_hba *); +static void lpfc_sli4_prep_dev_for_reset(struct lpfc_hba *phba); static struct scsi_transport_template *lpfc_transport_template = NULL; static struct scsi_transport_template *lpfc_vport_transport_template = NULL; @@ -1642,7 +1643,7 @@ lpfc_sli4_offline_eratt(struct lpfc_hba *phba) { spin_lock_irq(&phba->hbalock); if (phba->link_state == LPFC_HBA_ERROR && - phba->hba_flag & HBA_PCI_ERR) { + test_bit(HBA_PCI_ERR, &phba->bit_flags)) { spin_unlock_irq(&phba->hbalock); return; } @@ -1985,6 +1986,7 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) if (pci_channel_offline(phba->pcidev)) { lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3166 pci channel is offline\n"); + lpfc_sli_flush_io_rings(phba); return; } @@ -2973,6 +2975,22 @@ lpfc_cleanup(struct lpfc_vport *vport) NLP_EVT_DEVICE_RM); } + /* This is a special case flush to return all + * IOs before entering this loop. There are + * two points in the code where a flush is + * avoided if the FC_UNLOADING flag is set. + * one is in the multipool destroy, + * (this prevents a crash) and the other is + * in the nvme abort handler, ( also prevents + * a crash). Both of these exceptions are + * cases where the slot is still accessible. + * The flush here is only when the pci slot + * is offline. + */ + if (vport->load_flag & FC_UNLOADING && + pci_channel_offline(phba->pcidev)) + lpfc_sli_flush_io_rings(vport->phba); + /* At this point, ALL ndlp's should be gone * because of the previous NLP_EVT_DEVICE_RM. * Lets wait for this to happen, if needed. @@ -2985,7 +3003,7 @@ lpfc_cleanup(struct lpfc_vport *vport) list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { lpfc_printf_vlog(ndlp->vport, KERN_ERR, - LOG_TRACE_EVENT, + LOG_DISCOVERY, "0282 did:x%x ndlp:x%px " "refcnt:%d xflags x%x nflag x%x\n", ndlp->nlp_DID, (void *)ndlp, @@ -3682,7 +3700,8 @@ lpfc_offline_prep(struct lpfc_hba *phba, int mbx_action) struct lpfc_vport **vports; struct Scsi_Host *shost; int i; - int offline = 0; + int offline; + bool hba_pci_err; if (vport->fc_flag & FC_OFFLINE_MODE) return; @@ -3692,6 +3711,7 @@ lpfc_offline_prep(struct lpfc_hba *phba, int mbx_action) lpfc_linkdown(phba); offline = pci_channel_offline(phba->pcidev); + hba_pci_err = test_bit(HBA_PCI_ERR, &phba->bit_flags); /* Issue an unreg_login to all nodes on all vports */ vports = lpfc_create_vport_work_array(phba); @@ -3715,11 +3735,14 @@ lpfc_offline_prep(struct lpfc_hba *phba, int mbx_action) ndlp->nlp_flag &= ~NLP_NPR_ADISC; spin_unlock_irq(&ndlp->lock); - if (offline) { + if (offline || hba_pci_err) { spin_lock_irq(&ndlp->lock); ndlp->nlp_flag &= ~(NLP_UNREG_INP | NLP_RPI_REGISTERED); spin_unlock_irq(&ndlp->lock); + if (phba->sli_rev == LPFC_SLI_REV4) + lpfc_sli_rpi_release(vports[i], + ndlp); } else { lpfc_unreg_rpi(vports[i], ndlp); } @@ -13354,8 +13377,9 @@ lpfc_sli4_hba_unset(struct lpfc_hba *phba) /* Abort all iocbs associated with the hba */ lpfc_sli_hba_iocb_abort(phba); - /* Wait for completion of device XRI exchange busy */ - lpfc_sli4_xri_exchange_busy_wait(phba); + if (!pci_channel_offline(phba->pcidev)) + /* Wait for completion of device XRI exchange busy */ + lpfc_sli4_xri_exchange_busy_wait(phba); /* per-phba callback de-registration for hotplug event */ if (phba->pport) @@ -13374,15 +13398,12 @@ lpfc_sli4_hba_unset(struct lpfc_hba *phba) /* Disable FW logging to host memory */ lpfc_ras_stop_fwlog(phba); - /* Unset the queues shared with the hardware then release all - * allocated resources. - */ - lpfc_sli4_queue_unset(phba); - lpfc_sli4_queue_destroy(phba); - /* Reset SLI4 HBA FCoE function */ lpfc_pci_function_reset(phba); + /* release all queue allocated resources. */ + lpfc_sli4_queue_destroy(phba); + /* Free RAS DMA memory */ if (phba->ras_fwlog.ras_enabled) lpfc_sli4_ras_dma_free(phba); @@ -14262,6 +14283,7 @@ lpfc_sli_prep_dev_for_perm_failure(struct lpfc_hba *phba) "2711 PCI channel permanent disable for failure\n"); /* Block all SCSI devices' I/Os on the host */ lpfc_scsi_dev_block(phba); + lpfc_sli4_prep_dev_for_reset(phba); /* stop all timers */ lpfc_stop_hba_timers(phba); @@ -15057,24 +15079,28 @@ lpfc_sli4_prep_dev_for_recover(struct lpfc_hba *phba) static void lpfc_sli4_prep_dev_for_reset(struct lpfc_hba *phba) { - lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, - "2826 PCI channel disable preparing for reset\n"); + int offline = pci_channel_offline(phba->pcidev); + + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2826 PCI channel disable preparing for reset offline" + " %d\n", offline); /* Block any management I/Os to the device */ lpfc_block_mgmt_io(phba, LPFC_MBX_NO_WAIT); - /* Block all SCSI devices' I/Os on the host */ - lpfc_scsi_dev_block(phba); + /* HBA_PCI_ERR was set in io_error_detect */ + lpfc_offline_prep(phba, LPFC_MBX_NO_WAIT); /* Flush all driver's outstanding I/Os as we are to reset */ lpfc_sli_flush_io_rings(phba); + lpfc_offline(phba); /* stop all timers */ lpfc_stop_hba_timers(phba); + lpfc_sli4_queue_destroy(phba); /* Disable interrupt and pci device */ lpfc_sli4_disable_intr(phba); - lpfc_sli4_queue_destroy(phba); pci_disable_device(phba->pcidev); } @@ -15123,6 +15149,7 @@ lpfc_io_error_detected_s4(struct pci_dev *pdev, pci_channel_state_t state) { struct Scsi_Host *shost = pci_get_drvdata(pdev); struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; + bool hba_pci_err; switch (state) { case pci_channel_io_normal: @@ -15130,17 +15157,24 @@ lpfc_io_error_detected_s4(struct pci_dev *pdev, pci_channel_state_t state) lpfc_sli4_prep_dev_for_recover(phba); return PCI_ERS_RESULT_CAN_RECOVER; case pci_channel_io_frozen: - phba->hba_flag |= HBA_PCI_ERR; + hba_pci_err = test_and_set_bit(HBA_PCI_ERR, &phba->bit_flags); /* Fatal error, prepare for slot reset */ - lpfc_sli4_prep_dev_for_reset(phba); + if (!hba_pci_err) + lpfc_sli4_prep_dev_for_reset(phba); + else + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2832 Already handling PCI error " + "state: x%x\n", state); return PCI_ERS_RESULT_NEED_RESET; case pci_channel_io_perm_failure: - phba->hba_flag |= HBA_PCI_ERR; + set_bit(HBA_PCI_ERR, &phba->bit_flags); /* Permanent failure, prepare for device down */ lpfc_sli4_prep_dev_for_perm_failure(phba); return PCI_ERS_RESULT_DISCONNECT; default: - phba->hba_flag |= HBA_PCI_ERR; + hba_pci_err = test_and_set_bit(HBA_PCI_ERR, &phba->bit_flags); + if (!hba_pci_err) + lpfc_sli4_prep_dev_for_reset(phba); /* Unknown state, prepare and request slot reset */ lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "2825 Unknown PCI error state: x%x\n", state); @@ -15174,17 +15208,21 @@ lpfc_io_slot_reset_s4(struct pci_dev *pdev) struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; struct lpfc_sli *psli = &phba->sli; uint32_t intr_mode; + bool hba_pci_err; dev_printk(KERN_INFO, &pdev->dev, "recovering from a slot reset.\n"); if (pci_enable_device_mem(pdev)) { printk(KERN_ERR "lpfc: Cannot re-enable " - "PCI device after reset.\n"); + "PCI device after reset.\n"); return PCI_ERS_RESULT_DISCONNECT; } pci_restore_state(pdev); - phba->hba_flag &= ~HBA_PCI_ERR; + hba_pci_err = test_and_clear_bit(HBA_PCI_ERR, &phba->bit_flags); + if (!hba_pci_err) + dev_info(&pdev->dev, + "hba_pci_err was not set, recovering slot reset.\n"); /* * As the new kernel behavior of pci_restore_state() API call clears * device saved_state flag, need to save the restored state again. @@ -15198,6 +15236,8 @@ lpfc_io_slot_reset_s4(struct pci_dev *pdev) psli->sli_flag &= ~LPFC_SLI_ACTIVE; spin_unlock_irq(&phba->hbalock); + /* Init cpu_map array */ + lpfc_cpu_map_array_init(phba); /* Configure and enable interrupt */ intr_mode = lpfc_sli4_enable_intr(phba, phba->intr_mode); if (intr_mode == LPFC_INTR_ERROR) { @@ -15239,8 +15279,6 @@ lpfc_io_resume_s4(struct pci_dev *pdev) */ if (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE)) { /* Perform device reset */ - lpfc_offline_prep(phba, LPFC_MBX_WAIT); - lpfc_offline(phba); lpfc_sli_brdrestart(phba); /* Bring the device back online */ lpfc_online(phba); diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c index 1213a299f9aa..8d26f207ebd2 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.c +++ b/drivers/scsi/lpfc/lpfc_nvme.c @@ -93,6 +93,11 @@ lpfc_nvme_create_queue(struct nvme_fc_local_port *pnvme_lport, lport = (struct lpfc_nvme_lport *)pnvme_lport->private; vport = lport->vport; + + if (!vport || vport->load_flag & FC_UNLOADING || + vport->phba->hba_flag & HBA_IOQ_FLUSH) + return -ENODEV; + qhandle = kzalloc(sizeof(struct lpfc_nvme_qhandle), GFP_KERNEL); if (qhandle == NULL) return -ENOMEM; @@ -267,7 +272,8 @@ lpfc_nvme_handle_lsreq(struct lpfc_hba *phba, return -EINVAL; remoteport = lpfc_rport->remoteport; - if (!vport->localport) + if (!vport->localport || + vport->phba->hba_flag & HBA_IOQ_FLUSH) return -EINVAL; lport = vport->localport->private; @@ -559,6 +565,8 @@ __lpfc_nvme_ls_req(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp->nlp_DID, ntype, nstate); return -ENODEV; } + if (vport->phba->hba_flag & HBA_IOQ_FLUSH) + return -ENODEV; if (!vport->phba->sli4_hba.nvmels_wq) return -ENOMEM; @@ -662,7 +670,8 @@ lpfc_nvme_ls_req(struct nvme_fc_local_port *pnvme_lport, return -EINVAL; vport = lport->vport; - if (vport->load_flag & FC_UNLOADING) + if (vport->load_flag & FC_UNLOADING || + vport->phba->hba_flag & HBA_IOQ_FLUSH) return -ENODEV; atomic_inc(&lport->fc4NvmeLsRequests); @@ -1516,7 +1525,8 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport, phba = vport->phba; - if (unlikely(vport->load_flag & FC_UNLOADING)) { + if ((unlikely(vport->load_flag & FC_UNLOADING)) || + phba->hba_flag & HBA_IOQ_FLUSH) { lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_IOERR, "6124 Fail IO, Driver unload\n"); atomic_inc(&lport->xmt_fcp_err); @@ -2169,8 +2179,7 @@ lpfc_nvme_lport_unreg_wait(struct lpfc_vport *vport, abts_nvme = 0; for (i = 0; i < phba->cfg_hdw_queue; i++) { qp = &phba->sli4_hba.hdwq[i]; - if (!vport || !vport->localport || - !qp || !qp->io_wq) + if (!vport->localport || !qp || !qp->io_wq) return; pring = qp->io_wq->pring; @@ -2180,8 +2189,9 @@ lpfc_nvme_lport_unreg_wait(struct lpfc_vport *vport, abts_scsi += qp->abts_scsi_io_bufs; abts_nvme += qp->abts_nvme_io_bufs; } - if (!vport || !vport->localport || - vport->phba->hba_flag & HBA_PCI_ERR) + if (!vport->localport || + test_bit(HBA_PCI_ERR, &vport->phba->bit_flags) || + vport->load_flag & FC_UNLOADING) return; lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, @@ -2541,8 +2551,7 @@ lpfc_nvme_unregister_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) * return values is ignored. The upcall is a courtesy to the * transport. */ - if (vport->load_flag & FC_UNLOADING || - unlikely(vport->phba->hba_flag & HBA_PCI_ERR)) + if (vport->load_flag & FC_UNLOADING) (void)nvme_fc_set_remoteport_devloss(remoteport, 0); ret = nvme_fc_unregister_remoteport(remoteport); diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 3c132604fd91..ba9dbb51b75f 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -5929,13 +5929,15 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) } lpfc_cmd->waitq = &waitq; - if (phba->sli_rev == LPFC_SLI_REV4) + if (phba->sli_rev == LPFC_SLI_REV4) { spin_unlock(&pring_s4->ring_lock); - else + ret_val = lpfc_sli4_issue_abort_iotag(phba, iocb, + lpfc_sli_abort_fcp_cmpl); + } else { pring = &phba->sli.sli3_ring[LPFC_FCP_RING]; - - ret_val = lpfc_sli_issue_abort_iotag(phba, pring, iocb, - lpfc_sli_abort_fcp_cmpl); + ret_val = lpfc_sli_issue_abort_iotag(phba, pring, iocb, + lpfc_sli_abort_fcp_cmpl); + } /* Make sure HBA is alive */ lpfc_issue_hb_tmo(phba); diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 20d40957a385..bda2a7ba4e77 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -2828,6 +2828,12 @@ __lpfc_sli_rpi_release(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) ndlp->nlp_flag &= ~NLP_UNREG_INP; } +void +lpfc_sli_rpi_release(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) +{ + __lpfc_sli_rpi_release(vport, ndlp); +} + /** * lpfc_sli_def_mbox_cmpl - Default mailbox completion handler * @phba: Pointer to HBA context object. @@ -3715,7 +3721,15 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, unsigned long iflag; u32 ulp_command, ulp_status, ulp_word4, ulp_context, iotag; + if (phba->sli_rev == LPFC_SLI_REV4) + spin_lock_irqsave(&pring->ring_lock, iflag); + else + spin_lock_irqsave(&phba->hbalock, iflag); cmdiocbp = lpfc_sli_iocbq_lookup(phba, pring, saveq); + if (phba->sli_rev == LPFC_SLI_REV4) + spin_unlock_irqrestore(&pring->ring_lock, iflag); + else + spin_unlock_irqrestore(&phba->hbalock, iflag); ulp_command = get_job_cmnd(phba, saveq); ulp_status = get_job_ulpstatus(phba, saveq); @@ -4052,10 +4066,8 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba, break; } - spin_unlock_irqrestore(&phba->hbalock, iflag); cmdiocbq = lpfc_sli_iocbq_lookup(phba, pring, &rspiocbq); - spin_lock_irqsave(&phba->hbalock, iflag); if (unlikely(!cmdiocbq)) break; if (cmdiocbq->cmd_flag & LPFC_DRIVER_ABORTED) @@ -4536,42 +4548,62 @@ lpfc_sli_handle_slow_ring_event_s4(struct lpfc_hba *phba, void lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) { - LIST_HEAD(completions); + LIST_HEAD(tx_completions); + LIST_HEAD(txcmplq_completions); struct lpfc_iocbq *iocb, *next_iocb; + int offline; if (pring->ringno == LPFC_ELS_RING) { lpfc_fabric_abort_hba(phba); } + offline = pci_channel_offline(phba->pcidev); /* Error everything on txq and txcmplq * First do the txq. */ if (phba->sli_rev >= LPFC_SLI_REV4) { spin_lock_irq(&pring->ring_lock); - list_splice_init(&pring->txq, &completions); + list_splice_init(&pring->txq, &tx_completions); pring->txq_cnt = 0; - spin_unlock_irq(&pring->ring_lock); - spin_lock_irq(&phba->hbalock); - /* Next issue ABTS for everything on the txcmplq */ - list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) - lpfc_sli_issue_abort_iotag(phba, pring, iocb, NULL); - spin_unlock_irq(&phba->hbalock); + if (offline) { + list_splice_init(&pring->txcmplq, + &txcmplq_completions); + } else { + /* Next issue ABTS for everything on the txcmplq */ + list_for_each_entry_safe(iocb, next_iocb, + &pring->txcmplq, list) + lpfc_sli_issue_abort_iotag(phba, pring, + iocb, NULL); + } + spin_unlock_irq(&pring->ring_lock); } else { spin_lock_irq(&phba->hbalock); - list_splice_init(&pring->txq, &completions); + list_splice_init(&pring->txq, &tx_completions); pring->txq_cnt = 0; - /* Next issue ABTS for everything on the txcmplq */ - list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) - lpfc_sli_issue_abort_iotag(phba, pring, iocb, NULL); + if (offline) { + list_splice_init(&pring->txcmplq, &txcmplq_completions); + } else { + /* Next issue ABTS for everything on the txcmplq */ + list_for_each_entry_safe(iocb, next_iocb, + &pring->txcmplq, list) + lpfc_sli_issue_abort_iotag(phba, pring, + iocb, NULL); + } spin_unlock_irq(&phba->hbalock); } - /* Make sure HBA is alive */ - lpfc_issue_hb_tmo(phba); + if (offline) { + /* Cancel all the IOCBs from the completions list */ + lpfc_sli_cancel_iocbs(phba, &txcmplq_completions, + IOSTAT_LOCAL_REJECT, IOERR_SLI_ABORTED); + } else { + /* Make sure HBA is alive */ + lpfc_issue_hb_tmo(phba); + } /* Cancel all the IOCBs from the completions list */ - lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, + lpfc_sli_cancel_iocbs(phba, &tx_completions, IOSTAT_LOCAL_REJECT, IOERR_SLI_ABORTED); } @@ -4624,11 +4656,6 @@ lpfc_sli_flush_io_rings(struct lpfc_hba *phba) struct lpfc_iocbq *piocb, *next_iocb; spin_lock_irq(&phba->hbalock); - if (phba->hba_flag & HBA_IOQ_FLUSH || - !phba->sli4_hba.hdwq) { - spin_unlock_irq(&phba->hbalock); - return; - } /* Indicate the I/O queues are flushed */ phba->hba_flag |= HBA_IOQ_FLUSH; spin_unlock_irq(&phba->hbalock); @@ -10997,6 +11024,10 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number, unsigned long iflags; int rc; + /* If the PCI channel is in offline state, do not post iocbs. */ + if (unlikely(pci_channel_offline(phba->pcidev))) + return IOCB_ERROR; + if (phba->sli_rev == LPFC_SLI_REV4) { lpfc_sli_prep_wqe(phba, piocb); diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index e52f37e5d896..a4d3259b8c52 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -20,7 +20,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "14.2.0.0" +#define LPFC_DRIVER_VERSION "14.2.0.1" #define LPFC_DRIVER_NAME "lpfc" /* Used for SLI 2/3 */ diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 611871ef15b5..4919ea54b827 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -2560,6 +2560,9 @@ struct megasas_instance_template { #define MEGASAS_IS_LOGICAL(sdev) \ ((sdev->channel < MEGASAS_MAX_PD_CHANNELS) ? 0 : 1) +#define MEGASAS_IS_LUN_VALID(sdev) \ + (((sdev)->lun == 0) ? 1 : 0) + #define MEGASAS_DEV_INDEX(scp) \ (((scp->device->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL) + \ scp->device->id) diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 8bf72dbc33b7..db6793608447 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -2126,6 +2126,9 @@ static int megasas_slave_alloc(struct scsi_device *sdev) goto scan_target; } return -ENXIO; + } else if (!MEGASAS_IS_LUN_VALID(sdev)) { + sdev_printk(KERN_INFO, sdev, "%s: invalid LUN\n", __func__); + return -ENXIO; } scan_target: @@ -2156,6 +2159,10 @@ static void megasas_slave_destroy(struct scsi_device *sdev) instance = megasas_lookup_instance(sdev->host->host_no); if (MEGASAS_IS_LOGICAL(sdev)) { + if (!MEGASAS_IS_LUN_VALID(sdev)) { + sdev_printk(KERN_INFO, sdev, "%s: invalid LUN\n", __func__); + return; + } ld_tgt_id = MEGASAS_TARGET_ID(sdev); instance->ld_tgtid_status[ld_tgt_id] = LD_TARGET_ID_DELETED; if (megasas_dbg_lvl & LD_PD_DEBUG) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index b57f1803371e..538d2c0cd971 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -5716,13 +5716,12 @@ _base_release_memory_pools(struct MPT3SAS_ADAPTER *ioc) /** * mpt3sas_check_same_4gb_region - checks whether all reply queues in a set are * having same upper 32bits in their base memory address. - * @reply_pool_start_address: Base address of a reply queue set + * @start_address: Base address of a reply queue set * @pool_sz: Size of single Reply Descriptor Post Queues pool size * * Return: 1 if reply queues in a set have a same upper 32bits in their base * memory address, else 0. */ - static int mpt3sas_check_same_4gb_region(dma_addr_t start_address, u32 pool_sz) { diff --git a/drivers/scsi/mpt3sas/mpt3sas_config.c b/drivers/scsi/mpt3sas/mpt3sas_config.c index 0563078227de..a8dd14c91efd 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_config.c +++ b/drivers/scsi/mpt3sas/mpt3sas_config.c @@ -394,10 +394,13 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t retry_count++; if (ioc->config_cmds.smid == smid) mpt3sas_base_free_smid(ioc, smid); - if ((ioc->shost_recovery) || (ioc->config_cmds.status & - MPT3_CMD_RESET) || ioc->pci_error_recovery) + if (ioc->config_cmds.status & MPT3_CMD_RESET) goto retry_config; - issue_host_reset = 1; + if (ioc->shost_recovery || ioc->pci_error_recovery) { + issue_host_reset = 0; + r = -EFAULT; + } else + issue_host_reset = 1; goto free_mem; } diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 00792767c620..7e476f50935b 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -11035,6 +11035,7 @@ _scsih_expander_node_remove(struct MPT3SAS_ADAPTER *ioc, { struct _sas_port *mpt3sas_port, *next; unsigned long flags; + int port_id; /* remove sibling ports attached to this expander */ list_for_each_entry_safe(mpt3sas_port, next, @@ -11055,6 +11056,8 @@ _scsih_expander_node_remove(struct MPT3SAS_ADAPTER *ioc, mpt3sas_port->hba_port); } + port_id = sas_expander->port->port_id; + mpt3sas_transport_port_remove(ioc, sas_expander->sas_address, sas_expander->sas_address_parent, sas_expander->port); @@ -11062,7 +11065,7 @@ _scsih_expander_node_remove(struct MPT3SAS_ADAPTER *ioc, "expander_remove: handle(0x%04x), sas_addr(0x%016llx), port:%d\n", sas_expander->handle, (unsigned long long) sas_expander->sas_address, - sas_expander->port->port_id); + port_id); spin_lock_irqsave(&ioc->sas_node_lock, flags); list_del(&sas_expander->list); diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c index 7ac63eb5ccd3..2fde496fff5f 100644 --- a/drivers/scsi/mvsas/mv_init.c +++ b/drivers/scsi/mvsas/mv_init.c @@ -647,6 +647,7 @@ static struct pci_device_id mvs_pci_table[] = { { PCI_VDEVICE(ARECA, PCI_DEVICE_ID_ARECA_1300), chip_1300 }, { PCI_VDEVICE(ARECA, PCI_DEVICE_ID_ARECA_1320), chip_1320 }, { PCI_VDEVICE(ADAPTEC2, 0x0450), chip_6440 }, + { PCI_VDEVICE(TTI, 0x2640), chip_6440 }, { PCI_VDEVICE(TTI, 0x2710), chip_9480 }, { PCI_VDEVICE(TTI, 0x2720), chip_9480 }, { PCI_VDEVICE(TTI, 0x2721), chip_9480 }, diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c index c4a838635893..5d7dfefd6f6c 100644 --- a/drivers/scsi/pcmcia/sym53c500_cs.c +++ b/drivers/scsi/pcmcia/sym53c500_cs.c @@ -192,10 +192,11 @@ struct sym53c500_data { int fast_pio; }; -static struct scsi_pointer *sym53c500_scsi_pointer(struct scsi_cmnd *cmd) -{ - return scsi_cmd_priv(cmd); -} +struct sym53c500_cmd_priv { + int status; + int message; + int phase; +}; enum Phase { idle, @@ -356,7 +357,7 @@ SYM53C500_intr(int irq, void *dev_id) struct sym53c500_data *data = (struct sym53c500_data *)dev->hostdata; struct scsi_cmnd *curSC = data->current_SC; - struct scsi_pointer *scsi_pointer = sym53c500_scsi_pointer(curSC); + struct sym53c500_cmd_priv *scp = scsi_cmd_priv(curSC); int fast_pio = data->fast_pio; spin_lock_irqsave(dev->host_lock, flags); @@ -403,12 +404,11 @@ SYM53C500_intr(int irq, void *dev_id) if (int_reg & 0x20) { /* Disconnect */ DEB(printk("SYM53C500: disconnect intr received\n")); - if (scsi_pointer->phase != message_in) { /* Unexpected disconnect */ + if (scp->phase != message_in) { /* Unexpected disconnect */ curSC->result = DID_NO_CONNECT << 16; } else { /* Command complete, return status and message */ - curSC->result = (scsi_pointer->Status & 0xff) | - ((scsi_pointer->Message & 0xff) << 8) | - (DID_OK << 16); + curSC->result = (scp->status & 0xff) | + ((scp->message & 0xff) << 8) | (DID_OK << 16); } goto idle_out; } @@ -419,7 +419,7 @@ SYM53C500_intr(int irq, void *dev_id) struct scatterlist *sg; int i; - scsi_pointer->phase = data_out; + scp->phase = data_out; VDEB(printk("SYM53C500: Data-Out phase\n")); outb(FLUSH_FIFO, port_base + CMD_REG); LOAD_DMA_COUNT(port_base, scsi_bufflen(curSC)); /* Max transfer size */ @@ -438,7 +438,7 @@ SYM53C500_intr(int irq, void *dev_id) struct scatterlist *sg; int i; - scsi_pointer->phase = data_in; + scp->phase = data_in; VDEB(printk("SYM53C500: Data-In phase\n")); outb(FLUSH_FIFO, port_base + CMD_REG); LOAD_DMA_COUNT(port_base, scsi_bufflen(curSC)); /* Max transfer size */ @@ -453,12 +453,12 @@ SYM53C500_intr(int irq, void *dev_id) break; case 0x02: /* COMMAND */ - scsi_pointer->phase = command_ph; + scp->phase = command_ph; printk("SYM53C500: Warning: Unknown interrupt occurred in command phase!\n"); break; case 0x03: /* STATUS */ - scsi_pointer->phase = status_ph; + scp->phase = status_ph; VDEB(printk("SYM53C500: Status phase\n")); outb(FLUSH_FIFO, port_base + CMD_REG); outb(INIT_CMD_COMPLETE, port_base + CMD_REG); @@ -471,24 +471,22 @@ SYM53C500_intr(int irq, void *dev_id) case 0x06: /* MESSAGE-OUT */ DEB(printk("SYM53C500: Message-Out phase\n")); - scsi_pointer->phase = message_out; + scp->phase = message_out; outb(SET_ATN, port_base + CMD_REG); /* Reject the message */ outb(MSG_ACCEPT, port_base + CMD_REG); break; case 0x07: /* MESSAGE-IN */ VDEB(printk("SYM53C500: Message-In phase\n")); - scsi_pointer->phase = message_in; + scp->phase = message_in; - scsi_pointer->Status = inb(port_base + SCSI_FIFO); - scsi_pointer->Message = inb(port_base + SCSI_FIFO); + scp->status = inb(port_base + SCSI_FIFO); + scp->message = inb(port_base + SCSI_FIFO); VDEB(printk("SCSI FIFO size=%d\n", inb(port_base + FIFO_FLAGS) & 0x1f)); - DEB(printk("Status = %02x Message = %02x\n", - scsi_pointer->Status, scsi_pointer->Message)); + DEB(printk("Status = %02x Message = %02x\n", scp->status, scp->message)); - if (scsi_pointer->Message == SAVE_POINTERS || - scsi_pointer->Message == DISCONNECT) { + if (scp->message == SAVE_POINTERS || scp->message == DISCONNECT) { outb(SET_ATN, port_base + CMD_REG); /* Reject message */ DEB(printk("Discarding SAVE_POINTERS message\n")); } @@ -500,7 +498,7 @@ out: return IRQ_HANDLED; idle_out: - scsi_pointer->phase = idle; + scp->phase = idle; scsi_done(curSC); goto out; } @@ -548,7 +546,7 @@ SYM53C500_info(struct Scsi_Host *SChost) static int SYM53C500_queue_lck(struct scsi_cmnd *SCpnt) { - struct scsi_pointer *scsi_pointer = sym53c500_scsi_pointer(SCpnt); + struct sym53c500_cmd_priv *scp = scsi_cmd_priv(SCpnt); int i; int port_base = SCpnt->device->host->io_port; struct sym53c500_data *data = @@ -565,9 +563,9 @@ static int SYM53C500_queue_lck(struct scsi_cmnd *SCpnt) VDEB(printk("\n")); data->current_SC = SCpnt; - scsi_pointer->phase = command_ph; - scsi_pointer->Status = 0; - scsi_pointer->Message = 0; + scp->phase = command_ph; + scp->status = 0; + scp->message = 0; /* We are locked here already by the mid layer */ REG0(port_base); @@ -682,7 +680,7 @@ static struct scsi_host_template sym53c500_driver_template = { .this_id = 7, .sg_tablesize = 32, .shost_groups = SYM53C500_shost_groups, - .cmd_size = sizeof(struct scsi_pointer), + .cmd_size = sizeof(struct sym53c500_cmd_priv), }; static int SYM53C500_config_check(struct pcmcia_device *p_dev, void *priv_data) diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index 928532180d32..fd674ed1febe 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -3182,124 +3182,6 @@ static int pmcraid_build_ioadl( } /** - * pmcraid_free_sglist - Frees an allocated SG buffer list - * @sglist: scatter/gather list pointer - * - * Free a DMA'able memory previously allocated with pmcraid_alloc_sglist - * - * Return value: - * none - */ -static void pmcraid_free_sglist(struct pmcraid_sglist *sglist) -{ - sgl_free_order(sglist->scatterlist, sglist->order); - kfree(sglist); -} - -/** - * pmcraid_alloc_sglist - Allocates memory for a SG list - * @buflen: buffer length - * - * Allocates a DMA'able buffer in chunks and assembles a scatter/gather - * list. - * - * Return value - * pointer to sglist / NULL on failure - */ -static struct pmcraid_sglist *pmcraid_alloc_sglist(int buflen) -{ - struct pmcraid_sglist *sglist; - int sg_size; - int order; - - sg_size = buflen / (PMCRAID_MAX_IOADLS - 1); - order = (sg_size > 0) ? get_order(sg_size) : 0; - - /* Allocate a scatter/gather list for the DMA */ - sglist = kzalloc(sizeof(struct pmcraid_sglist), GFP_KERNEL); - if (sglist == NULL) - return NULL; - - sglist->order = order; - sgl_alloc_order(buflen, order, false, GFP_KERNEL | __GFP_ZERO, - &sglist->num_sg); - - return sglist; -} - -/** - * pmcraid_copy_sglist - Copy user buffer to kernel buffer's SG list - * @sglist: scatter/gather list pointer - * @buffer: buffer pointer - * @len: buffer length - * @direction: data transfer direction - * - * Copy a user buffer into a buffer allocated by pmcraid_alloc_sglist - * - * Return value: - * 0 on success / other on failure - */ -static int pmcraid_copy_sglist( - struct pmcraid_sglist *sglist, - void __user *buffer, - u32 len, - int direction -) -{ - struct scatterlist *sg; - void *kaddr; - int bsize_elem; - int i; - int rc = 0; - - /* Determine the actual number of bytes per element */ - bsize_elem = PAGE_SIZE * (1 << sglist->order); - - sg = sglist->scatterlist; - - for (i = 0; i < (len / bsize_elem); i++, sg = sg_next(sg), buffer += bsize_elem) { - struct page *page = sg_page(sg); - - kaddr = kmap(page); - if (direction == DMA_TO_DEVICE) - rc = copy_from_user(kaddr, buffer, bsize_elem); - else - rc = copy_to_user(buffer, kaddr, bsize_elem); - - kunmap(page); - - if (rc) { - pmcraid_err("failed to copy user data into sg list\n"); - return -EFAULT; - } - - sg->length = bsize_elem; - } - - if (len % bsize_elem) { - struct page *page = sg_page(sg); - - kaddr = kmap(page); - - if (direction == DMA_TO_DEVICE) - rc = copy_from_user(kaddr, buffer, len % bsize_elem); - else - rc = copy_to_user(buffer, kaddr, len % bsize_elem); - - kunmap(page); - - sg->length = len % bsize_elem; - } - - if (rc) { - pmcraid_err("failed to copy user data into sg list\n"); - rc = -EFAULT; - } - - return rc; -} - -/** * pmcraid_queuecommand_lck - Queue a mid-layer request * @scsi_cmd: scsi command struct * @@ -3454,365 +3336,6 @@ static int pmcraid_chr_fasync(int fd, struct file *filep, int mode) return rc; } - -/** - * pmcraid_build_passthrough_ioadls - builds SG elements for passthrough - * commands sent over IOCTL interface - * - * @cmd : pointer to struct pmcraid_cmd - * @buflen : length of the request buffer - * @direction : data transfer direction - * - * Return value - * 0 on success, non-zero error code on failure - */ -static int pmcraid_build_passthrough_ioadls( - struct pmcraid_cmd *cmd, - int buflen, - int direction -) -{ - struct pmcraid_sglist *sglist = NULL; - struct scatterlist *sg = NULL; - struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; - struct pmcraid_ioadl_desc *ioadl; - int i; - - sglist = pmcraid_alloc_sglist(buflen); - - if (!sglist) { - pmcraid_err("can't allocate memory for passthrough SGls\n"); - return -ENOMEM; - } - - sglist->num_dma_sg = dma_map_sg(&cmd->drv_inst->pdev->dev, - sglist->scatterlist, - sglist->num_sg, direction); - - if (!sglist->num_dma_sg || sglist->num_dma_sg > PMCRAID_MAX_IOADLS) { - dev_err(&cmd->drv_inst->pdev->dev, - "Failed to map passthrough buffer!\n"); - pmcraid_free_sglist(sglist); - return -EIO; - } - - cmd->sglist = sglist; - ioarcb->request_flags0 |= NO_LINK_DESCS; - - ioadl = pmcraid_init_ioadls(cmd, sglist->num_dma_sg); - - /* Initialize IOADL descriptor addresses */ - for_each_sg(sglist->scatterlist, sg, sglist->num_dma_sg, i) { - ioadl[i].data_len = cpu_to_le32(sg_dma_len(sg)); - ioadl[i].address = cpu_to_le64(sg_dma_address(sg)); - ioadl[i].flags = 0; - } - - /* setup the last descriptor */ - ioadl[i - 1].flags = IOADL_FLAGS_LAST_DESC; - - return 0; -} - - -/** - * pmcraid_release_passthrough_ioadls - release passthrough ioadls - * - * @cmd: pointer to struct pmcraid_cmd for which ioadls were allocated - * @buflen: size of the request buffer - * @direction: data transfer direction - * - * Return value - * 0 on success, non-zero error code on failure - */ -static void pmcraid_release_passthrough_ioadls( - struct pmcraid_cmd *cmd, - int buflen, - int direction -) -{ - struct pmcraid_sglist *sglist = cmd->sglist; - - if (buflen > 0) { - dma_unmap_sg(&cmd->drv_inst->pdev->dev, - sglist->scatterlist, - sglist->num_sg, - direction); - pmcraid_free_sglist(sglist); - cmd->sglist = NULL; - } -} - -/** - * pmcraid_ioctl_passthrough - handling passthrough IOCTL commands - * - * @pinstance: pointer to adapter instance structure - * @ioctl_cmd: ioctl code - * @buflen: unused - * @arg: pointer to pmcraid_passthrough_buffer user buffer - * - * Return value - * 0 on success, non-zero error code on failure - */ -static long pmcraid_ioctl_passthrough( - struct pmcraid_instance *pinstance, - unsigned int ioctl_cmd, - unsigned int buflen, - void __user *arg -) -{ - struct pmcraid_passthrough_ioctl_buffer *buffer; - struct pmcraid_ioarcb *ioarcb; - struct pmcraid_cmd *cmd; - struct pmcraid_cmd *cancel_cmd; - void __user *request_buffer; - unsigned long request_offset; - unsigned long lock_flags; - void __user *ioasa; - u32 ioasc; - int request_size; - int buffer_size; - u8 direction; - int rc = 0; - - /* If IOA reset is in progress, wait 10 secs for reset to complete */ - if (pinstance->ioa_reset_in_progress) { - rc = wait_event_interruptible_timeout( - pinstance->reset_wait_q, - !pinstance->ioa_reset_in_progress, - msecs_to_jiffies(10000)); - - if (!rc) - return -ETIMEDOUT; - else if (rc < 0) - return -ERESTARTSYS; - } - - /* If adapter is not in operational state, return error */ - if (pinstance->ioa_state != IOA_STATE_OPERATIONAL) { - pmcraid_err("IOA is not operational\n"); - return -ENOTTY; - } - - buffer_size = sizeof(struct pmcraid_passthrough_ioctl_buffer); - buffer = kmalloc(buffer_size, GFP_KERNEL); - - if (!buffer) { - pmcraid_err("no memory for passthrough buffer\n"); - return -ENOMEM; - } - - request_offset = - offsetof(struct pmcraid_passthrough_ioctl_buffer, request_buffer); - - request_buffer = arg + request_offset; - - rc = copy_from_user(buffer, arg, - sizeof(struct pmcraid_passthrough_ioctl_buffer)); - - ioasa = arg + offsetof(struct pmcraid_passthrough_ioctl_buffer, ioasa); - - if (rc) { - pmcraid_err("ioctl: can't copy passthrough buffer\n"); - rc = -EFAULT; - goto out_free_buffer; - } - - request_size = le32_to_cpu(buffer->ioarcb.data_transfer_length); - - if (buffer->ioarcb.request_flags0 & TRANSFER_DIR_WRITE) { - direction = DMA_TO_DEVICE; - } else { - direction = DMA_FROM_DEVICE; - } - - if (request_size < 0) { - rc = -EINVAL; - goto out_free_buffer; - } - - /* check if we have any additional command parameters */ - if (le16_to_cpu(buffer->ioarcb.add_cmd_param_length) - > PMCRAID_ADD_CMD_PARAM_LEN) { - rc = -EINVAL; - goto out_free_buffer; - } - - cmd = pmcraid_get_free_cmd(pinstance); - - if (!cmd) { - pmcraid_err("free command block is not available\n"); - rc = -ENOMEM; - goto out_free_buffer; - } - - cmd->scsi_cmd = NULL; - ioarcb = &(cmd->ioa_cb->ioarcb); - - /* Copy the user-provided IOARCB stuff field by field */ - ioarcb->resource_handle = buffer->ioarcb.resource_handle; - ioarcb->data_transfer_length = buffer->ioarcb.data_transfer_length; - ioarcb->cmd_timeout = buffer->ioarcb.cmd_timeout; - ioarcb->request_type = buffer->ioarcb.request_type; - ioarcb->request_flags0 = buffer->ioarcb.request_flags0; - ioarcb->request_flags1 = buffer->ioarcb.request_flags1; - memcpy(ioarcb->cdb, buffer->ioarcb.cdb, PMCRAID_MAX_CDB_LEN); - - if (buffer->ioarcb.add_cmd_param_length) { - ioarcb->add_cmd_param_length = - buffer->ioarcb.add_cmd_param_length; - ioarcb->add_cmd_param_offset = - buffer->ioarcb.add_cmd_param_offset; - memcpy(ioarcb->add_data.u.add_cmd_params, - buffer->ioarcb.add_data.u.add_cmd_params, - le16_to_cpu(buffer->ioarcb.add_cmd_param_length)); - } - - /* set hrrq number where the IOA should respond to. Note that all cmds - * generated internally uses hrrq_id 0, exception to this is the cmd - * block of scsi_cmd which is re-used (e.g. cancel/abort), which uses - * hrrq_id assigned here in queuecommand - */ - ioarcb->hrrq_id = atomic_add_return(1, &(pinstance->last_message_id)) % - pinstance->num_hrrq; - - if (request_size) { - rc = pmcraid_build_passthrough_ioadls(cmd, - request_size, - direction); - if (rc) { - pmcraid_err("couldn't build passthrough ioadls\n"); - goto out_free_cmd; - } - } - - /* If data is being written into the device, copy the data from user - * buffers - */ - if (direction == DMA_TO_DEVICE && request_size > 0) { - rc = pmcraid_copy_sglist(cmd->sglist, - request_buffer, - request_size, - direction); - if (rc) { - pmcraid_err("failed to copy user buffer\n"); - goto out_free_sglist; - } - } - - /* passthrough ioctl is a blocking command so, put the user to sleep - * until timeout. Note that a timeout value of 0 means, do timeout. - */ - cmd->cmd_done = pmcraid_internal_done; - init_completion(&cmd->wait_for_completion); - cmd->completion_req = 1; - - pmcraid_info("command(%d) (CDB[0] = %x) for %x\n", - le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle) >> 2, - cmd->ioa_cb->ioarcb.cdb[0], - le32_to_cpu(cmd->ioa_cb->ioarcb.resource_handle)); - - spin_lock_irqsave(pinstance->host->host_lock, lock_flags); - _pmcraid_fire_command(cmd); - spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); - - /* NOTE ! Remove the below line once abort_task is implemented - * in firmware. This line disables ioctl command timeout handling logic - * similar to IO command timeout handling, making ioctl commands to wait - * until the command completion regardless of timeout value specified in - * ioarcb - */ - buffer->ioarcb.cmd_timeout = 0; - - /* If command timeout is specified put caller to wait till that time, - * otherwise it would be blocking wait. If command gets timed out, it - * will be aborted. - */ - if (buffer->ioarcb.cmd_timeout == 0) { - wait_for_completion(&cmd->wait_for_completion); - } else if (!wait_for_completion_timeout( - &cmd->wait_for_completion, - msecs_to_jiffies(le16_to_cpu(buffer->ioarcb.cmd_timeout) * 1000))) { - - pmcraid_info("aborting cmd %d (CDB[0] = %x) due to timeout\n", - le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle) >> 2, - cmd->ioa_cb->ioarcb.cdb[0]); - - spin_lock_irqsave(pinstance->host->host_lock, lock_flags); - cancel_cmd = pmcraid_abort_cmd(cmd); - spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); - - if (cancel_cmd) { - wait_for_completion(&cancel_cmd->wait_for_completion); - ioasc = le32_to_cpu(cancel_cmd->ioa_cb->ioasa.ioasc); - pmcraid_return_cmd(cancel_cmd); - - /* if abort task couldn't find the command i.e it got - * completed prior to aborting, return good completion. - * if command got aborted successfully or there was IOA - * reset due to abort task itself getting timedout then - * return -ETIMEDOUT - */ - if (ioasc == PMCRAID_IOASC_IOA_WAS_RESET || - PMCRAID_IOASC_SENSE_KEY(ioasc) == 0x00) { - if (ioasc != PMCRAID_IOASC_GC_IOARCB_NOTFOUND) - rc = -ETIMEDOUT; - goto out_handle_response; - } - } - - /* no command block for abort task or abort task failed to abort - * the IOARCB, then wait for 150 more seconds and initiate reset - * sequence after timeout - */ - if (!wait_for_completion_timeout( - &cmd->wait_for_completion, - msecs_to_jiffies(150 * 1000))) { - pmcraid_reset_bringup(cmd->drv_inst); - rc = -ETIMEDOUT; - } - } - -out_handle_response: - /* copy entire IOASA buffer and return IOCTL success. - * If copying IOASA to user-buffer fails, return - * EFAULT - */ - if (copy_to_user(ioasa, &cmd->ioa_cb->ioasa, - sizeof(struct pmcraid_ioasa))) { - pmcraid_err("failed to copy ioasa buffer to user\n"); - rc = -EFAULT; - } - - /* If the data transfer was from device, copy the data onto user - * buffers - */ - else if (direction == DMA_FROM_DEVICE && request_size > 0) { - rc = pmcraid_copy_sglist(cmd->sglist, - request_buffer, - request_size, - direction); - if (rc) { - pmcraid_err("failed to copy user buffer\n"); - rc = -EFAULT; - } - } - -out_free_sglist: - pmcraid_release_passthrough_ioadls(cmd, request_size, direction); - -out_free_cmd: - pmcraid_return_cmd(cmd); - -out_free_buffer: - kfree(buffer); - - return rc; -} - - - - /** * pmcraid_ioctl_driver - ioctl handler for commands handled by driver itself * @@ -3922,20 +3445,6 @@ static long pmcraid_chr_ioctl( switch (_IOC_TYPE(cmd)) { - case PMCRAID_PASSTHROUGH_IOCTL: - /* If ioctl code is to download microcode, we need to block - * mid-layer requests. - */ - if (cmd == PMCRAID_IOCTL_DOWNLOAD_MICROCODE) - scsi_block_requests(pinstance->host); - - retval = pmcraid_ioctl_passthrough(pinstance, cmd, - hdr->buffer_length, argp); - - if (cmd == PMCRAID_IOCTL_DOWNLOAD_MICROCODE) - scsi_unblock_requests(pinstance->host); - break; - case PMCRAID_DRIVER_IOCTL: arg += sizeof(struct pmcraid_ioctl_header); retval = pmcraid_ioctl_driver(pinstance, cmd, diff --git a/drivers/scsi/pmcraid.h b/drivers/scsi/pmcraid.h index bbb75318f1e7..9f59930e8b4f 100644 --- a/drivers/scsi/pmcraid.h +++ b/drivers/scsi/pmcraid.h @@ -1023,40 +1023,15 @@ struct pmcraid_ioctl_header { #define PMCRAID_IOCTL_SIGNATURE "PMCRAID" /* - * pmcraid_passthrough_ioctl_buffer - structure given as argument to - * passthrough(or firmware handled) IOCTL commands. Note that ioarcb requires - * 32-byte alignment so, it is necessary to pack this structure to avoid any - * holes between ioctl_header and passthrough buffer - * - * .ioactl_header : ioctl header - * .ioarcb : filled-up ioarcb buffer, driver always reads this buffer - * .ioasa : buffer for ioasa, driver fills this with IOASA from firmware - * .request_buffer: The I/O buffer (flat), driver reads/writes to this based on - * the transfer directions passed in ioarcb.flags0. Contents - * of this buffer are valid only when ioarcb.data_transfer_len - * is not zero. - */ -struct pmcraid_passthrough_ioctl_buffer { - struct pmcraid_ioctl_header ioctl_header; - struct pmcraid_ioarcb ioarcb; - struct pmcraid_ioasa ioasa; - u8 request_buffer[]; -} __attribute__ ((packed, aligned(PMCRAID_IOARCB_ALIGNMENT))); - -/* * keys to differentiate between driver handled IOCTLs and passthrough * IOCTLs passed to IOA. driver determines the ioctl type using macro * _IOC_TYPE */ #define PMCRAID_DRIVER_IOCTL 'D' -#define PMCRAID_PASSTHROUGH_IOCTL 'F' #define DRV_IOCTL(n, size) \ _IOC(_IOC_READ|_IOC_WRITE, PMCRAID_DRIVER_IOCTL, (n), (size)) -#define FMW_IOCTL(n, size) \ - _IOC(_IOC_READ|_IOC_WRITE, PMCRAID_PASSTHROUGH_IOCTL, (n), (size)) - /* * _ARGSIZE: macro that gives size of the argument type passed to an IOCTL cmd. * This is to facilitate applications avoiding un-necessary memory allocations. @@ -1069,12 +1044,4 @@ struct pmcraid_passthrough_ioctl_buffer { #define PMCRAID_IOCTL_RESET_ADAPTER \ DRV_IOCTL(5, sizeof(struct pmcraid_ioctl_header)) -/* passthrough/firmware handled commands */ -#define PMCRAID_IOCTL_PASSTHROUGH_COMMAND \ - FMW_IOCTL(1, sizeof(struct pmcraid_passthrough_ioctl_buffer)) - -#define PMCRAID_IOCTL_DOWNLOAD_MICROCODE \ - FMW_IOCTL(2, sizeof(struct pmcraid_passthrough_ioctl_buffer)) - - #endif /* _PMCRAID_H */ diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index c607755cce00..ff78ef702f22 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -7519,12 +7519,13 @@ static int sdebug_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num) struct sdebug_defer *sd_dp; sqp = sdebug_q_arr + queue_num; - qc_idx = find_first_bit(sqp->in_use_bm, sdebug_max_queue); - if (qc_idx >= sdebug_max_queue) - return 0; spin_lock_irqsave(&sqp->qc_lock, iflags); + qc_idx = find_first_bit(sqp->in_use_bm, sdebug_max_queue); + if (qc_idx >= sdebug_max_queue) + goto unlock; + for (first = true; first || qc_idx + 1 < sdebug_max_queue; ) { if (first) { first = false; @@ -7589,6 +7590,7 @@ static int sdebug_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num) break; } +unlock: spin_unlock_irqrestore(&sqp->qc_lock, iflags); if (num_entries > 0) diff --git a/drivers/scsi/scsi_logging.c b/drivers/scsi/scsi_logging.c index ff89de86545d..b02af340c2d3 100644 --- a/drivers/scsi/scsi_logging.c +++ b/drivers/scsi/scsi_logging.c @@ -30,7 +30,7 @@ static inline const char *scmd_name(const struct scsi_cmnd *scmd) { struct request *rq = scsi_cmd_to_rq((struct scsi_cmnd *)scmd); - if (!rq->q->disk) + if (!rq->q || !rq->q->disk) return NULL; return rq->q->disk->disk_name; } diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index f4e6c68ac99e..2ef78083f1ef 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -223,6 +223,8 @@ static int scsi_realloc_sdev_budget_map(struct scsi_device *sdev, int ret; struct sbitmap sb_backup; + depth = min_t(unsigned int, depth, scsi_device_max_queue_depth(sdev)); + /* * realloc if new shift is calculated, which is caused by setting * up one new default queue depth after calling ->slave_configure @@ -245,6 +247,9 @@ static int scsi_realloc_sdev_budget_map(struct scsi_device *sdev, scsi_device_max_queue_depth(sdev), new_shift, GFP_KERNEL, sdev->request_queue->node, false, true); + if (!ret) + sbitmap_resize(&sdev->budget_map, depth); + if (need_free) { if (ret) sdev->budget_map = sb_backup; diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 226a50944c00..dc6872e352bd 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -1384,10 +1384,6 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev) if (IS_ENABLED(CONFIG_BLK_DEV_BSG)) { sdev->bsg_dev = scsi_bsg_register_queue(sdev); if (IS_ERR(sdev->bsg_dev)) { - /* - * We're treating error on bsg register as non-fatal, so - * pretend nothing went wrong. - */ error = PTR_ERR(sdev->bsg_dev); sdev_printk(KERN_INFO, sdev, "Failed to register bsg queue, errno=%d\n", diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index a390679cf458..dc6e55761fd1 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -3216,6 +3216,7 @@ static int sd_revalidate_disk(struct gendisk *disk) sd_read_block_limits(sdkp); sd_read_block_characteristics(sdkp); sd_zbc_read_zones(sdkp, buffer); + sd_read_cpr(sdkp); } sd_print_capacity(sdkp, old_capacity); @@ -3225,7 +3226,6 @@ static int sd_revalidate_disk(struct gendisk *disk) sd_read_app_tag_own(sdkp, buffer); sd_read_write_same(sdkp, buffer); sd_read_security(sdkp, buffer); - sd_read_cpr(sdkp); } /* @@ -3475,6 +3475,7 @@ static int sd_probe(struct device *dev) error = device_add_disk(dev, gd, NULL); if (error) { put_device(&sdkp->disk_dev); + blk_cleanup_disk(gd); goto out; } diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 5ba9df334968..cbd92891a762 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -535,7 +535,7 @@ static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, scsi_autopm_get_device(sdev); - if (ret != CDROMCLOSETRAY && ret != CDROMEJECT) { + if (cmd != CDROMCLOSETRAY && cmd != CDROMEJECT) { ret = cdrom_ioctl(&cd->cdi, bdev, mode, cmd, arg); if (ret != -ENOSYS) goto put; diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index 0d2e950d0865..586c0e567ff9 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -957,18 +957,6 @@ static const struct reset_control_ops ufs_qcom_reset_ops = { .deassert = ufs_qcom_reset_deassert, }; -#define ANDROID_BOOT_DEV_MAX 30 -static char android_boot_dev[ANDROID_BOOT_DEV_MAX]; - -#ifndef MODULE -static int __init get_android_boot_dev(char *str) -{ - strlcpy(android_boot_dev, str, ANDROID_BOOT_DEV_MAX); - return 1; -} -__setup("androidboot.bootdevice=", get_android_boot_dev); -#endif - /** * ufs_qcom_init - bind phy with controller * @hba: host controller instance @@ -988,9 +976,6 @@ static int ufs_qcom_init(struct ufs_hba *hba) struct resource *res; struct ufs_clk_info *clki; - if (strlen(android_boot_dev) && strcmp(android_boot_dev, dev_name(dev))) - return -ENODEV; - host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL); if (!host) { err = -ENOMEM; diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c index f76692053ca1..e892b9feffb1 100644 --- a/drivers/scsi/ufs/ufshcd-pci.c +++ b/drivers/scsi/ufs/ufshcd-pci.c @@ -428,6 +428,12 @@ static int ufs_intel_adl_init(struct ufs_hba *hba) return ufs_intel_common_init(hba); } +static int ufs_intel_mtl_init(struct ufs_hba *hba) +{ + hba->caps |= UFSHCD_CAP_CRYPTO | UFSHCD_CAP_WB_EN; + return ufs_intel_common_init(hba); +} + static struct ufs_hba_variant_ops ufs_intel_cnl_hba_vops = { .name = "intel-pci", .init = ufs_intel_common_init, @@ -465,6 +471,16 @@ static struct ufs_hba_variant_ops ufs_intel_adl_hba_vops = { .device_reset = ufs_intel_device_reset, }; +static struct ufs_hba_variant_ops ufs_intel_mtl_hba_vops = { + .name = "intel-pci", + .init = ufs_intel_mtl_init, + .exit = ufs_intel_common_exit, + .hce_enable_notify = ufs_intel_hce_enable_notify, + .link_startup_notify = ufs_intel_link_startup_notify, + .resume = ufs_intel_resume, + .device_reset = ufs_intel_device_reset, +}; + #ifdef CONFIG_PM_SLEEP static int ufshcd_pci_restore(struct device *dev) { @@ -579,6 +595,7 @@ static const struct pci_device_id ufshcd_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x98FA), (kernel_ulong_t)&ufs_intel_lkf_hba_vops }, { PCI_VDEVICE(INTEL, 0x51FF), (kernel_ulong_t)&ufs_intel_adl_hba_vops }, { PCI_VDEVICE(INTEL, 0x54FF), (kernel_ulong_t)&ufs_intel_adl_hba_vops }, + { PCI_VDEVICE(INTEL, 0x7E47), (kernel_ulong_t)&ufs_intel_mtl_hba_vops }, { } /* terminate list */ }; diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 88c20f3608c2..94f545be183a 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -820,8 +820,6 @@ struct ufs_hba { enum ufs_pm_level rpm_lvl; /* Desired UFS power management level during system PM */ enum ufs_pm_level spm_lvl; - struct device_attribute rpm_lvl_attr; - struct device_attribute spm_lvl_attr; int pm_op_in_progress; /* Auto-Hibernate Idle Timer register value */ diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c index b2bec19022cd..81099b68bbfb 100644 --- a/drivers/scsi/ufs/ufshpb.c +++ b/drivers/scsi/ufs/ufshpb.c @@ -867,12 +867,6 @@ static struct ufshpb_region *ufshpb_victim_lru_info(struct ufshpb_lu *hpb) struct ufshpb_region *rgn, *victim_rgn = NULL; list_for_each_entry(rgn, &lru_info->lh_lru_rgn, list_lru_rgn) { - if (!rgn) { - dev_err(&hpb->sdev_ufs_lu->sdev_dev, - "%s: no region allocated\n", - __func__); - return NULL; - } if (ufshpb_check_srgns_issue_state(hpb, rgn)) continue; @@ -888,6 +882,11 @@ static struct ufshpb_region *ufshpb_victim_lru_info(struct ufshpb_lu *hpb) break; } + if (!victim_rgn) + dev_err(&hpb->sdev_ufs_lu->sdev_dev, + "%s: no region allocated\n", + __func__); + return victim_rgn; } diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c index 0e6110da69e7..578c4b6d0f7d 100644 --- a/drivers/scsi/virtio_scsi.c +++ b/drivers/scsi/virtio_scsi.c @@ -988,7 +988,7 @@ static struct virtio_driver virtio_scsi_driver = { .remove = virtscsi_remove, }; -static int __init init(void) +static int __init virtio_scsi_init(void) { int ret = -ENOMEM; @@ -1020,14 +1020,14 @@ error: return ret; } -static void __exit fini(void) +static void __exit virtio_scsi_fini(void) { unregister_virtio_driver(&virtio_scsi_driver); mempool_destroy(virtscsi_cmd_pool); kmem_cache_destroy(virtscsi_cmd_cache); } -module_init(init); -module_exit(fini); +module_init(virtio_scsi_init); +module_exit(virtio_scsi_fini); MODULE_DEVICE_TABLE(virtio, id_table); MODULE_DESCRIPTION("Virtio SCSI HBA driver"); diff --git a/drivers/scsi/zorro7xx.c b/drivers/scsi/zorro7xx.c index 27b9e2baab1a..7acf9193a9e8 100644 --- a/drivers/scsi/zorro7xx.c +++ b/drivers/scsi/zorro7xx.c @@ -159,6 +159,8 @@ static void zorro7xx_remove_one(struct zorro_dev *z) scsi_remove_host(host); NCR_700_release(host); + if (host->base > 0x01000000) + iounmap(hostdata->base); kfree(hostdata); free_irq(host->irq, host); zorro_release_device(z); diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c index 86c76211b3d3..cad2d55dcd3d 100644 --- a/drivers/spi/spi-bcm-qspi.c +++ b/drivers/spi/spi-bcm-qspi.c @@ -1205,7 +1205,7 @@ static int bcm_qspi_exec_mem_op(struct spi_mem *mem, addr = op->addr.val; len = op->data.nbytes; - if (bcm_qspi_bspi_ver_three(qspi) == true) { + if (has_bspi(qspi) && bcm_qspi_bspi_ver_three(qspi) == true) { /* * The address coming into this function is a raw flash offset. * But for BSPI <= V3, we need to convert it to a remapped BSPI @@ -1224,7 +1224,7 @@ static int bcm_qspi_exec_mem_op(struct spi_mem *mem, len < 4) mspi_read = true; - if (mspi_read) + if (!has_bspi(qspi) || mspi_read) return bcm_qspi_mspi_exec_mem_op(spi, op); ret = bcm_qspi_bspi_set_mode(qspi, op, 0); diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c index b0c9f62ccefb..616ada891974 100644 --- a/drivers/spi/spi-cadence-quadspi.c +++ b/drivers/spi/spi-cadence-quadspi.c @@ -19,6 +19,7 @@ #include <linux/iopoll.h> #include <linux/jiffies.h> #include <linux/kernel.h> +#include <linux/log2.h> #include <linux/module.h> #include <linux/of_device.h> #include <linux/of.h> @@ -102,12 +103,6 @@ struct cqspi_driver_platdata { #define CQSPI_TIMEOUT_MS 500 #define CQSPI_READ_TIMEOUT_MS 10 -/* Instruction type */ -#define CQSPI_INST_TYPE_SINGLE 0 -#define CQSPI_INST_TYPE_DUAL 1 -#define CQSPI_INST_TYPE_QUAD 2 -#define CQSPI_INST_TYPE_OCTAL 3 - #define CQSPI_DUMMY_CLKS_PER_BYTE 8 #define CQSPI_DUMMY_BYTES_MAX 4 #define CQSPI_DUMMY_CLKS_MAX 31 @@ -376,10 +371,6 @@ static unsigned int cqspi_calc_dummy(const struct spi_mem_op *op, bool dtr) static int cqspi_set_protocol(struct cqspi_flash_pdata *f_pdata, const struct spi_mem_op *op) { - f_pdata->inst_width = CQSPI_INST_TYPE_SINGLE; - f_pdata->addr_width = CQSPI_INST_TYPE_SINGLE; - f_pdata->data_width = CQSPI_INST_TYPE_SINGLE; - /* * For an op to be DTR, cmd phase along with every other non-empty * phase should have dtr field set to 1. If an op phase has zero @@ -389,32 +380,23 @@ static int cqspi_set_protocol(struct cqspi_flash_pdata *f_pdata, (!op->addr.nbytes || op->addr.dtr) && (!op->data.nbytes || op->data.dtr); - switch (op->data.buswidth) { - case 0: - break; - case 1: - f_pdata->data_width = CQSPI_INST_TYPE_SINGLE; - break; - case 2: - f_pdata->data_width = CQSPI_INST_TYPE_DUAL; - break; - case 4: - f_pdata->data_width = CQSPI_INST_TYPE_QUAD; - break; - case 8: - f_pdata->data_width = CQSPI_INST_TYPE_OCTAL; - break; - default: - return -EINVAL; - } + f_pdata->inst_width = 0; + if (op->cmd.buswidth) + f_pdata->inst_width = ilog2(op->cmd.buswidth); + + f_pdata->addr_width = 0; + if (op->addr.buswidth) + f_pdata->addr_width = ilog2(op->addr.buswidth); + + f_pdata->data_width = 0; + if (op->data.buswidth) + f_pdata->data_width = ilog2(op->data.buswidth); /* Right now we only support 8-8-8 DTR mode. */ if (f_pdata->dtr) { switch (op->cmd.buswidth) { case 0: - break; case 8: - f_pdata->inst_width = CQSPI_INST_TYPE_OCTAL; break; default: return -EINVAL; @@ -422,9 +404,7 @@ static int cqspi_set_protocol(struct cqspi_flash_pdata *f_pdata, switch (op->addr.buswidth) { case 0: - break; case 8: - f_pdata->addr_width = CQSPI_INST_TYPE_OCTAL; break; default: return -EINVAL; @@ -432,9 +412,7 @@ static int cqspi_set_protocol(struct cqspi_flash_pdata *f_pdata, switch (op->data.buswidth) { case 0: - break; case 8: - f_pdata->data_width = CQSPI_INST_TYPE_OCTAL; break; default: return -EINVAL; diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c index 55c092069301..65be8e085ab8 100644 --- a/drivers/spi/spi-mxic.c +++ b/drivers/spi/spi-mxic.c @@ -813,6 +813,7 @@ static int mxic_spi_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "spi_register_master failed\n"); pm_runtime_disable(&pdev->dev); + mxic_spi_mem_ecc_remove(mxic); } return ret; diff --git a/drivers/spi/spi-rpc-if.c b/drivers/spi/spi-rpc-if.c index fe82f3575df4..24ec1c83f379 100644 --- a/drivers/spi/spi-rpc-if.c +++ b/drivers/spi/spi-rpc-if.c @@ -158,14 +158,18 @@ static int rpcif_spi_probe(struct platform_device *pdev) error = rpcif_hw_init(rpc, false); if (error) - return error; + goto out_disable_rpm; error = spi_register_controller(ctlr); if (error) { dev_err(&pdev->dev, "spi_register_controller failed\n"); - rpcif_disable_rpm(rpc); + goto out_disable_rpm; } + return 0; + +out_disable_rpm: + rpcif_disable_rpm(rpc); return error; } diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index c4dd1200fe99..2e6d6bbeb784 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1130,11 +1130,15 @@ static int __spi_unmap_msg(struct spi_controller *ctlr, struct spi_message *msg) if (ctlr->dma_tx) tx_dev = ctlr->dma_tx->device->dev; + else if (ctlr->dma_map_dev) + tx_dev = ctlr->dma_map_dev; else tx_dev = ctlr->dev.parent; if (ctlr->dma_rx) rx_dev = ctlr->dma_rx->device->dev; + else if (ctlr->dma_map_dev) + rx_dev = ctlr->dma_map_dev; else rx_dev = ctlr->dev.parent; @@ -2406,7 +2410,8 @@ static int acpi_spi_add_resource(struct acpi_resource *ares, void *data) } else { struct acpi_device *adev; - if (acpi_bus_get_device(parent_handle, &adev)) + adev = acpi_fetch_acpi_dev(parent_handle); + if (!adev) return -ENODEV; ctlr = acpi_spi_find_controller_by_adev(adev); diff --git a/drivers/staging/r8188eu/core/rtw_br_ext.c b/drivers/staging/r8188eu/core/rtw_br_ext.c index d68611ef22f8..f056204c0fdb 100644 --- a/drivers/staging/r8188eu/core/rtw_br_ext.c +++ b/drivers/staging/r8188eu/core/rtw_br_ext.c @@ -70,7 +70,7 @@ static int __nat25_add_pppoe_tag(struct sk_buff *skb, struct pppoe_tag *tag) struct pppoe_hdr *ph = (struct pppoe_hdr *)(skb->data + ETH_HLEN); int data_len; - data_len = tag->tag_len + TAG_HDR_LEN; + data_len = be16_to_cpu(tag->tag_len) + TAG_HDR_LEN; if (skb_tailroom(skb) < data_len) return -1; diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 95d4ca50a605..fd7267baa707 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1821,6 +1821,7 @@ static struct page *tcmu_try_get_data_page(struct tcmu_dev *udev, uint32_t dpi) mutex_lock(&udev->cmdr_lock); page = xa_load(&udev->data_pages, dpi); if (likely(page)) { + get_page(page); mutex_unlock(&udev->cmdr_lock); return page; } @@ -1877,6 +1878,7 @@ static vm_fault_t tcmu_vma_fault(struct vm_fault *vmf) /* For the vmalloc()ed cmd area pages */ addr = (void *)(unsigned long)info->mem[mi].addr + offset; page = vmalloc_to_page(addr); + get_page(page); } else { uint32_t dpi; @@ -1887,7 +1889,6 @@ static vm_fault_t tcmu_vma_fault(struct vm_fault *vmf) return VM_FAULT_SIGBUS; } - get_page(page); vmf->page = page; return 0; } diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c index 8a6958377764..3acc0f185762 100644 --- a/drivers/tty/serial/mpc52xx_uart.c +++ b/drivers/tty/serial/mpc52xx_uart.c @@ -436,31 +436,31 @@ static void mpc512x_psc_fifo_init(struct uart_port *port) out_be32(&FIFO_512x(port)->rximr, MPC512x_PSC_FIFO_ALARM); } -static int mpc512x_psc_raw_rx_rdy(struct uart_port *port) +static unsigned int mpc512x_psc_raw_rx_rdy(struct uart_port *port) { return !(in_be32(&FIFO_512x(port)->rxsr) & MPC512x_PSC_FIFO_EMPTY); } -static int mpc512x_psc_raw_tx_rdy(struct uart_port *port) +static unsigned int mpc512x_psc_raw_tx_rdy(struct uart_port *port) { return !(in_be32(&FIFO_512x(port)->txsr) & MPC512x_PSC_FIFO_FULL); } -static int mpc512x_psc_rx_rdy(struct uart_port *port) +static unsigned int mpc512x_psc_rx_rdy(struct uart_port *port) { return in_be32(&FIFO_512x(port)->rxsr) & in_be32(&FIFO_512x(port)->rximr) & MPC512x_PSC_FIFO_ALARM; } -static int mpc512x_psc_tx_rdy(struct uart_port *port) +static unsigned int mpc512x_psc_tx_rdy(struct uart_port *port) { return in_be32(&FIFO_512x(port)->txsr) & in_be32(&FIFO_512x(port)->tximr) & MPC512x_PSC_FIFO_ALARM; } -static int mpc512x_psc_tx_empty(struct uart_port *port) +static unsigned int mpc512x_psc_tx_empty(struct uart_port *port) { return in_be32(&FIFO_512x(port)->txsr) & MPC512x_PSC_FIFO_EMPTY; @@ -780,29 +780,29 @@ static void mpc5125_psc_fifo_init(struct uart_port *port) out_be32(&FIFO_5125(port)->rximr, MPC512x_PSC_FIFO_ALARM); } -static int mpc5125_psc_raw_rx_rdy(struct uart_port *port) +static unsigned int mpc5125_psc_raw_rx_rdy(struct uart_port *port) { return !(in_be32(&FIFO_5125(port)->rxsr) & MPC512x_PSC_FIFO_EMPTY); } -static int mpc5125_psc_raw_tx_rdy(struct uart_port *port) +static unsigned int mpc5125_psc_raw_tx_rdy(struct uart_port *port) { return !(in_be32(&FIFO_5125(port)->txsr) & MPC512x_PSC_FIFO_FULL); } -static int mpc5125_psc_rx_rdy(struct uart_port *port) +static unsigned int mpc5125_psc_rx_rdy(struct uart_port *port) { return in_be32(&FIFO_5125(port)->rxsr) & in_be32(&FIFO_5125(port)->rximr) & MPC512x_PSC_FIFO_ALARM; } -static int mpc5125_psc_tx_rdy(struct uart_port *port) +static unsigned int mpc5125_psc_tx_rdy(struct uart_port *port) { return in_be32(&FIFO_5125(port)->txsr) & in_be32(&FIFO_5125(port)->tximr) & MPC512x_PSC_FIFO_ALARM; } -static int mpc5125_psc_tx_empty(struct uart_port *port) +static unsigned int mpc5125_psc_tx_empty(struct uart_port *port) { return in_be32(&FIFO_5125(port)->txsr) & MPC512x_PSC_FIFO_EMPTY; } diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index 2f4fb09f1e89..79001301b383 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -163,6 +163,7 @@ struct mlx5_vdpa_net { u32 cur_num_vqs; struct notifier_block nb; struct vdpa_callback config_cb; + struct mlx5_vdpa_wq_ent cvq_ent; }; static void free_resources(struct mlx5_vdpa_net *ndev); @@ -1658,6 +1659,12 @@ static void mlx5_cvq_kick_handler(struct work_struct *work) mvdev = wqent->mvdev; ndev = to_mlx5_vdpa_ndev(mvdev); cvq = &mvdev->cvq; + + mutex_lock(&ndev->reslock); + + if (!(mvdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) + goto out; + if (!(ndev->mvdev.actual_features & BIT_ULL(VIRTIO_NET_F_CTRL_VQ))) goto out; @@ -1696,9 +1703,13 @@ static void mlx5_cvq_kick_handler(struct work_struct *work) if (vringh_need_notify_iotlb(&cvq->vring)) vringh_notify(&cvq->vring); + + queue_work(mvdev->wq, &wqent->work); + break; } + out: - kfree(wqent); + mutex_unlock(&ndev->reslock); } static void mlx5_vdpa_kick_vq(struct vdpa_device *vdev, u16 idx) @@ -1706,7 +1717,6 @@ static void mlx5_vdpa_kick_vq(struct vdpa_device *vdev, u16 idx) struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); struct mlx5_vdpa_virtqueue *mvq; - struct mlx5_vdpa_wq_ent *wqent; if (!is_index_valid(mvdev, idx)) return; @@ -1715,13 +1725,7 @@ static void mlx5_vdpa_kick_vq(struct vdpa_device *vdev, u16 idx) if (!mvdev->wq || !mvdev->cvq.ready) return; - wqent = kzalloc(sizeof(*wqent), GFP_ATOMIC); - if (!wqent) - return; - - wqent->mvdev = mvdev; - INIT_WORK(&wqent->work, mlx5_cvq_kick_handler); - queue_work(mvdev->wq, &wqent->work); + queue_work(mvdev->wq, &ndev->cvq_ent.work); return; } @@ -2180,7 +2184,7 @@ static int mlx5_vdpa_change_map(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb goto err_mr; if (!(mvdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) - return 0; + goto err_mr; restore_channels_info(ndev); err = setup_driver(mvdev); @@ -2195,12 +2199,14 @@ err_mr: return err; } +/* reslock must be held for this function */ static int setup_driver(struct mlx5_vdpa_dev *mvdev) { struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); int err; - mutex_lock(&ndev->reslock); + WARN_ON(!mutex_is_locked(&ndev->reslock)); + if (ndev->setup) { mlx5_vdpa_warn(mvdev, "setup driver called for already setup driver\n"); err = 0; @@ -2230,7 +2236,6 @@ static int setup_driver(struct mlx5_vdpa_dev *mvdev) goto err_fwd; } ndev->setup = true; - mutex_unlock(&ndev->reslock); return 0; @@ -2241,23 +2246,23 @@ err_tir: err_rqt: teardown_virtqueues(ndev); out: - mutex_unlock(&ndev->reslock); return err; } +/* reslock must be held for this function */ static void teardown_driver(struct mlx5_vdpa_net *ndev) { - mutex_lock(&ndev->reslock); + + WARN_ON(!mutex_is_locked(&ndev->reslock)); + if (!ndev->setup) - goto out; + return; remove_fwd_to_tir(ndev); destroy_tir(ndev); destroy_rqt(ndev); teardown_virtqueues(ndev); ndev->setup = false; -out: - mutex_unlock(&ndev->reslock); } static void clear_vqs_ready(struct mlx5_vdpa_net *ndev) @@ -2278,6 +2283,8 @@ static void mlx5_vdpa_set_status(struct vdpa_device *vdev, u8 status) print_status(mvdev, status, true); + mutex_lock(&ndev->reslock); + if ((status ^ ndev->mvdev.status) & VIRTIO_CONFIG_S_DRIVER_OK) { if (status & VIRTIO_CONFIG_S_DRIVER_OK) { err = setup_driver(mvdev); @@ -2287,16 +2294,19 @@ static void mlx5_vdpa_set_status(struct vdpa_device *vdev, u8 status) } } else { mlx5_vdpa_warn(mvdev, "did not expect DRIVER_OK to be cleared\n"); - return; + goto err_clear; } } ndev->mvdev.status = status; + mutex_unlock(&ndev->reslock); return; err_setup: mlx5_vdpa_destroy_mr(&ndev->mvdev); ndev->mvdev.status |= VIRTIO_CONFIG_S_FAILED; +err_clear: + mutex_unlock(&ndev->reslock); } static int mlx5_vdpa_reset(struct vdpa_device *vdev) @@ -2306,6 +2316,8 @@ static int mlx5_vdpa_reset(struct vdpa_device *vdev) print_status(mvdev, 0, true); mlx5_vdpa_info(mvdev, "performing device reset\n"); + + mutex_lock(&ndev->reslock); teardown_driver(ndev); clear_vqs_ready(ndev); mlx5_vdpa_destroy_mr(&ndev->mvdev); @@ -2318,6 +2330,7 @@ static int mlx5_vdpa_reset(struct vdpa_device *vdev) if (mlx5_vdpa_create_mr(mvdev, NULL)) mlx5_vdpa_warn(mvdev, "create MR failed\n"); } + mutex_unlock(&ndev->reslock); return 0; } @@ -2353,19 +2366,24 @@ static u32 mlx5_vdpa_get_generation(struct vdpa_device *vdev) static int mlx5_vdpa_set_map(struct vdpa_device *vdev, struct vhost_iotlb *iotlb) { struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); + struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); bool change_map; int err; + mutex_lock(&ndev->reslock); + err = mlx5_vdpa_handle_set_map(mvdev, iotlb, &change_map); if (err) { mlx5_vdpa_warn(mvdev, "set map failed(%d)\n", err); - return err; + goto err; } if (change_map) - return mlx5_vdpa_change_map(mvdev, iotlb); + err = mlx5_vdpa_change_map(mvdev, iotlb); - return 0; +err: + mutex_unlock(&ndev->reslock); + return err; } static void mlx5_vdpa_free(struct vdpa_device *vdev) @@ -2740,6 +2758,8 @@ static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name, if (err) goto err_mr; + ndev->cvq_ent.mvdev = mvdev; + INIT_WORK(&ndev->cvq_ent.work, mlx5_cvq_kick_handler); mvdev->wq = create_singlethread_workqueue("mlx5_vdpa_wq"); if (!mvdev->wq) { err = -ENOMEM; diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index bdd00d381bbc..bc6ed750e915 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -1579,7 +1579,14 @@ static void do_remove_conflicting_framebuffers(struct apertures_struct *a, * If it's not a platform device, at least print a warning. A * fix would add code to remove the device from the system. */ - if (dev_is_platform(device)) { + if (!device) { + /* TODO: Represent each OF framebuffer as its own + * device in the device hierarchy. For now, offb + * doesn't have such a device, so unregister the + * framebuffer as before without warning. + */ + do_unregister_framebuffer(registered_fb[i]); + } else if (dev_is_platform(device)) { registered_fb[i]->forced_out = true; platform_device_unregister(to_platform_device(device)); } else { diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c index 75c8d560bbd3..22f15f444f75 100644 --- a/drivers/virtio/virtio.c +++ b/drivers/virtio/virtio.c @@ -526,9 +526,8 @@ int virtio_device_restore(struct virtio_device *dev) goto err; } - /* If restore didn't do it, mark device DRIVER_OK ourselves. */ - if (!(dev->config->get_status(dev) & VIRTIO_CONFIG_S_DRIVER_OK)) - virtio_device_ready(dev); + /* Finally, tell the device we're all set */ + virtio_add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK); virtio_config_enable(dev); |