From ca263dd848a26d243dca113469e6cff31a131bb6 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 10 May 2021 21:55:12 -0700 Subject: mei: Drop unnecessary NULL check after container_of The result of container_of() operations is never NULL unless the embedded element is the first element of the data structure, which is not the case here. The NULL check is therefore unnecessary and misleading. Remove it. This change was made automatically with the following Coccinelle script. @@ type t; identifier v; statement s; @@ <+... ( t v = container_of(...); | v = container_of(...); ) ... when != v - if (\( !v \| v == NULL \) ) s ...+> Acked-by: Tomas Winkler Signed-off-by: Guenter Roeck Link: https://lore.kernel.org/r/20210511045512.2376580-1-linux@roeck-us.net Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/main.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 28937b6e7e0c..9001c45f6fc4 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -50,8 +50,6 @@ static int mei_open(struct inode *inode, struct file *file) int err; dev = container_of(inode->i_cdev, struct mei_device, cdev); - if (!dev) - return -ENODEV; mutex_lock(&dev->device_lock); -- cgit v1.2.3 From da9db711733067b45ffbcd582387ad86369e2c62 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Wed, 5 May 2021 21:38:49 +0200 Subject: cxl: Fix an error message 'rc' is known to be 0 here. Initialize 'rc' with the expected error code before using it. While at it, avoid the affectation of 'rc' in a 'if' to make things more obvious and linux style. Fixes: f204e0b8cedd ("cxl: Driver code for powernv PCIe based cards for userspace access") Acked-by: Andrew Donnellan Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/fa2b2c9c72335ab4c3d5e6a33415e7f020b1d51b.1620243401.git.christophe.jaillet@wanadoo.fr Signed-off-by: Greg Kroah-Hartman --- drivers/misc/cxl/file.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/cxl/file.c b/drivers/misc/cxl/file.c index bd3bd32333c5..3dbdce96fae0 100644 --- a/drivers/misc/cxl/file.c +++ b/drivers/misc/cxl/file.c @@ -569,7 +569,8 @@ static int cxl_add_chardev(struct cxl_afu *afu, dev_t devt, struct cdev *cdev, int rc; cdev_init(cdev, fops); - if ((rc = cdev_add(cdev, devt, 1))) { + rc = cdev_add(cdev, devt, 1); + if (rc) { dev_err(&afu->dev, "Unable to add %s chardev: %i\n", desc, rc); return rc; } @@ -577,8 +578,8 @@ static int cxl_add_chardev(struct cxl_afu *afu, dev_t devt, struct cdev *cdev, dev = device_create(cxl_class, &afu->dev, devt, afu, "afu%i.%i%s", afu->adapter->adapter_num, afu->slice, postfix); if (IS_ERR(dev)) { - dev_err(&afu->dev, "Unable to create %s chardev in sysfs: %i\n", desc, rc); rc = PTR_ERR(dev); + dev_err(&afu->dev, "Unable to create %s chardev in sysfs: %i\n", desc, rc); goto err; } -- cgit v1.2.3 From 4a5ff99bbb8fcd4642995ef39bccc7f25e1f90d3 Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Tue, 11 May 2021 23:07:24 +0200 Subject: misc: eeprom_93xx46: Remove hardcoded bit lengths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This avoids using magic numbers based on the length of an address or a command, while we only want to differentiate between 8-bit and 16-bit. The driver was previously wrapping around the offset in the write operation, this now returns -EINVAL instead (but should never happen in the first place). If two pointer indirections are too many, we could move the flags to the main struct instead, but I doubt it’s going to make any sensible difference on any hardware. Reviewed-by: Jonathan Neuschäfer Signed-off-by: Emmanuel Gil Peyrot Link: https://lore.kernel.org/r/20210511210727.24895-2-linkmauve@linkmauve.fr Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/eeprom_93xx46.c | 57 +++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 25 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c index 80114f4c80ad..ffdb8e5a26e0 100644 --- a/drivers/misc/eeprom/eeprom_93xx46.c +++ b/drivers/misc/eeprom/eeprom_93xx46.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -70,6 +71,7 @@ static int eeprom_93xx46_read(void *priv, unsigned int off, struct eeprom_93xx46_dev *edev = priv; char *buf = val; int err = 0; + int bits; if (unlikely(off >= edev->size)) return 0; @@ -83,21 +85,21 @@ static int eeprom_93xx46_read(void *priv, unsigned int off, if (edev->pdata->prepare) edev->pdata->prepare(edev); + /* The opcode in front of the address is three bits. */ + bits = edev->addrlen + 3; + while (count) { struct spi_message m; struct spi_transfer t[2] = { { 0 } }; u16 cmd_addr = OP_READ << edev->addrlen; size_t nbytes = count; - int bits; - if (edev->addrlen == 7) { - cmd_addr |= off & 0x7f; - bits = 10; + if (edev->pdata->flags & EE_ADDR8) { + cmd_addr |= off; if (has_quirk_single_word_read(edev)) nbytes = 1; } else { - cmd_addr |= (off >> 1) & 0x3f; - bits = 9; + cmd_addr |= (off >> 1); if (has_quirk_single_word_read(edev)) nbytes = 2; } @@ -152,14 +154,14 @@ static int eeprom_93xx46_ew(struct eeprom_93xx46_dev *edev, int is_on) int bits, ret; u16 cmd_addr; + /* The opcode in front of the address is three bits. */ + bits = edev->addrlen + 3; + cmd_addr = OP_START << edev->addrlen; - if (edev->addrlen == 7) { + if (edev->pdata->flags & EE_ADDR8) cmd_addr |= (is_on ? ADDR_EWEN : ADDR_EWDS) << 1; - bits = 10; - } else { + else cmd_addr |= (is_on ? ADDR_EWEN : ADDR_EWDS); - bits = 9; - } if (has_quirk_instruction_length(edev)) { cmd_addr <<= 2; @@ -205,15 +207,19 @@ eeprom_93xx46_write_word(struct eeprom_93xx46_dev *edev, int bits, data_len, ret; u16 cmd_addr; + if (unlikely(off >= edev->size)) + return -EINVAL; + + /* The opcode in front of the address is three bits. */ + bits = edev->addrlen + 3; + cmd_addr = OP_WRITE << edev->addrlen; - if (edev->addrlen == 7) { - cmd_addr |= off & 0x7f; - bits = 10; + if (edev->pdata->flags & EE_ADDR8) { + cmd_addr |= off; data_len = 1; } else { - cmd_addr |= (off >> 1) & 0x3f; - bits = 9; + cmd_addr |= (off >> 1); data_len = 2; } @@ -253,7 +259,7 @@ static int eeprom_93xx46_write(void *priv, unsigned int off, return count; /* only write even number of bytes on 16-bit devices */ - if (edev->addrlen == 6) { + if (edev->pdata->flags & EE_ADDR16) { step = 2; count &= ~1; } @@ -295,14 +301,14 @@ static int eeprom_93xx46_eral(struct eeprom_93xx46_dev *edev) int bits, ret; u16 cmd_addr; + /* The opcode in front of the address is three bits. */ + bits = edev->addrlen + 3; + cmd_addr = OP_START << edev->addrlen; - if (edev->addrlen == 7) { + if (edev->pdata->flags & EE_ADDR8) cmd_addr |= ADDR_ERAL << 1; - bits = 10; - } else { + else cmd_addr |= ADDR_ERAL; - bits = 9; - } if (has_quirk_instruction_length(edev)) { cmd_addr <<= 2; @@ -455,10 +461,12 @@ static int eeprom_93xx46_probe(struct spi_device *spi) if (!edev) return -ENOMEM; + edev->size = 128; + if (pd->flags & EE_ADDR8) - edev->addrlen = 7; + edev->addrlen = ilog2(edev->size); else if (pd->flags & EE_ADDR16) - edev->addrlen = 6; + edev->addrlen = ilog2(edev->size) - 1; else { dev_err(&spi->dev, "unspecified address type\n"); return -EINVAL; @@ -469,7 +477,6 @@ static int eeprom_93xx46_probe(struct spi_device *spi) edev->spi = spi; edev->pdata = pd; - edev->size = 128; edev->nvmem_config.type = NVMEM_TYPE_EEPROM; edev->nvmem_config.name = dev_name(&spi->dev); edev->nvmem_config.dev = &spi->dev; -- cgit v1.2.3 From 14374fbb3f06ddaba186d608a58c07f3d48d08df Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Tue, 11 May 2021 23:07:25 +0200 Subject: misc: eeprom_93xx46: Add new 93c56 and 93c66 compatible strings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These two devices have respectively 2048 and 4096 bits of storage, compared to 1024 for the 93c46. Reviewed-by: Jonathan Neuschäfer Signed-off-by: Emmanuel Gil Peyrot Link: https://lore.kernel.org/r/20210511210727.24895-3-linkmauve@linkmauve.fr Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/eeprom_93xx46.c | 35 ++++++++++++++++++++++++++++++++--- include/linux/eeprom_93xx46.h | 3 +++ 2 files changed, 35 insertions(+), 3 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c index ffdb8e5a26e0..29d8971ec558 100644 --- a/drivers/misc/eeprom/eeprom_93xx46.c +++ b/drivers/misc/eeprom/eeprom_93xx46.c @@ -29,14 +29,29 @@ struct eeprom_93xx46_devtype_data { unsigned int quirks; + unsigned char flags; +}; + +static const struct eeprom_93xx46_devtype_data at93c46_data = { + .flags = EE_SIZE1K, +}; + +static const struct eeprom_93xx46_devtype_data at93c56_data = { + .flags = EE_SIZE2K, +}; + +static const struct eeprom_93xx46_devtype_data at93c66_data = { + .flags = EE_SIZE4K, }; static const struct eeprom_93xx46_devtype_data atmel_at93c46d_data = { + .flags = EE_SIZE1K, .quirks = EEPROM_93XX46_QUIRK_SINGLE_WORD_READ | EEPROM_93XX46_QUIRK_INSTRUCTION_LENGTH, }; static const struct eeprom_93xx46_devtype_data microchip_93lc46b_data = { + .flags = EE_SIZE1K, .quirks = EEPROM_93XX46_QUIRK_EXTRA_READ_CYCLE, }; @@ -381,8 +396,11 @@ static void select_deassert(void *context) } static const struct of_device_id eeprom_93xx46_of_table[] = { - { .compatible = "eeprom-93xx46", }, + { .compatible = "eeprom-93xx46", .data = &at93c46_data, }, + { .compatible = "atmel,at93c46", .data = &at93c46_data, }, { .compatible = "atmel,at93c46d", .data = &atmel_at93c46d_data, }, + { .compatible = "atmel,at93c56", .data = &at93c56_data, }, + { .compatible = "atmel,at93c66", .data = &at93c66_data, }, { .compatible = "microchip,93lc46b", .data = µchip_93lc46b_data, }, {} }; @@ -432,6 +450,7 @@ static int eeprom_93xx46_probe_dt(struct spi_device *spi) const struct eeprom_93xx46_devtype_data *data = of_id->data; pd->quirks = data->quirks; + pd->flags |= data->flags; } spi->dev.platform_data = pd; @@ -461,7 +480,16 @@ static int eeprom_93xx46_probe(struct spi_device *spi) if (!edev) return -ENOMEM; - edev->size = 128; + if (pd->flags & EE_SIZE1K) + edev->size = 128; + else if (pd->flags & EE_SIZE2K) + edev->size = 256; + else if (pd->flags & EE_SIZE4K) + edev->size = 512; + else { + dev_err(&spi->dev, "unspecified size\n"); + return -EINVAL; + } if (pd->flags & EE_ADDR8) edev->addrlen = ilog2(edev->size); @@ -496,8 +524,9 @@ static int eeprom_93xx46_probe(struct spi_device *spi) if (IS_ERR(edev->nvmem)) return PTR_ERR(edev->nvmem); - dev_info(&spi->dev, "%d-bit eeprom %s\n", + dev_info(&spi->dev, "%d-bit eeprom containing %d bytes %s\n", (pd->flags & EE_ADDR8) ? 8 : 16, + edev->size, (pd->flags & EE_READONLY) ? "(readonly)" : ""); if (!(pd->flags & EE_READONLY)) { diff --git a/include/linux/eeprom_93xx46.h b/include/linux/eeprom_93xx46.h index 99580c22f91a..34c2175e6a1e 100644 --- a/include/linux/eeprom_93xx46.h +++ b/include/linux/eeprom_93xx46.h @@ -10,6 +10,9 @@ struct eeprom_93xx46_platform_data { #define EE_ADDR8 0x01 /* 8 bit addr. cfg */ #define EE_ADDR16 0x02 /* 16 bit addr. cfg */ #define EE_READONLY 0x08 /* forbid writing */ +#define EE_SIZE1K 0x10 /* 1 kb of data, that is a 93xx46 */ +#define EE_SIZE2K 0x20 /* 2 kb of data, that is a 93xx56 */ +#define EE_SIZE4K 0x40 /* 4 kb of data, that is a 93xx66 */ unsigned int quirks; /* Single word read transfers only; no sequential read. */ -- cgit v1.2.3 From 7272b591c4cb9327c43443f67b8fbae7657dd9ae Mon Sep 17 00:00:00 2001 From: Lv Yunlong Date: Mon, 26 Apr 2021 10:06:20 -0700 Subject: misc/libmasm/module: Fix two use after free in ibmasm_init_one In ibmasm_init_one, it calls ibmasm_init_remote_input_dev(). Inside ibmasm_init_remote_input_dev, mouse_dev and keybd_dev are allocated by input_allocate_device(), and assigned to sp->remote.mouse_dev and sp->remote.keybd_dev respectively. In the err_free_devices error branch of ibmasm_init_one, mouse_dev and keybd_dev are freed by input_free_device(), and return error. Then the execution runs into error_send_message error branch of ibmasm_init_one, where ibmasm_free_remote_input_dev(sp) is called to unregister the freed sp->remote.mouse_dev and sp->remote.keybd_dev. My patch add a "error_init_remote" label to handle the error of ibmasm_init_remote_input_dev(), to avoid the uaf bugs. Signed-off-by: Lv Yunlong Link: https://lore.kernel.org/r/20210426170620.10546-1-lyl2019@mail.ustc.edu.cn Signed-off-by: Greg Kroah-Hartman --- drivers/misc/ibmasm/module.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/ibmasm/module.c b/drivers/misc/ibmasm/module.c index 4edad6c445d3..dc8a06c06c63 100644 --- a/drivers/misc/ibmasm/module.c +++ b/drivers/misc/ibmasm/module.c @@ -111,7 +111,7 @@ static int ibmasm_init_one(struct pci_dev *pdev, const struct pci_device_id *id) result = ibmasm_init_remote_input_dev(sp); if (result) { dev_err(sp->dev, "Failed to initialize remote queue\n"); - goto error_send_message; + goto error_init_remote; } result = ibmasm_send_driver_vpd(sp); @@ -131,8 +131,9 @@ static int ibmasm_init_one(struct pci_dev *pdev, const struct pci_device_id *id) return 0; error_send_message: - disable_sp_interrupts(sp->base_address); ibmasm_free_remote_input_dev(sp); +error_init_remote: + disable_sp_interrupts(sp->base_address); free_irq(sp->irq, (void *)sp); error_request_irq: iounmap(sp->base_address); -- cgit v1.2.3 From 3ce3e45cc333da707d4d6eb433574b990bcc26f5 Mon Sep 17 00:00:00 2001 From: Tong Zhang Date: Thu, 13 May 2021 00:07:33 -0400 Subject: misc: alcor_pci: fix null-ptr-deref when there is no PCI bridge There is an issue with the ASPM(optional) capability checking function. A device might be attached to root complex directly, in this case, bus->self(bridge) will be NULL, thus priv->parent_pdev is NULL. Since alcor_pci_init_check_aspm(priv->parent_pdev) checks the PCI link's ASPM capability and populate parent_cap_off, which will be used later by alcor_pci_aspm_ctrl() to dynamically turn on/off device, what we can do here is to avoid checking the capability if we are on the root complex. This will make pdev_cap_off 0 and alcor_pci_aspm_ctrl() will simply return when bring called, effectively disable ASPM for the device. [ 1.246492] BUG: kernel NULL pointer dereference, address: 00000000000000c0 [ 1.248731] RIP: 0010:pci_read_config_byte+0x5/0x40 [ 1.253998] Call Trace: [ 1.254131] ? alcor_pci_find_cap_offset.isra.0+0x3a/0x100 [alcor_pci] [ 1.254476] alcor_pci_probe+0x169/0x2d5 [alcor_pci] Co-developed-by: Greg Kroah-Hartman Signed-off-by: Tong Zhang Link: https://lore.kernel.org/r/20210513040732.1310159-1-ztong0001@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/cardreader/alcor_pci.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/cardreader/alcor_pci.c b/drivers/misc/cardreader/alcor_pci.c index cd402c89189e..0a62307f7ffb 100644 --- a/drivers/misc/cardreader/alcor_pci.c +++ b/drivers/misc/cardreader/alcor_pci.c @@ -139,7 +139,13 @@ static void alcor_pci_init_check_aspm(struct alcor_pci_priv *priv) u32 val32; priv->pdev_cap_off = alcor_pci_find_cap_offset(priv, priv->pdev); - priv->parent_cap_off = alcor_pci_find_cap_offset(priv, + /* + * A device might be attached to root complex directly and + * priv->parent_pdev will be NULL. In this case we don't check its + * capability and disable ASPM completely. + */ + if (!priv->parent_pdev) + priv->parent_cap_off = alcor_pci_find_cap_offset(priv, priv->parent_pdev); if ((priv->pdev_cap_off == 0) || (priv->parent_cap_off == 0)) { -- cgit v1.2.3 From 208012f051636d1ab8b7f7f86d6988d4b39758af Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 14 May 2021 18:08:01 -0500 Subject: misc: bcm-vk: Replace zero-length array with flexible array member MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is a regular need in the kernel to provide a way to declare having a dynamically sized set of trailing elements in a structure. Kernel code should always use “flexible array members”[1] for these cases. The older style of one-element or zero-length arrays should no longer be used[2]. Also, make use of the struct_size() helper in kzalloc(). [1] https://en.wikipedia.org/wiki/Flexible_array_member [2] https://www.kernel.org/doc/html/v5.10/process/deprecated.html#zero-length-and-one-element-arrays Acked-by: Scott Branden Signed-off-by: Gustavo A. R. Silva Link: https://lore.kernel.org/r/20210514230801.GA35863@embeddedor Signed-off-by: Greg Kroah-Hartman --- drivers/misc/bcm-vk/bcm_vk_msg.c | 3 +-- drivers/misc/bcm-vk/bcm_vk_msg.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/bcm-vk/bcm_vk_msg.c b/drivers/misc/bcm-vk/bcm_vk_msg.c index f40cf08a6192..6efc52b49af6 100644 --- a/drivers/misc/bcm-vk/bcm_vk_msg.c +++ b/drivers/misc/bcm-vk/bcm_vk_msg.c @@ -701,8 +701,7 @@ int bcm_vk_send_shutdown_msg(struct bcm_vk *vk, u32 shut_type, return -EINVAL; } - entry = kzalloc(sizeof(*entry) + - sizeof(struct vk_msg_blk), GFP_KERNEL); + entry = kzalloc(struct_size(entry, to_v_msg, 1), GFP_KERNEL); if (!entry) return -ENOMEM; diff --git a/drivers/misc/bcm-vk/bcm_vk_msg.h b/drivers/misc/bcm-vk/bcm_vk_msg.h index 4eaad84825d6..56784c8896d8 100644 --- a/drivers/misc/bcm-vk/bcm_vk_msg.h +++ b/drivers/misc/bcm-vk/bcm_vk_msg.h @@ -116,7 +116,7 @@ struct bcm_vk_wkent { u32 usr_msg_id; u32 to_v_blks; u32 seq_num; - struct vk_msg_blk to_v_msg[0]; + struct vk_msg_blk to_v_msg[]; }; /* queue stats counters */ -- cgit v1.2.3 From b63866efa10ca5e4497f17eb3e3a03dc6929c49e Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 19 May 2021 18:34:27 +0200 Subject: eeprom: ee1004: Let device core handle attribute eeprom Instead of creating/removing the attribute ourselves, just declare the attribute and let the device core handle it. This allows to simplify the code. Signed-off-by: Heiner Kallweit Link: https://lore.kernel.org/r/8a6c77f2-f84a-311b-c2b9-21798f690e4d@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/ee1004.c | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/eeprom/ee1004.c b/drivers/misc/eeprom/ee1004.c index 252e15ba65e1..0950d4d9d9ce 100644 --- a/drivers/misc/eeprom/ee1004.c +++ b/drivers/misc/eeprom/ee1004.c @@ -89,7 +89,7 @@ static ssize_t ee1004_eeprom_read(struct i2c_client *client, char *buf, return status; } -static ssize_t ee1004_read(struct file *filp, struct kobject *kobj, +static ssize_t eeprom_read(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { @@ -160,15 +160,15 @@ static ssize_t ee1004_read(struct file *filp, struct kobject *kobj, return requested; } -static const struct bin_attribute eeprom_attr = { - .attr = { - .name = "eeprom", - .mode = 0444, - }, - .size = EE1004_EEPROM_SIZE, - .read = ee1004_read, +static BIN_ATTR_RO(eeprom, EE1004_EEPROM_SIZE); + +static struct bin_attribute *ee1004_attrs[] = { + &bin_attr_eeprom, + NULL }; +BIN_ATTRIBUTE_GROUPS(ee1004); + static int ee1004_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -222,11 +222,6 @@ static int ee1004_probe(struct i2c_client *client, ee1004_current_page); mutex_unlock(&ee1004_bus_lock); - /* Create the sysfs eeprom file */ - err = sysfs_create_bin_file(&client->dev.kobj, &eeprom_attr); - if (err) - goto err_clients_lock; - dev_info(&client->dev, "%u byte EE1004-compliant SPD EEPROM, read-only\n", EE1004_EEPROM_SIZE); @@ -237,8 +232,6 @@ static int ee1004_probe(struct i2c_client *client, return 0; - err_clients_lock: - mutex_lock(&ee1004_bus_lock); err_clients: if (--ee1004_dev_count == 0) { for (cnr--; cnr >= 0; cnr--) { @@ -255,8 +248,6 @@ static int ee1004_remove(struct i2c_client *client) { int i; - sysfs_remove_bin_file(&client->dev.kobj, &eeprom_attr); - /* Remove page select clients if this is the last device */ mutex_lock(&ee1004_bus_lock); if (--ee1004_dev_count == 0) { @@ -275,6 +266,7 @@ static int ee1004_remove(struct i2c_client *client) static struct i2c_driver ee1004_driver = { .driver = { .name = "ee1004", + .dev_groups = ee1004_groups, }, .probe = ee1004_probe, .remove = ee1004_remove, -- cgit v1.2.3 From 78429edfeed8da0562243e876be46d700f9ed13c Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 21 May 2021 13:04:57 -0700 Subject: misc: xilinx-sdfec: Drop unnecessary NULL check after container_of container_of() only returns NULL if the passed pointer is NULL _and_ if the embedded element is the first element of the structure. Even if that is the case, testing against it is misleading and possibly dangerous because the position of the embedded element may change. In this case, the check is unnecessary since it is known that file->private_data is never NULL for an open file, and container_of() will therefore also never be NULL. Drop the check. Acked-by: Dragan Cvetic Signed-off-by: Guenter Roeck Link: https://lore.kernel.org/r/20210521200457.2112041-1-linux@roeck-us.net Signed-off-by: Greg Kroah-Hartman --- drivers/misc/xilinx_sdfec.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/xilinx_sdfec.c b/drivers/misc/xilinx_sdfec.c index 23c8448a9c3b..d6e3c650bd11 100644 --- a/drivers/misc/xilinx_sdfec.c +++ b/drivers/misc/xilinx_sdfec.c @@ -1013,9 +1013,6 @@ static __poll_t xsdfec_poll(struct file *file, poll_table *wait) xsdfec = container_of(file->private_data, struct xsdfec_dev, miscdev); - if (!xsdfec) - return EPOLLNVAL | EPOLLHUP; - poll_wait(file, &xsdfec->waitq, wait); /* XSDFEC ISR detected an error */ -- cgit v1.2.3 From 281e468446994a7672733af2bf941f4110d4a895 Mon Sep 17 00:00:00 2001 From: Tong Zhang Date: Sat, 22 May 2021 00:37:25 -0400 Subject: misc: alcor_pci: fix inverted branch condition This patch fixes a trivial mistake that I made in the previous attempt in fixing the null bridge issue. The branch condition is inverted and we should call alcor_pci_find_cap_offset() only if bridge is not null. Reported-by: Colin Ian King Fixes: 3ce3e45cc333 ("misc: alcor_pci: fix null-ptr-deref when there is no PCI bridge") Signed-off-by: Tong Zhang Link: https://lore.kernel.org/r/20210522043725.602179-1-ztong0001@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/cardreader/alcor_pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/cardreader/alcor_pci.c b/drivers/misc/cardreader/alcor_pci.c index 0a62307f7ffb..de6d44a158bb 100644 --- a/drivers/misc/cardreader/alcor_pci.c +++ b/drivers/misc/cardreader/alcor_pci.c @@ -144,7 +144,7 @@ static void alcor_pci_init_check_aspm(struct alcor_pci_priv *priv) * priv->parent_pdev will be NULL. In this case we don't check its * capability and disable ASPM completely. */ - if (!priv->parent_pdev) + if (priv->parent_pdev) priv->parent_cap_off = alcor_pci_find_cap_offset(priv, priv->parent_pdev); -- cgit v1.2.3 From 372dae89972594393b57f29ec44e351fa7eedbbe Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 22 May 2021 08:54:33 +0200 Subject: misc/pvpanic-pci: Fix error handling in 'pvpanic_pci_probe()' There is no error handling path in the probe function. Switch to managed resource so that errors in the probe are handled easily and simplify the remove function accordingly. Fixes: db3a4f0abefd ("misc/pvpanic: add PCI driver") Reviewed-by: Andy Shevchenko Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/ab071b1f4ed6e1174f9199095fb16a58bb406090.1621665058.git.christophe.jaillet@wanadoo.fr Signed-off-by: Greg Kroah-Hartman --- drivers/misc/pvpanic/pvpanic-pci.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/pvpanic/pvpanic-pci.c b/drivers/misc/pvpanic/pvpanic-pci.c index 9ecc4e8559d5..046ce4ecc195 100644 --- a/drivers/misc/pvpanic/pvpanic-pci.c +++ b/drivers/misc/pvpanic/pvpanic-pci.c @@ -78,15 +78,15 @@ static int pvpanic_pci_probe(struct pci_dev *pdev, void __iomem *base; int ret; - ret = pci_enable_device(pdev); + ret = pcim_enable_device(pdev); if (ret < 0) return ret; - base = pci_iomap(pdev, 0, 0); + base = pcim_iomap(pdev, 0, 0); if (!base) return -ENOMEM; - pi = kmalloc(sizeof(*pi), GFP_ATOMIC); + pi = devm_kmalloc(&pdev->dev, sizeof(*pi), GFP_ATOMIC); if (!pi) return -ENOMEM; @@ -107,9 +107,6 @@ static void pvpanic_pci_remove(struct pci_dev *pdev) struct pvpanic_instance *pi = dev_get_drvdata(&pdev->dev); pvpanic_remove(pi); - iounmap(pi->base); - kfree(pi); - pci_disable_device(pdev); } static struct pci_driver pvpanic_pci_driver = { -- cgit v1.2.3 From b647ceb5a13e0cbe2f47fcc939a87526e1debf10 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 22 May 2021 08:54:52 +0200 Subject: misc/pvpanic-pci: Use GFP_KERNEL instead of GFP_ATOMIC There is no need to use GFP_ATOMIC in a probe function. Use GFP_KERNEL instead. Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/5ea4fb9802f7b780cc3e5ae768561a0372a39ebb.1621665058.git.christophe.jaillet@wanadoo.fr Signed-off-by: Greg Kroah-Hartman --- drivers/misc/pvpanic/pvpanic-pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/pvpanic/pvpanic-pci.c b/drivers/misc/pvpanic/pvpanic-pci.c index 046ce4ecc195..3d7f9efb3dd4 100644 --- a/drivers/misc/pvpanic/pvpanic-pci.c +++ b/drivers/misc/pvpanic/pvpanic-pci.c @@ -86,7 +86,7 @@ static int pvpanic_pci_probe(struct pci_dev *pdev, if (!base) return -ENOMEM; - pi = devm_kmalloc(&pdev->dev, sizeof(*pi), GFP_ATOMIC); + pi = devm_kmalloc(&pdev->dev, sizeof(*pi), GFP_KERNEL); if (!pi) return -ENOMEM; -- cgit v1.2.3 From 9a3c72ee6ffcd461bae1bbdf4e71dca6d5bc160c Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 22 May 2021 08:55:03 +0200 Subject: misc/pvpanic-mmio: Fix error handling in 'pvpanic_mmio_probe()' There is no error handling path in the probe function. Switch to managed resource so that errors in the probe are handled easily and simplify the remove function accordingly. Fixes: b3c0f8774668 ("misc/pvpanic: probe multiple instances") Reviewed-by: Andy Shevchenko Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/2a5dab18f10db783b27e0579ba66cc38d610734a.1621665058.git.christophe.jaillet@wanadoo.fr Signed-off-by: Greg Kroah-Hartman --- drivers/misc/pvpanic/pvpanic-mmio.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/pvpanic/pvpanic-mmio.c b/drivers/misc/pvpanic/pvpanic-mmio.c index 4c0841776087..69b31f7adf4f 100644 --- a/drivers/misc/pvpanic/pvpanic-mmio.c +++ b/drivers/misc/pvpanic/pvpanic-mmio.c @@ -93,7 +93,7 @@ static int pvpanic_mmio_probe(struct platform_device *pdev) return -EINVAL; } - pi = kmalloc(sizeof(*pi), GFP_ATOMIC); + pi = devm_kmalloc(dev, sizeof(*pi), GFP_ATOMIC); if (!pi) return -ENOMEM; @@ -114,7 +114,6 @@ static int pvpanic_mmio_remove(struct platform_device *pdev) struct pvpanic_instance *pi = dev_get_drvdata(&pdev->dev); pvpanic_remove(pi); - kfree(pi); return 0; } -- cgit v1.2.3 From a224db273accc43699598a89895f9215ccfc2f31 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 22 May 2021 08:55:12 +0200 Subject: misc/pvpanic-mmio: Use GFP_KERNEL instead of GFP_ATOMIC There is no need to use GFP_ATOMIC in a probe function. Use GFP_KERNEL instead. Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/58cc7f12535a796a0ef1a699bcba61e45ab8a2ad.1621665058.git.christophe.jaillet@wanadoo.fr Signed-off-by: Greg Kroah-Hartman --- drivers/misc/pvpanic/pvpanic-mmio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/pvpanic/pvpanic-mmio.c b/drivers/misc/pvpanic/pvpanic-mmio.c index 69b31f7adf4f..d4a407956c07 100644 --- a/drivers/misc/pvpanic/pvpanic-mmio.c +++ b/drivers/misc/pvpanic/pvpanic-mmio.c @@ -93,7 +93,7 @@ static int pvpanic_mmio_probe(struct platform_device *pdev) return -EINVAL; } - pi = devm_kmalloc(dev, sizeof(*pi), GFP_ATOMIC); + pi = devm_kmalloc(dev, sizeof(*pi), GFP_KERNEL); if (!pi) return -ENOMEM; -- cgit v1.2.3 From 394febc9d0a607d6310e14d8248af62125feb5d1 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 22 May 2021 08:55:20 +0200 Subject: misc/pvpanic: Make 'pvpanic_probe()' resource managed Simplify code and turn 'pvpanic_probe()' into a managed resource version. This simplify callers that don't need to do some clean-up on error in the probe and on remove. Update pvpanic-mmio.c and pvpanic-pci.c accordingly. 'pvpanic_remove()' don't need to be exported anymore. Suggested-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/9212cdc8c1e5c187a2f1129a6190085c2a10d28a.1621665058.git.christophe.jaillet@wanadoo.fr Signed-off-by: Greg Kroah-Hartman --- drivers/misc/pvpanic/pvpanic-mmio.c | 14 +------------- drivers/misc/pvpanic/pvpanic-pci.c | 13 +------------ drivers/misc/pvpanic/pvpanic.c | 30 +++++++++++++++--------------- drivers/misc/pvpanic/pvpanic.h | 3 +-- 4 files changed, 18 insertions(+), 42 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/pvpanic/pvpanic-mmio.c b/drivers/misc/pvpanic/pvpanic-mmio.c index d4a407956c07..be4016084979 100644 --- a/drivers/misc/pvpanic/pvpanic-mmio.c +++ b/drivers/misc/pvpanic/pvpanic-mmio.c @@ -104,18 +104,7 @@ static int pvpanic_mmio_probe(struct platform_device *pdev) pi->capability &= ioread8(base); pi->events = pi->capability; - dev_set_drvdata(dev, pi); - - return pvpanic_probe(pi); -} - -static int pvpanic_mmio_remove(struct platform_device *pdev) -{ - struct pvpanic_instance *pi = dev_get_drvdata(&pdev->dev); - - pvpanic_remove(pi); - - return 0; + return devm_pvpanic_probe(dev, pi); } static const struct of_device_id pvpanic_mmio_match[] = { @@ -138,6 +127,5 @@ static struct platform_driver pvpanic_mmio_driver = { .dev_groups = pvpanic_mmio_dev_groups, }, .probe = pvpanic_mmio_probe, - .remove = pvpanic_mmio_remove, }; module_platform_driver(pvpanic_mmio_driver); diff --git a/drivers/misc/pvpanic/pvpanic-pci.c b/drivers/misc/pvpanic/pvpanic-pci.c index 3d7f9efb3dd4..a43c401017ae 100644 --- a/drivers/misc/pvpanic/pvpanic-pci.c +++ b/drivers/misc/pvpanic/pvpanic-pci.c @@ -73,7 +73,6 @@ ATTRIBUTE_GROUPS(pvpanic_pci_dev); static int pvpanic_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - struct device *dev = &pdev->dev; struct pvpanic_instance *pi; void __iomem *base; int ret; @@ -97,23 +96,13 @@ static int pvpanic_pci_probe(struct pci_dev *pdev, pi->capability &= ioread8(base); pi->events = pi->capability; - dev_set_drvdata(dev, pi); - - return pvpanic_probe(pi); -} - -static void pvpanic_pci_remove(struct pci_dev *pdev) -{ - struct pvpanic_instance *pi = dev_get_drvdata(&pdev->dev); - - pvpanic_remove(pi); + return devm_pvpanic_probe(&pdev->dev, pi); } static struct pci_driver pvpanic_pci_driver = { .name = "pvpanic-pci", .id_table = pvpanic_pci_id_tbl, .probe = pvpanic_pci_probe, - .remove = pvpanic_pci_remove, .driver = { .dev_groups = pvpanic_pci_dev_groups, }, diff --git a/drivers/misc/pvpanic/pvpanic.c b/drivers/misc/pvpanic/pvpanic.c index 65f70a4da8c0..29f63a31edbc 100644 --- a/drivers/misc/pvpanic/pvpanic.c +++ b/drivers/misc/pvpanic/pvpanic.c @@ -60,22 +60,10 @@ static struct notifier_block pvpanic_panic_nb = { .priority = 1, /* let this called before broken drm_fb_helper */ }; -int pvpanic_probe(struct pvpanic_instance *pi) -{ - if (!pi || !pi->base) - return -EINVAL; - - spin_lock(&pvpanic_lock); - list_add(&pi->list, &pvpanic_list); - spin_unlock(&pvpanic_lock); - - return 0; -} -EXPORT_SYMBOL_GPL(pvpanic_probe); - -void pvpanic_remove(struct pvpanic_instance *pi) +static void pvpanic_remove(void *param) { struct pvpanic_instance *pi_cur, *pi_next; + struct pvpanic_instance *pi = param; if (!pi) return; @@ -89,7 +77,19 @@ void pvpanic_remove(struct pvpanic_instance *pi) } spin_unlock(&pvpanic_lock); } -EXPORT_SYMBOL_GPL(pvpanic_remove); + +int devm_pvpanic_probe(struct device *dev, struct pvpanic_instance *pi) +{ + if (!pi || !pi->base) + return -EINVAL; + + spin_lock(&pvpanic_lock); + list_add(&pi->list, &pvpanic_list); + spin_unlock(&pvpanic_lock); + + return devm_add_action_or_reset(dev, pvpanic_remove, pi); +} +EXPORT_SYMBOL_GPL(devm_pvpanic_probe); static int pvpanic_init(void) { diff --git a/drivers/misc/pvpanic/pvpanic.h b/drivers/misc/pvpanic/pvpanic.h index 1afccc2e9fec..493545951754 100644 --- a/drivers/misc/pvpanic/pvpanic.h +++ b/drivers/misc/pvpanic/pvpanic.h @@ -15,7 +15,6 @@ struct pvpanic_instance { struct list_head list; }; -int pvpanic_probe(struct pvpanic_instance *pi); -void pvpanic_remove(struct pvpanic_instance *pi); +int devm_pvpanic_probe(struct device *dev, struct pvpanic_instance *pi); #endif /* PVPANIC_H_ */ -- cgit v1.2.3 From 7adbd54fb23b38fd7bc28f679445ae93d3846c40 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 24 May 2021 22:08:51 +0200 Subject: eeprom: ee1004: Use kobj_to_i2c_client to simplify the code Switch to helper kobj_to_i2c_client() to simplify the code. Signed-off-by: Heiner Kallweit Link: https://lore.kernel.org/r/4ae57f09-b803-6ae3-c734-87e733a56eb8@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/ee1004.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/eeprom/ee1004.c b/drivers/misc/eeprom/ee1004.c index 0950d4d9d9ce..0613a530099c 100644 --- a/drivers/misc/eeprom/ee1004.c +++ b/drivers/misc/eeprom/ee1004.c @@ -93,8 +93,7 @@ static ssize_t eeprom_read(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { - struct device *dev = kobj_to_dev(kobj); - struct i2c_client *client = to_i2c_client(dev); + struct i2c_client *client = kobj_to_i2c_client(kobj); size_t requested = count; int page; -- cgit v1.2.3 From 7abdadfcf19a385b6f8ffea75457074240a9536f Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 24 May 2021 22:09:49 +0200 Subject: eeprom: ee1004: Remove not needed check in ee1004_read sysfs_kf_bin_read() checks this for us already. In addition the function works correctly also w/o this check. Signed-off-by: Heiner Kallweit Link: https://lore.kernel.org/r/33889bff-3614-4b73-5010-701635e1edab@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/ee1004.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/eeprom/ee1004.c b/drivers/misc/eeprom/ee1004.c index 0613a530099c..6aff333ff049 100644 --- a/drivers/misc/eeprom/ee1004.c +++ b/drivers/misc/eeprom/ee1004.c @@ -97,9 +97,6 @@ static ssize_t eeprom_read(struct file *filp, struct kobject *kobj, size_t requested = count; int page; - if (unlikely(!count)) - return count; - page = off >> EE1004_PAGE_SHIFT; if (unlikely(page > 1)) return 0; -- cgit v1.2.3 From 64bf274711c0ba973bb1907fd5119c0d06255e37 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 24 May 2021 22:10:47 +0200 Subject: eeprom: ee1004: Remove not needed check in ee1004_eeprom_read i2c_smbus_read_i2c_block_data_or_emulated() checks its length argument, so we don't have to do it. In addition remove the unlikely hint from the checks, we do i2c reads and therefore are in a slow path. Signed-off-by: Heiner Kallweit Link: https://lore.kernel.org/r/eb2a8bff-43ec-c763-a417-9d741e6f0034@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/ee1004.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/eeprom/ee1004.c b/drivers/misc/eeprom/ee1004.c index 6aff333ff049..2824dba76858 100644 --- a/drivers/misc/eeprom/ee1004.c +++ b/drivers/misc/eeprom/ee1004.c @@ -76,10 +76,8 @@ static ssize_t ee1004_eeprom_read(struct i2c_client *client, char *buf, { int status; - if (count > I2C_SMBUS_BLOCK_MAX) - count = I2C_SMBUS_BLOCK_MAX; /* Can't cross page boundaries */ - if (unlikely(offset + count > EE1004_PAGE_SIZE)) + if (offset + count > EE1004_PAGE_SIZE) count = EE1004_PAGE_SIZE - offset; status = i2c_smbus_read_i2c_block_data_or_emulated(client, offset, -- cgit v1.2.3 From b97ba92e2962b7ede713bc5b70dcf747083e45f9 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 24 May 2021 22:11:31 +0200 Subject: eeprom: ee1004: Remove usage of i2c_adapter_id in adapter comparison We can compare the adapter pointers directly instead of using i2c_adapter_id(). Signed-off-by: Heiner Kallweit Link: https://lore.kernel.org/r/99a3f94d-e7ca-e01d-6a78-81e109fde086@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/ee1004.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/eeprom/ee1004.c b/drivers/misc/eeprom/ee1004.c index 2824dba76858..b991ab250456 100644 --- a/drivers/misc/eeprom/ee1004.c +++ b/drivers/misc/eeprom/ee1004.c @@ -199,8 +199,7 @@ static int ee1004_probe(struct i2c_client *client, goto err_clients; } } - } else if (i2c_adapter_id(client->adapter) != - i2c_adapter_id(ee1004_set_page[0]->adapter)) { + } else if (client->adapter != ee1004_set_page[0]->adapter) { dev_err(&client->dev, "Driver only supports devices on a single I2C bus\n"); err = -EOPNOTSUPP; -- cgit v1.2.3 From 08e5138aa419350d0a168abeac3ecec4b7e779be Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 24 May 2021 22:12:22 +0200 Subject: eeprom: ee1004: Improve check for SMBUS features We have to read 512 bytes only, therefore read performance isn't really a concern. Don't bother the user if i2c block read isn't supported. For i2c_smbus_read_i2c_block_data_or_emulated() to work it's sufficient if I2C_FUNC_SMBUS_READ_I2C_BLOCK or I2C_FUNC_SMBUS_READ_BYTE_DATA is supported. Therefore remove the check for I2C_FUNC_SMBUS_READ_WORD_DATA. In addition check for I2C_FUNC_SMBUS_WRITE_BYTE (included in I2C_FUNC_SMBUS_BYTE) which is needed for setting the page. Signed-off-by: Heiner Kallweit Link: https://lore.kernel.org/r/840c668e-6310-e933-e50e-5abeaecfb39c@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/ee1004.c | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/eeprom/ee1004.c b/drivers/misc/eeprom/ee1004.c index b991ab250456..0d497e0e4a51 100644 --- a/drivers/misc/eeprom/ee1004.c +++ b/drivers/misc/eeprom/ee1004.c @@ -167,23 +167,13 @@ static int ee1004_probe(struct i2c_client *client, const struct i2c_device_id *id) { int err, cnr = 0; - const char *slow = NULL; /* Make sure we can operate on this adapter */ if (!i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_READ_BYTE | - I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { - if (i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_READ_BYTE | - I2C_FUNC_SMBUS_READ_WORD_DATA)) - slow = "word"; - else if (i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_READ_BYTE | - I2C_FUNC_SMBUS_READ_BYTE_DATA)) - slow = "byte"; - else - return -EPFNOSUPPORT; - } + I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_READ_I2C_BLOCK) && + !i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_READ_BYTE_DATA)) + return -EPFNOSUPPORT; /* Use 2 dummy devices for page select command */ mutex_lock(&ee1004_bus_lock); @@ -218,10 +208,6 @@ static int ee1004_probe(struct i2c_client *client, dev_info(&client->dev, "%u byte EE1004-compliant SPD EEPROM, read-only\n", EE1004_EEPROM_SIZE); - if (slow) - dev_notice(&client->dev, - "Falling back to %s reads, performance will suffer\n", - slow); return 0; -- cgit v1.2.3 From 3c03dad7652ee2b30728a263905de93a79205477 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 24 May 2021 22:13:12 +0200 Subject: eeprom: ee1004: Improve creating dummy devices i2c_new_dummy_device() calls i2c_new_client_device() that complains if it fails to create the device. Therefore we don't have to emit an error message in case of failure. In addition ensure that ee1004_set_page is only set if creating the device succeeded. Signed-off-by: Heiner Kallweit Link: https://lore.kernel.org/r/d38df5ac-6ecb-7d5f-b5c3-39bfc6a1e8a1@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/ee1004.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/eeprom/ee1004.c b/drivers/misc/eeprom/ee1004.c index 0d497e0e4a51..4b2c60a1828c 100644 --- a/drivers/misc/eeprom/ee1004.c +++ b/drivers/misc/eeprom/ee1004.c @@ -179,15 +179,14 @@ static int ee1004_probe(struct i2c_client *client, mutex_lock(&ee1004_bus_lock); if (++ee1004_dev_count == 1) { for (cnr = 0; cnr < 2; cnr++) { - ee1004_set_page[cnr] = i2c_new_dummy_device(client->adapter, - EE1004_ADDR_SET_PAGE + cnr); - if (IS_ERR(ee1004_set_page[cnr])) { - dev_err(&client->dev, - "address 0x%02x unavailable\n", - EE1004_ADDR_SET_PAGE + cnr); - err = PTR_ERR(ee1004_set_page[cnr]); + struct i2c_client *cl; + + cl = i2c_new_dummy_device(client->adapter, EE1004_ADDR_SET_PAGE + cnr); + if (IS_ERR(cl)) { + err = PTR_ERR(cl); goto err_clients; } + ee1004_set_page[cnr] = cl; } } else if (client->adapter != ee1004_set_page[0]->adapter) { dev_err(&client->dev, -- cgit v1.2.3 From 2ac99039c568467ea2e593221aa2a741fa63f0b1 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 24 May 2021 22:13:52 +0200 Subject: eeprom: ee1004: Switch to i2c probe_new callback Switch to the new i2c_driver probe callback version. Signed-off-by: Heiner Kallweit Link: https://lore.kernel.org/r/eb5be659-7427-46c5-66c2-b39650e08ea3@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/ee1004.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/eeprom/ee1004.c b/drivers/misc/eeprom/ee1004.c index 4b2c60a1828c..460cc22ea85a 100644 --- a/drivers/misc/eeprom/ee1004.c +++ b/drivers/misc/eeprom/ee1004.c @@ -163,8 +163,7 @@ static struct bin_attribute *ee1004_attrs[] = { BIN_ATTRIBUTE_GROUPS(ee1004); -static int ee1004_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ee1004_probe(struct i2c_client *client) { int err, cnr = 0; @@ -246,7 +245,7 @@ static struct i2c_driver ee1004_driver = { .name = "ee1004", .dev_groups = ee1004_groups, }, - .probe = ee1004_probe, + .probe_new = ee1004_probe, .remove = ee1004_remove, .id_table = ee1004_ids, }; -- cgit v1.2.3 From b2cd8a2f8eb148366fb974e265f1799e93062ea7 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 24 May 2021 22:14:43 +0200 Subject: eeprom: ee1004: Cache current page at initialization of first device only The value of ee1004_current_page applies to all SPD eeproms connected to the adapter. Therefore it's sufficient if we set ee1004_current_page when the first device is added. Signed-off-by: Heiner Kallweit Link: https://lore.kernel.org/r/b9240e58-08bb-3d71-7a9c-9a323b470ab6@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/ee1004.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/eeprom/ee1004.c b/drivers/misc/eeprom/ee1004.c index 460cc22ea85a..d7c693b26d98 100644 --- a/drivers/misc/eeprom/ee1004.c +++ b/drivers/misc/eeprom/ee1004.c @@ -187,20 +187,19 @@ static int ee1004_probe(struct i2c_client *client) } ee1004_set_page[cnr] = cl; } + + /* Remember current page to avoid unneeded page select */ + err = ee1004_get_current_page(); + if (err < 0) + goto err_clients; + dev_dbg(&client->dev, "Currently selected page: %d\n", err); + ee1004_current_page = err; } else if (client->adapter != ee1004_set_page[0]->adapter) { dev_err(&client->dev, "Driver only supports devices on a single I2C bus\n"); err = -EOPNOTSUPP; goto err_clients; } - - /* Remember current page to avoid unneeded page select */ - err = ee1004_get_current_page(); - if (err < 0) - goto err_clients; - ee1004_current_page = err; - dev_dbg(&client->dev, "Currently selected page: %d\n", - ee1004_current_page); mutex_unlock(&ee1004_bus_lock); dev_info(&client->dev, -- cgit v1.2.3 From 6601017e2a4936a93c7d9527cd25a4a2c16cc5ef Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 24 May 2021 22:15:26 +0200 Subject: eeprom: ee1004: Factor out setting page to ee1004_set_current_page Factor out setting the page, this makes the code better readable. Signed-off-by: Heiner Kallweit Link: https://lore.kernel.org/r/21e0966f-e6c9-045f-b130-bd9fb071f0d7@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/ee1004.c | 52 +++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 22 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/eeprom/ee1004.c b/drivers/misc/eeprom/ee1004.c index d7c693b26d98..33855e459a40 100644 --- a/drivers/misc/eeprom/ee1004.c +++ b/drivers/misc/eeprom/ee1004.c @@ -71,6 +71,32 @@ static int ee1004_get_current_page(void) return 0; } +static int ee1004_set_current_page(struct device *dev, int page) +{ + int ret; + + if (page == ee1004_current_page) + return 0; + + /* Data is ignored */ + ret = i2c_smbus_write_byte(ee1004_set_page[page], 0x00); + /* + * Don't give up just yet. Some memory modules will select the page + * but not ack the command. Check which page is selected now. + */ + if (ret == -ENXIO && ee1004_get_current_page() == page) + ret = 0; + if (ret < 0) { + dev_err(dev, "Failed to select page %d (%d)\n", page, ret); + return ret; + } + + dev_dbg(dev, "Selected page %d\n", page); + ee1004_current_page = page; + + return 0; +} + static ssize_t ee1004_eeprom_read(struct i2c_client *client, char *buf, unsigned int offset, size_t count) { @@ -110,28 +136,10 @@ static ssize_t eeprom_read(struct file *filp, struct kobject *kobj, int status; /* Select page */ - if (page != ee1004_current_page) { - /* Data is ignored */ - status = i2c_smbus_write_byte(ee1004_set_page[page], - 0x00); - if (status == -ENXIO) { - /* - * Don't give up just yet. Some memory - * modules will select the page but not - * ack the command. Check which page is - * selected now. - */ - if (ee1004_get_current_page() == page) - status = 0; - } - if (status < 0) { - dev_err(dev, "Failed to select page %d (%d)\n", - page, status); - mutex_unlock(&ee1004_bus_lock); - return status; - } - dev_dbg(dev, "Selected page %d\n", page); - ee1004_current_page = page; + status = ee1004_set_current_page(dev, page); + if (status) { + mutex_unlock(&ee1004_bus_lock); + return status; } status = ee1004_eeprom_read(client, buf, off, count); -- cgit v1.2.3 From 6f68dbd6cc7b440c91aea894e214a7065f5fbbb6 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 24 May 2021 22:16:05 +0200 Subject: eeprom: ee1004: Improve error handling in ee1004_read Simplify the error handling and make it better readable. No functional change intended. Signed-off-by: Heiner Kallweit Link: https://lore.kernel.org/r/13ad7b39-e722-d70a-e25b-03d1fb1734a7@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/ee1004.c | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/eeprom/ee1004.c b/drivers/misc/eeprom/ee1004.c index 33855e459a40..d18348ee4a57 100644 --- a/drivers/misc/eeprom/ee1004.c +++ b/drivers/misc/eeprom/ee1004.c @@ -119,7 +119,7 @@ static ssize_t eeprom_read(struct file *filp, struct kobject *kobj, { struct i2c_client *client = kobj_to_i2c_client(kobj); size_t requested = count; - int page; + int page, ret = 0; page = off >> EE1004_PAGE_SHIFT; if (unlikely(page > 1)) @@ -133,33 +133,28 @@ static ssize_t eeprom_read(struct file *filp, struct kobject *kobj, mutex_lock(&ee1004_bus_lock); while (count) { - int status; - /* Select page */ - status = ee1004_set_current_page(dev, page); - if (status) { - mutex_unlock(&ee1004_bus_lock); - return status; - } + ret = ee1004_set_current_page(dev, page); + if (ret) + goto out; - status = ee1004_eeprom_read(client, buf, off, count); - if (status < 0) { - mutex_unlock(&ee1004_bus_lock); - return status; - } - buf += status; - off += status; - count -= status; + ret = ee1004_eeprom_read(client, buf, off, count); + if (ret < 0) + goto out; + + buf += ret; + off += ret; + count -= ret; if (off == EE1004_PAGE_SIZE) { page++; off = 0; } } - +out: mutex_unlock(&ee1004_bus_lock); - return requested; + return ret < 0 ? ret : requested; } static BIN_ATTR_RO(eeprom, EE1004_EEPROM_SIZE); -- cgit v1.2.3 From 8aeacb7a2de36e429213faa3b0d092a8e9019b3c Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 24 May 2021 22:16:51 +0200 Subject: eeprom: ee1004: Move call to ee1004_set_current_page to ee1004_eeprom_read Moving the call to ee1004_set_current_page() to ee1004_eeprom_read() allows to simplify the code. Signed-off-by: Heiner Kallweit Link: https://lore.kernel.org/r/2829a131-51e3-8865-462a-564080158b0b@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/ee1004.c | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/eeprom/ee1004.c b/drivers/misc/eeprom/ee1004.c index d18348ee4a57..65fe11d8f7d7 100644 --- a/drivers/misc/eeprom/ee1004.c +++ b/drivers/misc/eeprom/ee1004.c @@ -100,7 +100,14 @@ static int ee1004_set_current_page(struct device *dev, int page) static ssize_t ee1004_eeprom_read(struct i2c_client *client, char *buf, unsigned int offset, size_t count) { - int status; + int status, page; + + page = offset >> EE1004_PAGE_SHIFT; + offset &= (1 << EE1004_PAGE_SHIFT) - 1; + + status = ee1004_set_current_page(&client->dev, page); + if (status) + return status; /* Can't cross page boundaries */ if (offset + count > EE1004_PAGE_SIZE) @@ -119,12 +126,7 @@ static ssize_t eeprom_read(struct file *filp, struct kobject *kobj, { struct i2c_client *client = kobj_to_i2c_client(kobj); size_t requested = count; - int page, ret = 0; - - page = off >> EE1004_PAGE_SHIFT; - if (unlikely(page > 1)) - return 0; - off &= (1 << EE1004_PAGE_SHIFT) - 1; + int ret = 0; /* * Read data from chip, protecting against concurrent access to @@ -133,11 +135,6 @@ static ssize_t eeprom_read(struct file *filp, struct kobject *kobj, mutex_lock(&ee1004_bus_lock); while (count) { - /* Select page */ - ret = ee1004_set_current_page(dev, page); - if (ret) - goto out; - ret = ee1004_eeprom_read(client, buf, off, count); if (ret < 0) goto out; @@ -145,11 +142,6 @@ static ssize_t eeprom_read(struct file *filp, struct kobject *kobj, buf += ret; off += ret; count -= ret; - - if (off == EE1004_PAGE_SIZE) { - page++; - off = 0; - } } out: mutex_unlock(&ee1004_bus_lock); -- cgit v1.2.3 From 8700a7328e89371493c267edb4c8812645f6e38b Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 24 May 2021 22:17:28 +0200 Subject: eeprom: ee1004: Add constant EE1004_NUM_PAGES Add a constant for the number of pages. Signed-off-by: Heiner Kallweit Link: https://lore.kernel.org/r/6167f9c5-995a-03c3-c324-e93e2a6c969b@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/ee1004.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/eeprom/ee1004.c b/drivers/misc/eeprom/ee1004.c index 65fe11d8f7d7..5173d040c7ae 100644 --- a/drivers/misc/eeprom/ee1004.c +++ b/drivers/misc/eeprom/ee1004.c @@ -32,16 +32,17 @@ */ #define EE1004_ADDR_SET_PAGE 0x36 -#define EE1004_EEPROM_SIZE 512 +#define EE1004_NUM_PAGES 2 #define EE1004_PAGE_SIZE 256 #define EE1004_PAGE_SHIFT 8 +#define EE1004_EEPROM_SIZE (EE1004_PAGE_SIZE * EE1004_NUM_PAGES) /* * Mutex protects ee1004_set_page and ee1004_dev_count, and must be held * from page selection to end of read. */ static DEFINE_MUTEX(ee1004_bus_lock); -static struct i2c_client *ee1004_set_page[2]; +static struct i2c_client *ee1004_set_page[EE1004_NUM_PAGES]; static unsigned int ee1004_dev_count; static int ee1004_current_page; @@ -172,7 +173,7 @@ static int ee1004_probe(struct i2c_client *client) /* Use 2 dummy devices for page select command */ mutex_lock(&ee1004_bus_lock); if (++ee1004_dev_count == 1) { - for (cnr = 0; cnr < 2; cnr++) { + for (cnr = 0; cnr < EE1004_NUM_PAGES; cnr++) { struct i2c_client *cl; cl = i2c_new_dummy_device(client->adapter, EE1004_ADDR_SET_PAGE + cnr); @@ -222,7 +223,7 @@ static int ee1004_remove(struct i2c_client *client) /* Remove page select clients if this is the last device */ mutex_lock(&ee1004_bus_lock); if (--ee1004_dev_count == 0) { - for (i = 0; i < 2; i++) { + for (i = 0; i < EE1004_NUM_PAGES; i++) { i2c_unregister_device(ee1004_set_page[i]); ee1004_set_page[i] = NULL; } -- cgit v1.2.3 From 5fe3cba0bf5c2c1331cbf21baea6a99daa0a6f78 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 24 May 2021 22:18:23 +0200 Subject: eeprom: ee1004: Add helper ee1004_cleanup Factor out the cleanup code to a new helper ee1004_cleanup(). Signed-off-by: Heiner Kallweit Link: https://lore.kernel.org/r/9738cbc7-458d-276f-4012-66551f105d90@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/ee1004.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/eeprom/ee1004.c b/drivers/misc/eeprom/ee1004.c index 5173d040c7ae..00f61a83d7dd 100644 --- a/drivers/misc/eeprom/ee1004.c +++ b/drivers/misc/eeprom/ee1004.c @@ -159,6 +159,15 @@ static struct bin_attribute *ee1004_attrs[] = { BIN_ATTRIBUTE_GROUPS(ee1004); +static void ee1004_cleanup(int idx) +{ + if (--ee1004_dev_count == 0) + while (--idx >= 0) { + i2c_unregister_device(ee1004_set_page[idx]); + ee1004_set_page[idx] = NULL; + } +} + static int ee1004_probe(struct i2c_client *client) { int err, cnr = 0; @@ -205,12 +214,7 @@ static int ee1004_probe(struct i2c_client *client) return 0; err_clients: - if (--ee1004_dev_count == 0) { - for (cnr--; cnr >= 0; cnr--) { - i2c_unregister_device(ee1004_set_page[cnr]); - ee1004_set_page[cnr] = NULL; - } - } + ee1004_cleanup(cnr); mutex_unlock(&ee1004_bus_lock); return err; @@ -218,16 +222,9 @@ static int ee1004_probe(struct i2c_client *client) static int ee1004_remove(struct i2c_client *client) { - int i; - /* Remove page select clients if this is the last device */ mutex_lock(&ee1004_bus_lock); - if (--ee1004_dev_count == 0) { - for (i = 0; i < EE1004_NUM_PAGES; i++) { - i2c_unregister_device(ee1004_set_page[i]); - ee1004_set_page[i] = NULL; - } - } + ee1004_cleanup(EE1004_NUM_PAGES); mutex_unlock(&ee1004_bus_lock); return 0; -- cgit v1.2.3 From 23d51b818151273125e35b1a1ce1b294f7d8c073 Mon Sep 17 00:00:00 2001 From: Matt Hsiao Date: Mon, 31 May 2021 16:55:51 +0800 Subject: misc: hpilo: map iLO shared memory by PCI revision id Starting from iLO ASIC 'Neches' with subsystem device id 0x00E4, bar 5 is used for shared memory region mapping instead of bar 2 because bar 2 is made inaccessible after system POST for security reason. As this holds true for future iLO ASIC generations, it does not make sense to map shared memory region according to the subsystem device id of each following generations. Map iLO shared memory region with PCI revision id that maps to the iLO ASIC generation, starting from Neches (Rev 7). Signed-off-by: Matt Hsiao Link: https://lore.kernel.org/r/20210531085551.26421-1-matt.hsiao@hpe.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/hpilo.c | 10 +++++++++- drivers/misc/hpilo.h | 3 +++ 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/hpilo.c b/drivers/misc/hpilo.c index fea3ae9d8686..8d00df9243c4 100644 --- a/drivers/misc/hpilo.c +++ b/drivers/misc/hpilo.c @@ -693,6 +693,8 @@ static int ilo_map_device(struct pci_dev *pdev, struct ilo_hwinfo *hw) { int bar; unsigned long off; + u8 pci_rev_id; + int rc; /* map the memory mapped i/o registers */ hw->mmio_vaddr = pci_iomap(pdev, 1, 0); @@ -702,7 +704,13 @@ static int ilo_map_device(struct pci_dev *pdev, struct ilo_hwinfo *hw) } /* map the adapter shared memory region */ - if (pdev->subsystem_device == 0x00E4) { + rc = pci_read_config_byte(pdev, PCI_REVISION_ID, &pci_rev_id); + if (rc != 0) { + dev_err(&pdev->dev, "Error reading PCI rev id: %d\n", rc); + goto out; + } + + if (pci_rev_id >= PCI_REV_ID_NECHES) { bar = 5; /* Last 8k is reserved for CCBs */ off = pci_resource_len(pdev, bar) - 0x2000; diff --git a/drivers/misc/hpilo.h b/drivers/misc/hpilo.h index f69ff645cac9..d57c34680b09 100644 --- a/drivers/misc/hpilo.h +++ b/drivers/misc/hpilo.h @@ -10,6 +10,9 @@ #define ILO_NAME "hpilo" +/* iLO ASIC PCI revision id */ +#define PCI_REV_ID_NECHES 7 + /* max number of open channel control blocks per device, hw limited to 32 */ #define MAX_CCB 24 /* min number of open channel control blocks per device, hw limited to 32 */ -- cgit v1.2.3 From 2fa7d74ff54e8c99f7cf04e1749bfca8f8e12e98 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 1 Jun 2021 09:50:30 +0200 Subject: eeprom: ee1004: Remove not needed debug message If a user is interested in such transfer statistics he can simply switch on smbus tracing. Signed-off-by: Heiner Kallweit Link: https://lore.kernel.org/r/6169f52e-6ede-d7cc-7f8b-cced55b693d0@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/ee1004.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/eeprom/ee1004.c b/drivers/misc/eeprom/ee1004.c index 00f61a83d7dd..bb9c4512c968 100644 --- a/drivers/misc/eeprom/ee1004.c +++ b/drivers/misc/eeprom/ee1004.c @@ -114,11 +114,7 @@ static ssize_t ee1004_eeprom_read(struct i2c_client *client, char *buf, if (offset + count > EE1004_PAGE_SIZE) count = EE1004_PAGE_SIZE - offset; - status = i2c_smbus_read_i2c_block_data_or_emulated(client, offset, - count, buf); - dev_dbg(&client->dev, "read %zu@%d --> %d\n", count, offset, status); - - return status; + return i2c_smbus_read_i2c_block_data_or_emulated(client, offset, count, buf); } static ssize_t eeprom_read(struct file *filp, struct kobject *kobj, -- cgit v1.2.3 From d208cbb0024ec0a5878bfd6c757c7f01872201ea Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 5 Jun 2021 18:53:47 +0200 Subject: misc/pvpanic: Remove some dead-code 'pvpanic_remove()' is referenced only by a 'devm_add_action_or_reset()' call in 'devm_pvpanic_probe()'. So, we know that its parameter is non-NULL. Axe the unneeded check to save a few lines of code. Suggested-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/8e425618f4042a8ab8366be4d34026972e77bd40.1622911768.git.christophe.jaillet@wanadoo.fr Signed-off-by: Greg Kroah-Hartman --- drivers/misc/pvpanic/pvpanic.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/pvpanic/pvpanic.c b/drivers/misc/pvpanic/pvpanic.c index 29f63a31edbc..b6bd6abc2952 100644 --- a/drivers/misc/pvpanic/pvpanic.c +++ b/drivers/misc/pvpanic/pvpanic.c @@ -65,9 +65,6 @@ static void pvpanic_remove(void *param) struct pvpanic_instance *pi_cur, *pi_next; struct pvpanic_instance *pi = param; - if (!pi) - return; - spin_lock(&pvpanic_lock); list_for_each_entry_safe(pi_cur, pi_next, &pvpanic_list, list) { if (pi_cur == pi) { -- cgit v1.2.3 From 432b6c56075071c5614beb895e4d9ba9fb378d3d Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 3 Jun 2021 14:12:10 +0100 Subject: habanalabs/gaudi: remove redundant assignment to variable err The variable err is being assigned a value that is never read, the assignment is redundant and can be removed. Also remove some empty lines. Reviewed-by: Oded Gabbay Signed-off-by: Colin Ian King Addresses-Coverity: ("Unused value") Link: https://lore.kernel.org/r/20210603131210.84763-1-colin.king@canonical.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/habanalabs/gaudi/gaudi.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 9e4a6bb3acd1..22f220859b46 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -7379,9 +7379,6 @@ static int gaudi_hbm_read_interrupts(struct hl_device *hdev, int device, device, ch, hbm_ecc_data->first_addr, type, hbm_ecc_data->sec_cont_cnt, hbm_ecc_data->sec_cnt, hbm_ecc_data->dec_cnt); - - err = 1; - return 0; } -- cgit v1.2.3 From 20827dddf27d433e45703a4f9bf0a66ab957dd0c Mon Sep 17 00:00:00 2001 From: Baokun Li Date: Wed, 9 Jun 2021 15:14:30 +0800 Subject: misc: bcm-vk: use list_move_tail instead of list_del/list_add_tail in bcm_vk_msg.c Using list_move_tail() instead of list_del() + list_add_tail() in bcm_vk_msg.c. Reported-by: Hulk Robot Signed-off-by: Baokun Li Link: https://lore.kernel.org/r/20210609071430.1337400-1-libaokun1@huawei.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/bcm-vk/bcm_vk_msg.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/bcm-vk/bcm_vk_msg.c b/drivers/misc/bcm-vk/bcm_vk_msg.c index 6efc52b49af6..066b9ef7fcd7 100644 --- a/drivers/misc/bcm-vk/bcm_vk_msg.c +++ b/drivers/misc/bcm-vk/bcm_vk_msg.c @@ -354,8 +354,7 @@ static void bcm_vk_drain_all_pend(struct device *dev, for (num = 0; num < chan->q_nr; num++) { list_for_each_entry_safe(entry, tmp, &chan->pendq[num], node) { if ((!ctx) || (entry->ctx->idx == ctx->idx)) { - list_del(&entry->node); - list_add_tail(&entry->node, &del_q); + list_move_tail(&entry->node, &del_q); } } } -- cgit v1.2.3 From 3f6ee1c095156a74ab2df605af13020f1ce3e600 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 8 Jun 2021 01:17:55 +0300 Subject: eeprom: idt_89hpesx: Put fwnode in matching case during ->probe() device_get_next_child_node() bumps a reference counting of a returned variable. We have to balance it whenever we return to the caller. Fixes: db15d73e5f0e ("eeprom: idt_89hpesx: Support both ACPI and OF probing") Cc: Huy Duong Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210607221757.81465-1-andy.shevchenko@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/idt_89hpesx.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/misc') diff --git a/drivers/misc/eeprom/idt_89hpesx.c b/drivers/misc/eeprom/idt_89hpesx.c index 81c70e5bc168..45a61a1f9e98 100644 --- a/drivers/misc/eeprom/idt_89hpesx.c +++ b/drivers/misc/eeprom/idt_89hpesx.c @@ -1161,6 +1161,7 @@ static void idt_get_fw_data(struct idt_89hpesx_dev *pdev) else /* if (!fwnode_property_read_bool(node, "read-only")) */ pdev->eero = false; + fwnode_handle_put(fwnode); dev_info(dev, "EEPROM of %d bytes found by 0x%x", pdev->eesize, pdev->eeaddr); } -- cgit v1.2.3 From e0db3deea73ba418bf5dc21f5a4e32ca87d16dde Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 8 Jun 2021 01:17:56 +0300 Subject: eeprom: idt_89hpesx: Restore printing the unsupported fwnode name When iterating over child firmware nodes restore printing the name of ones that are not supported. While at it, refactor loop body to clearly show that we stop at the first match. Fixes: db15d73e5f0e ("eeprom: idt_89hpesx: Support both ACPI and OF probing") Cc: Huy Duong Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210607221757.81465-2-andy.shevchenko@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/idt_89hpesx.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/eeprom/idt_89hpesx.c b/drivers/misc/eeprom/idt_89hpesx.c index 45a61a1f9e98..3e4a594c110b 100644 --- a/drivers/misc/eeprom/idt_89hpesx.c +++ b/drivers/misc/eeprom/idt_89hpesx.c @@ -1126,11 +1126,10 @@ static void idt_get_fw_data(struct idt_89hpesx_dev *pdev) device_for_each_child_node(dev, fwnode) { ee_id = idt_ee_match_id(fwnode); - if (!ee_id) { - dev_warn(dev, "Skip unsupported EEPROM device"); - continue; - } else + if (ee_id) break; + + dev_warn(dev, "Skip unsupported EEPROM device %pfw\n", fwnode); } /* If there is no fwnode EEPROM device, then set zero size */ -- cgit v1.2.3 From 75041120657408ada98514617d3c118419f002c4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 8 Jun 2021 01:17:57 +0300 Subject: eeprom: idt_89hpesx: use SPDX-License-Identifier Use SPDX-License-Identifier: GPL-2.0-only, instead of hand writing it. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210607221757.81465-3-andy.shevchenko@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/idt_89hpesx.c | 33 +-------------------------------- 1 file changed, 1 insertion(+), 32 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/eeprom/idt_89hpesx.c b/drivers/misc/eeprom/idt_89hpesx.c index 3e4a594c110b..b0cff4b152da 100644 --- a/drivers/misc/eeprom/idt_89hpesx.c +++ b/drivers/misc/eeprom/idt_89hpesx.c @@ -1,38 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* - * This file is provided under a GPLv2 license. When using or - * redistributing this file, you may do so under that license. - * - * GPL LICENSE SUMMARY - * * Copyright (C) 2016 T-Platforms. All Rights Reserved. * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, it can be found . - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * * IDT PCIe-switch NTB Linux driver * * Contact Information: -- cgit v1.2.3 From 762b296bcbbc7344752ebf3a25583cf38f8adbdc Mon Sep 17 00:00:00 2001 From: Kai Ye Date: Wed, 9 Jun 2021 18:09:05 +0800 Subject: uacce: add print information if not enable sva Add print information necessary if user not enable sva. Signed-off-by: Kai Ye Link: https://lore.kernel.org/r/1623233345-8765-1-git-send-email-yekai13@huawei.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/uacce/uacce.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/uacce/uacce.c b/drivers/misc/uacce/uacce.c index bae18ef03dcb..488eeb2811ae 100644 --- a/drivers/misc/uacce/uacce.c +++ b/drivers/misc/uacce/uacce.c @@ -387,15 +387,22 @@ static void uacce_release(struct device *dev) static unsigned int uacce_enable_sva(struct device *parent, unsigned int flags) { + int ret; + if (!(flags & UACCE_DEV_SVA)) return flags; flags &= ~UACCE_DEV_SVA; - if (iommu_dev_enable_feature(parent, IOMMU_DEV_FEAT_IOPF)) + ret = iommu_dev_enable_feature(parent, IOMMU_DEV_FEAT_IOPF); + if (ret) { + dev_err(parent, "failed to enable IOPF feature! ret = %pe\n", ERR_PTR(ret)); return flags; + } - if (iommu_dev_enable_feature(parent, IOMMU_DEV_FEAT_SVA)) { + ret = iommu_dev_enable_feature(parent, IOMMU_DEV_FEAT_SVA); + if (ret) { + dev_err(parent, "failed to enable SVA feature! ret = %pe\n", ERR_PTR(ret)); iommu_dev_disable_feature(parent, IOMMU_DEV_FEAT_IOPF); return flags; } -- cgit v1.2.3 From fd307a4ad332ef50be5569c92490219e7cd84ce5 Mon Sep 17 00:00:00 2001 From: Jiri Prchal Date: Fri, 11 Jun 2021 11:45:58 +0200 Subject: nvmem: prepare basics for FRAM support Added enum and string for FRAM (ferroelectric RAM) to expose it as file named "fram". Added documentation of sysfs file. Signed-off-by: Jiri Prchal Link: https://lore.kernel.org/r/20210611094601.95131-2-jiri.prchal@aksignal.cz Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-class-spi-eeprom | 19 +++ Documentation/devicetree/bindings/eeprom/at25.yaml | 31 +++- drivers/misc/eeprom/Kconfig | 5 +- drivers/misc/eeprom/at25.c | 161 +++++++++++++++++---- drivers/nvmem/core.c | 4 + include/linux/nvmem-provider.h | 1 + 6 files changed, 183 insertions(+), 38 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-class-spi-eeprom (limited to 'drivers/misc') diff --git a/Documentation/ABI/testing/sysfs-class-spi-eeprom b/Documentation/ABI/testing/sysfs-class-spi-eeprom new file mode 100644 index 000000000000..1ff757982079 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-spi-eeprom @@ -0,0 +1,19 @@ +What: /sys/class/spi_master/spi/spi./fram +Date: June 2021 +KernelVersion: 5.14 +Contact: Jiri Prchal +Description: + Contains the FRAM binary data. Same as EEPROM, just another file + name to indicate that it employs ferroelectric process. + It performs write operations at bus speed - no write delays. + +What: /sys/class/spi_master/spi/spi./sernum +Date: May 2021 +KernelVersion: 5.14 +Contact: Jiri Prchal +Description: + Contains the serial number of the Cypress FRAM (FM25VN) if it is + present. It will be displayed as a 8 byte hex string, as read + from the device. + + This is a read-only attribute. diff --git a/Documentation/devicetree/bindings/eeprom/at25.yaml b/Documentation/devicetree/bindings/eeprom/at25.yaml index 6a2dc8b3ed14..fbf99e346966 100644 --- a/Documentation/devicetree/bindings/eeprom/at25.yaml +++ b/Documentation/devicetree/bindings/eeprom/at25.yaml @@ -4,14 +4,16 @@ $id: "http://devicetree.org/schemas/eeprom/at25.yaml#" $schema: "http://devicetree.org/meta-schemas/core.yaml#" -title: SPI EEPROMs compatible with Atmel's AT25 +title: SPI EEPROMs or FRAMs compatible with Atmel's AT25 maintainers: - Christian Eggers properties: $nodename: - pattern: "^eeprom@[0-9a-f]{1,2}$" + anyOf: + - pattern: "^eeprom@[0-9a-f]{1,2}$" + - pattern: "^fram@[0-9a-f]{1,2}$" # There are multiple known vendors who manufacture EEPROM chips compatible # with Atmel's AT25. The compatible string requires two items where the @@ -31,6 +33,7 @@ properties: - microchip,25lc040 - st,m95m02 - st,m95256 + - cypress,fm25 - const: atmel,at25 @@ -47,7 +50,7 @@ properties: $ref: /schemas/types.yaml#/definitions/uint32 enum: [1, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072] description: - Size of the eeprom page. + Size of the eeprom page. FRAMs don't have pages. size: $ref: /schemas/types.yaml#/definitions/uint32 @@ -100,9 +103,19 @@ required: - compatible - reg - spi-max-frequency - - pagesize - - size - - address-width + +allOf: + - if: + properties: + compatible: + not: + contains: + const: cypress,fm25 + then: + required: + - pagesize + - size + - address-width additionalProperties: false @@ -125,4 +138,10 @@ examples: size = <32768>; address-width = <16>; }; + + fram@1 { + compatible = "cypress,fm25", "atmel,at25"; + reg = <1>; + spi-max-frequency = <40000000>; + }; }; diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig index 0f791bfdc1f5..f0a7531f354c 100644 --- a/drivers/misc/eeprom/Kconfig +++ b/drivers/misc/eeprom/Kconfig @@ -32,12 +32,13 @@ config EEPROM_AT24 will be called at24. config EEPROM_AT25 - tristate "SPI EEPROMs from most vendors" + tristate "SPI EEPROMs (FRAMs) from most vendors" depends on SPI && SYSFS select NVMEM select NVMEM_SYSFS help - Enable this driver to get read/write support to most SPI EEPROMs, + Enable this driver to get read/write support to most SPI EEPROMs + and Cypress FRAMs, after you configure the board init code to know about each eeprom on your target board. diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c index b76e4901b4a4..6e26de68a001 100644 --- a/drivers/misc/eeprom/at25.c +++ b/drivers/misc/eeprom/at25.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * at25.c -- support most SPI EEPROMs, such as Atmel AT25 models + * and Cypress FRAMs FM25 models * * Copyright (C) 2006 David Brownell */ @@ -16,6 +17,9 @@ #include #include #include +#include +#include +#include /* * NOTE: this is an *EEPROM* driver. The vagaries of product naming @@ -27,6 +31,7 @@ * AT25M02, AT25128B */ +#define FM25_SN_LEN 8 /* serial number length */ struct at25_data { struct spi_device *spi; struct mutex lock; @@ -34,6 +39,7 @@ struct at25_data { unsigned addrlen; struct nvmem_config nvmem_config; struct nvmem_device *nvmem; + u8 sernum[FM25_SN_LEN]; }; #define AT25_WREN 0x06 /* latch the write enable */ @@ -42,6 +48,9 @@ struct at25_data { #define AT25_WRSR 0x01 /* write status register */ #define AT25_READ 0x03 /* read byte(s) */ #define AT25_WRITE 0x02 /* write byte(s)/sector */ +#define FM25_SLEEP 0xb9 /* enter sleep mode */ +#define FM25_RDID 0x9f /* read device ID */ +#define FM25_RDSN 0xc3 /* read S/N */ #define AT25_SR_nRDY 0x01 /* nRDY = write-in-progress */ #define AT25_SR_WEN 0x02 /* write enable (latched) */ @@ -51,6 +60,8 @@ struct at25_data { #define AT25_INSTR_BIT3 0x08 /* Additional address bit in instr */ +#define FM25_ID_LEN 9 /* ID length */ + #define EE_MAXADDRLEN 3 /* 24 bit addresses, up to 2 MBytes */ /* Specs often allow 5 msec for a page write, sometimes 20 msec; @@ -58,6 +69,9 @@ struct at25_data { */ #define EE_TIMEOUT 25 +#define IS_EEPROM 0 +#define IS_FRAM 1 + /*-------------------------------------------------------------------------*/ #define io_limit PAGE_SIZE /* bytes */ @@ -129,6 +143,51 @@ static int at25_ee_read(void *priv, unsigned int offset, return status; } +/* + * read extra registers as ID or serial number + */ +static int fm25_aux_read(struct at25_data *at25, u8 *buf, uint8_t command, + int len) +{ + int status; + struct spi_transfer t[2]; + struct spi_message m; + + spi_message_init(&m); + memset(t, 0, sizeof(t)); + + t[0].tx_buf = &command; + t[0].len = 1; + spi_message_add_tail(&t[0], &m); + + t[1].rx_buf = buf; + t[1].len = len; + spi_message_add_tail(&t[1], &m); + + mutex_lock(&at25->lock); + + status = spi_sync(at25->spi, &m); + dev_dbg(&at25->spi->dev, "read %d aux bytes --> %d\n", len, status); + + mutex_unlock(&at25->lock); + return status; +} + +static ssize_t sernum_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct at25_data *at25; + + at25 = dev_get_drvdata(dev); + return sysfs_emit(buf, "%*ph\n", sizeof(at25->sernum), at25->sernum); +} +static DEVICE_ATTR_RO(sernum); + +static struct attribute *sernum_attrs[] = { + &dev_attr_sernum.attr, + NULL, +}; +ATTRIBUTE_GROUPS(sernum); + static int at25_ee_write(void *priv, unsigned int off, void *val, size_t count) { struct at25_data *at25 = priv; @@ -303,34 +362,39 @@ static int at25_fw_to_chip(struct device *dev, struct spi_eeprom *chip) return 0; } +static const struct of_device_id at25_of_match[] = { + { .compatible = "atmel,at25", .data = (const void *)IS_EEPROM }, + { .compatible = "cypress,fm25", .data = (const void *)IS_FRAM }, + { } +}; +MODULE_DEVICE_TABLE(of, at25_of_match); + static int at25_probe(struct spi_device *spi) { struct at25_data *at25 = NULL; struct spi_eeprom chip; int err; int sr; - int addrlen; + u8 id[FM25_ID_LEN]; + u8 sernum[FM25_SN_LEN]; + int i; + const struct of_device_id *match; + int is_fram = 0; + + match = of_match_device(of_match_ptr(at25_of_match), &spi->dev); + if (match) + is_fram = (int)match->data; /* Chip description */ if (!spi->dev.platform_data) { - err = at25_fw_to_chip(&spi->dev, &chip); - if (err) - return err; + if (!is_fram) { + err = at25_fw_to_chip(&spi->dev, &chip); + if (err) + return err; + } } else chip = *(struct spi_eeprom *)spi->dev.platform_data; - /* For now we only support 8/16/24 bit addressing */ - if (chip.flags & EE_ADDR1) - addrlen = 1; - else if (chip.flags & EE_ADDR2) - addrlen = 2; - else if (chip.flags & EE_ADDR3) - addrlen = 3; - else { - dev_dbg(&spi->dev, "unsupported address type\n"); - return -EINVAL; - } - /* Ping the chip ... the status register is pretty portable, * unlike probing manufacturer IDs. We do expect that system * firmware didn't write it in the past few milliseconds! @@ -349,9 +413,51 @@ static int at25_probe(struct spi_device *spi) at25->chip = chip; at25->spi = spi; spi_set_drvdata(spi, at25); - at25->addrlen = addrlen; - at25->nvmem_config.type = NVMEM_TYPE_EEPROM; + if (is_fram) { + /* Get ID of chip */ + fm25_aux_read(at25, id, FM25_RDID, FM25_ID_LEN); + if (id[6] != 0xc2) { + dev_err(&spi->dev, + "Error: no Cypress FRAM (id %02x)\n", id[6]); + return -ENODEV; + } + /* set size found in ID */ + if (id[7] < 0x21 || id[7] > 0x26) { + dev_err(&spi->dev, "Error: unsupported size (id %02x)\n", id[7]); + return -ENODEV; + } + chip.byte_len = int_pow(2, id[7] - 0x21 + 4) * 1024; + + if (at25->chip.byte_len > 64 * 1024) + at25->chip.flags |= EE_ADDR3; + else + at25->chip.flags |= EE_ADDR2; + + if (id[8]) { + fm25_aux_read(at25, sernum, FM25_RDSN, FM25_SN_LEN); + /* swap byte order */ + for (i = 0; i < FM25_SN_LEN; i++) + at25->sernum[i] = sernum[FM25_SN_LEN - 1 - i]; + } + + at25->chip.page_size = PAGE_SIZE; + strncpy(at25->chip.name, "fm25", sizeof(at25->chip.name)); + } + + /* For now we only support 8/16/24 bit addressing */ + if (at25->chip.flags & EE_ADDR1) + at25->addrlen = 1; + else if (at25->chip.flags & EE_ADDR2) + at25->addrlen = 2; + else if (at25->chip.flags & EE_ADDR3) + at25->addrlen = 3; + else { + dev_dbg(&spi->dev, "unsupported address type\n"); + return -EINVAL; + } + + at25->nvmem_config.type = is_fram ? NVMEM_TYPE_FRAM : NVMEM_TYPE_EEPROM; at25->nvmem_config.name = dev_name(&spi->dev); at25->nvmem_config.dev = &spi->dev; at25->nvmem_config.read_only = chip.flags & EE_READONLY; @@ -370,27 +476,22 @@ static int at25_probe(struct spi_device *spi) if (IS_ERR(at25->nvmem)) return PTR_ERR(at25->nvmem); - dev_info(&spi->dev, "%d %s %s eeprom%s, pagesize %u\n", - (chip.byte_len < 1024) ? chip.byte_len : (chip.byte_len / 1024), - (chip.byte_len < 1024) ? "Byte" : "KByte", - at25->chip.name, - (chip.flags & EE_READONLY) ? " (readonly)" : "", - at25->chip.page_size); + dev_info(&spi->dev, "%d %s %s %s%s, pagesize %u\n", + (chip.byte_len < 1024) ? chip.byte_len : (chip.byte_len / 1024), + (chip.byte_len < 1024) ? "Byte" : "KByte", + at25->chip.name, is_fram ? "fram" : "eeprom", + (chip.flags & EE_READONLY) ? " (readonly)" : "", + at25->chip.page_size); return 0; } /*-------------------------------------------------------------------------*/ -static const struct of_device_id at25_of_match[] = { - { .compatible = "atmel,at25", }, - { } -}; -MODULE_DEVICE_TABLE(of, at25_of_match); - static struct spi_driver at25_driver = { .driver = { .name = "at25", .of_match_table = at25_of_match, + .dev_groups = sernum_groups, }, .probe = at25_probe, }; diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index b3c28a2d4c10..4d1c4f83b22f 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -180,6 +180,7 @@ static const char * const nvmem_type_str[] = { [NVMEM_TYPE_EEPROM] = "EEPROM", [NVMEM_TYPE_OTP] = "OTP", [NVMEM_TYPE_BATTERY_BACKED] = "Battery backed", + [NVMEM_TYPE_FRAM] = "FRAM", }; #ifdef CONFIG_DEBUG_LOCK_ALLOC @@ -359,6 +360,9 @@ static int nvmem_sysfs_setup_compat(struct nvmem_device *nvmem, if (!config->base_dev) return -EINVAL; + if (config->type == NVMEM_TYPE_FRAM) + bin_attr_nvmem_eeprom_compat.attr.name = "fram"; + nvmem->eeprom = bin_attr_nvmem_eeprom_compat; nvmem->eeprom.attr.mode = nvmem_bin_attr_get_umode(nvmem); nvmem->eeprom.size = nvmem->size; diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h index e162b757b6d5..890003565761 100644 --- a/include/linux/nvmem-provider.h +++ b/include/linux/nvmem-provider.h @@ -25,6 +25,7 @@ enum nvmem_type { NVMEM_TYPE_EEPROM, NVMEM_TYPE_OTP, NVMEM_TYPE_BATTERY_BACKED, + NVMEM_TYPE_FRAM, }; #define NVMEM_DEVID_NONE (-1) -- cgit v1.2.3 From 604288bc61965a3acb20e7ff04379a5d3d289bd8 Mon Sep 17 00:00:00 2001 From: Jiri Prchal Date: Fri, 11 Jun 2021 16:27:06 +0200 Subject: nvmem: eeprom: at25: fix type compiler warnings Fixes: drivers/misc/eeprom/at25.c:181:28: warning: field width should have type 'int', but argument has type 'unsigned long' drivers/misc/eeprom/at25.c:386:13: warning: cast to smaller integer type 'int' from 'const void *' Reported-by: kernel test robot Signed-off-by: Jiri Prchal Fixes: fd307a4ad332 ("nvmem: prepare basics for FRAM support") Link: https://lore.kernel.org/r/20210611142706.27336-1-jiri.prchal@aksignal.cz Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/at25.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c index 6e26de68a001..744f7abb22ee 100644 --- a/drivers/misc/eeprom/at25.c +++ b/drivers/misc/eeprom/at25.c @@ -178,7 +178,7 @@ static ssize_t sernum_show(struct device *dev, struct device_attribute *attr, ch struct at25_data *at25; at25 = dev_get_drvdata(dev); - return sysfs_emit(buf, "%*ph\n", sizeof(at25->sernum), at25->sernum); + return sysfs_emit(buf, "%*ph\n", (int)sizeof(at25->sernum), at25->sernum); } static DEVICE_ATTR_RO(sernum); @@ -379,11 +379,11 @@ static int at25_probe(struct spi_device *spi) u8 sernum[FM25_SN_LEN]; int i; const struct of_device_id *match; - int is_fram = 0; + unsigned long is_fram = 0; match = of_match_device(of_match_ptr(at25_of_match), &spi->dev); if (match) - is_fram = (int)match->data; + is_fram = (unsigned long)match->data; /* Chip description */ if (!spi->dev.platform_data) { -- cgit v1.2.3 From eab61fb1cc2eeeffbceb2cf891c1b7272141af82 Mon Sep 17 00:00:00 2001 From: Jiri Prchal Date: Fri, 11 Jun 2021 17:24:16 +0200 Subject: nvmem: eeprom: at25: fram discovery simplification Changed "is_fram" to bool and set it based on compatible string. Signed-off-by: Jiri Prchal Link: https://lore.kernel.org/r/20210611152416.68386-1-jiri.prchal@aksignal.cz Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/at25.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c index 744f7abb22ee..4d09b672ac3c 100644 --- a/drivers/misc/eeprom/at25.c +++ b/drivers/misc/eeprom/at25.c @@ -69,9 +69,6 @@ struct at25_data { */ #define EE_TIMEOUT 25 -#define IS_EEPROM 0 -#define IS_FRAM 1 - /*-------------------------------------------------------------------------*/ #define io_limit PAGE_SIZE /* bytes */ @@ -363,8 +360,8 @@ static int at25_fw_to_chip(struct device *dev, struct spi_eeprom *chip) } static const struct of_device_id at25_of_match[] = { - { .compatible = "atmel,at25", .data = (const void *)IS_EEPROM }, - { .compatible = "cypress,fm25", .data = (const void *)IS_FRAM }, + { .compatible = "atmel,at25",}, + { .compatible = "cypress,fm25",}, { } }; MODULE_DEVICE_TABLE(of, at25_of_match); @@ -379,11 +376,11 @@ static int at25_probe(struct spi_device *spi) u8 sernum[FM25_SN_LEN]; int i; const struct of_device_id *match; - unsigned long is_fram = 0; + bool is_fram = 0; match = of_match_device(of_match_ptr(at25_of_match), &spi->dev); - if (match) - is_fram = (unsigned long)match->data; + if (match && !strcmp(match->compatible, "cypress,fm25")) + is_fram = 1; /* Chip description */ if (!spi->dev.platform_data) { -- cgit v1.2.3 From c7e9967668d98f868fb577fd95d84fdb1ba0446c Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Thu, 10 Jun 2021 14:44:33 -0700 Subject: mei: hdcp: SPDX tag should be the first line checkpatch looks for the tag on the first line. So delete empty first line Signed-off-by: Tom Rix Link: https://lore.kernel.org/r/20210610214438.3161140-4-trix@redhat.com Acked-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/hdcp/Kconfig | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/mei/hdcp/Kconfig b/drivers/misc/mei/hdcp/Kconfig index 95b2d6d37f10..54e1c9526909 100644 --- a/drivers/misc/mei/hdcp/Kconfig +++ b/drivers/misc/mei/hdcp/Kconfig @@ -1,4 +1,3 @@ - # SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2019, Intel Corporation. All rights reserved. # -- cgit v1.2.3 From 7bd1e23e5f1381c58ed2a68045ac042dd174c55f Mon Sep 17 00:00:00 2001 From: Moti Haimovski Date: Thu, 8 Apr 2021 21:18:03 +0300 Subject: habanalabs: increase ELBI reset timeout for PLDM On PLDM, in case of NIC hangs, the ELBI reset to take much longer than expected. As a result an increase in the ELBI reset timeout is required. Signed-off-by: Moti Haimovski Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/pci/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/pci/pci.c b/drivers/misc/habanalabs/common/pci/pci.c index e941b7eef346..5d07ca53d9ce 100644 --- a/drivers/misc/habanalabs/common/pci/pci.c +++ b/drivers/misc/habanalabs/common/pci/pci.c @@ -10,7 +10,7 @@ #include -#define HL_PLDM_PCI_ELBI_TIMEOUT_MSEC (HL_PCI_ELBI_TIMEOUT_MSEC * 10) +#define HL_PLDM_PCI_ELBI_TIMEOUT_MSEC (HL_PCI_ELBI_TIMEOUT_MSEC * 100) #define IATU_REGION_CTRL_REGION_EN_MASK BIT(31) #define IATU_REGION_CTRL_MATCH_MODE_MASK BIT(30) -- cgit v1.2.3 From 3b39840083ef809e71206e9717d5bd502317e696 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Sun, 11 Apr 2021 08:43:50 +0300 Subject: habanalabs: update firmware files to latest Update the firmware files to the latest from the firmware team. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/include/common/cpucp_if.h | 4 +++- drivers/misc/habanalabs/include/common/hl_boot_if.h | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/include/common/cpucp_if.h b/drivers/misc/habanalabs/include/common/cpucp_if.h index 27cd0ba99aa3..bf10ca8d2457 100644 --- a/drivers/misc/habanalabs/include/common/cpucp_if.h +++ b/drivers/misc/habanalabs/include/common/cpucp_if.h @@ -107,7 +107,9 @@ enum pq_init_status { PQ_INIT_STATUS_NA = 0, PQ_INIT_STATUS_READY_FOR_CP, PQ_INIT_STATUS_READY_FOR_HOST, - PQ_INIT_STATUS_READY_FOR_CP_SINGLE_MSI + PQ_INIT_STATUS_READY_FOR_CP_SINGLE_MSI, + PQ_INIT_STATUS_LEN_NOT_POWER_OF_TWO_ERR, + PQ_INIT_STATUS_ILLEGAL_Q_ADDR_ERR }; /* diff --git a/drivers/misc/habanalabs/include/common/hl_boot_if.h b/drivers/misc/habanalabs/include/common/hl_boot_if.h index e0a259e0495c..84c14688d69a 100644 --- a/drivers/misc/habanalabs/include/common/hl_boot_if.h +++ b/drivers/misc/habanalabs/include/common/hl_boot_if.h @@ -8,7 +8,7 @@ #ifndef HL_BOOT_IF_H #define HL_BOOT_IF_H -#define LKD_HARD_RESET_MAGIC 0xED7BD694 +#define LKD_HARD_RESET_MAGIC 0xED7BD694 /* deprecated - do not use */ #define HL_POWER9_HOST_MAGIC 0x1DA30009 #define BOOT_FIT_SRAM_OFFSET 0x200000 -- cgit v1.2.3 From 6e16ab6c326cd149c086ccbab6da9ccff1a528ff Mon Sep 17 00:00:00 2001 From: Ohad Sharabi Date: Thu, 25 Mar 2021 10:06:26 +0200 Subject: habanalabs: prepare preboot stage to dynamic f/w load Start the skeleton for the dynamic F/W load by marking current preboot code path as legacy. Signed-off-by: Ohad Sharabi Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 78 +++++++++++++++++++++++----- drivers/misc/habanalabs/common/habanalabs.h | 8 ++- 2 files changed, 71 insertions(+), 15 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index 0713b2c12d54..a45aea4730cf 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -809,21 +809,15 @@ static void detect_cpu_boot_status(struct hl_device *hdev, u32 status) } } -int hl_fw_read_preboot_status(struct hl_device *hdev, u32 cpu_boot_status_reg, - u32 cpu_security_boot_status_reg, u32 boot_err0_reg, - u32 timeout) +static int hl_fw_read_preboot_caps(struct hl_device *hdev, + u32 cpu_boot_status_reg, + u32 cpu_boot_caps_reg, + u32 boot_err0_reg, u32 timeout) { struct asic_fixed_properties *prop = &hdev->asic_prop; - u32 status, security_status; + u32 status; int rc; - /* pldm was added for cases in which we use preboot on pldm and want - * to load boot fit, but we can't wait for preboot because it runs - * very slowly - */ - if (!(hdev->fw_components & FW_TYPE_PREBOOT_CPU) || hdev->pldm) - return 0; - /* Need to check two possible scenarios: * * CPU_BOOT_STATUS_WAITING_FOR_BOOT_FIT - for newer firmwares where @@ -846,7 +840,7 @@ int hl_fw_read_preboot_status(struct hl_device *hdev, u32 cpu_boot_status_reg, timeout); if (rc) { - dev_err(hdev->dev, "Failed to read preboot version\n"); + dev_err(hdev->dev, "CPU boot ready status timeout\n"); detect_cpu_boot_status(hdev, status); /* If we read all FF, then something is totally wrong, no point @@ -854,15 +848,39 @@ int hl_fw_read_preboot_status(struct hl_device *hdev, u32 cpu_boot_status_reg, */ if (status != -1) fw_read_errors(hdev, boot_err0_reg, - cpu_security_boot_status_reg); + cpu_boot_status_reg); return -EIO; } + prop->fw_preboot_caps_map = RREG32(cpu_boot_caps_reg); + + /* + * For now- force dynamic_fw_load to false as LKD does not yet + * implements all necessary parts of it. + * TODO: once dynamic load is ready set to: + * prop->dynamic_fw_load = !!(prop->fw_preboot_caps_map & + * CPU_BOOT_DEV_STS0_FW_LD_COM_EN) + */ + prop->dynamic_fw_load = 0; + + dev_dbg(hdev->dev, "Attempting %s FW load\n", + prop->dynamic_fw_load ? "dynamic" : "legacy"); + return 0; +} + +static int hl_fw_read_preboot_status_legacy(struct hl_device *hdev, + u32 cpu_boot_status_reg, u32 cpu_security_boot_status_reg, + u32 boot_err0_reg, u32 timeout) +{ + struct asic_fixed_properties *prop = &hdev->asic_prop; + u32 security_status; + int rc; + rc = hdev->asic_funcs->read_device_fw_version(hdev, FW_COMP_PREBOOT); if (rc) return rc; - security_status = RREG32(cpu_security_boot_status_reg); + security_status = prop->fw_preboot_caps_map; /* We read security status multiple times during boot: * 1. preboot - a. Check whether the security status bits are valid @@ -904,6 +922,38 @@ int hl_fw_read_preboot_status(struct hl_device *hdev, u32 cpu_boot_status_reg, return 0; } +int hl_fw_read_preboot_status(struct hl_device *hdev, u32 cpu_boot_status_reg, + u32 cpu_boot_caps_reg, u32 boot_err0_reg, + u32 timeout) +{ + int rc; + + /* pldm was added for cases in which we use preboot on pldm and want + * to load boot fit, but we can't wait for preboot because it runs + * very slowly + */ + if (!(hdev->fw_components & FW_TYPE_PREBOOT_CPU) || hdev->pldm) + return 0; + + /* + * In order to determine boot method (static VS dymanic) we need to + * read the boot caps register + */ + rc = hl_fw_read_preboot_caps(hdev, cpu_boot_status_reg, + cpu_boot_caps_reg, boot_err0_reg, + timeout); + if (rc) + return rc; + + if (!hdev->asic_prop.dynamic_fw_load) + return hl_fw_read_preboot_status_legacy(hdev, cpu_boot_status_reg, + cpu_boot_caps_reg, boot_err0_reg, + timeout); + + dev_err(hdev->dev, "Dynamic FW load is not supported\n"); + return -EINVAL; +} + int hl_fw_init_cpu(struct hl_device *hdev, u32 cpu_boot_status_reg, u32 msg_to_cpu_reg, u32 cpu_msg_status_reg, u32 cpu_security_boot_status_reg, u32 boot_err0_reg, diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index 6579f8767abd..72726de6575c 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -420,6 +420,9 @@ struct hl_mmu_properties { * @cb_pool_cb_size: size of each CB in the CB pool. * @max_pending_cs: maximum of concurrent pending command submissions * @max_queues: maximum amount of queues in the system + * @fw_preboot_caps_map: bitmap representation of preboot cpu capabilities + * reported by FW, bit description can be found in + * CPU_BOOT_DEV_STS* * @fw_boot_cpu_security_map: bitmap representation of boot cpu security status * reported by FW, bit description can be found in * CPU_BOOT_DEV_STS* @@ -446,6 +449,7 @@ struct hl_mmu_properties { * @hard_reset_done_by_fw: true if firmware is handling hard reset flow * @num_functional_hbms: number of functional HBMs in each DCORE. * @iatu_done_by_fw: true if iATU configuration is being done by FW. + * @dynamic_fw_load: is dynamic FW load is supported. */ struct asic_fixed_properties { struct hw_queue_properties *hw_queues_props; @@ -491,6 +495,7 @@ struct asic_fixed_properties { u32 cb_pool_cb_size; u32 max_pending_cs; u32 max_queues; + u32 fw_preboot_caps_map; u32 fw_boot_cpu_security_map; u32 fw_app_security_map; u16 collective_first_sob; @@ -510,6 +515,7 @@ struct asic_fixed_properties { u8 hard_reset_done_by_fw; u8 num_functional_hbms; u8 iatu_done_by_fw; + u8 dynamic_fw_load; }; /** @@ -2404,7 +2410,7 @@ int hl_fw_init_cpu(struct hl_device *hdev, u32 cpu_boot_status_reg, u32 cpu_security_boot_status_reg, u32 boot_err0_reg, bool skip_bmc, u32 cpu_timeout, u32 boot_fit_timeout); int hl_fw_read_preboot_status(struct hl_device *hdev, u32 cpu_boot_status_reg, - u32 cpu_security_boot_status_reg, u32 boot_err0_reg, + u32 cpu_boot_caps_reg, u32 boot_err0_reg, u32 timeout); int hl_pci_bars_map(struct hl_device *hdev, const char * const name[3], -- cgit v1.2.3 From 364690429a603ac4a7e8df3c3b98b51c914c7c3f Mon Sep 17 00:00:00 2001 From: Ohad Sharabi Date: Thu, 8 Apr 2021 10:22:17 +0300 Subject: habanalabs: request f/w in separate function This refactor is needed due to the dynamic FW load in which requesting the FW file (and getting its attributes) is not immediately followed by copying FW file content. Signed-off-by: Ohad Sharabi Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 65 +++++++++++++++++++--------- 1 file changed, 44 insertions(+), 21 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index a45aea4730cf..af9fbebabbfe 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -12,6 +12,47 @@ #include #define FW_FILE_MAX_SIZE 0x1400000 /* maximum size of 20MB */ + +static int hl_request_fw(struct hl_device *hdev, + const struct firmware **firmware_p, + const char *fw_name) +{ + size_t fw_size; + int rc; + + rc = request_firmware(firmware_p, fw_name, hdev->dev); + if (rc) { + dev_err(hdev->dev, "Firmware file %s is not found! (error %d)\n", + fw_name, rc); + goto out; + } + + fw_size = (*firmware_p)->size; + if ((fw_size % 4) != 0) { + dev_err(hdev->dev, "Illegal %s firmware size %zu\n", + fw_name, fw_size); + rc = -EINVAL; + goto release_fw; + } + + dev_dbg(hdev->dev, "%s firmware size == %zu\n", fw_name, fw_size); + + if (fw_size > FW_FILE_MAX_SIZE) { + dev_err(hdev->dev, + "FW file size %zu exceeds maximum of %u bytes\n", + fw_size, FW_FILE_MAX_SIZE); + rc = -EINVAL; + goto release_fw; + } + + return 0; + +release_fw: + release_firmware(*firmware_p); +out: + return rc; +} + /** * hl_fw_load_fw_to_device() - Load F/W code to device's memory. * @@ -33,29 +74,11 @@ int hl_fw_load_fw_to_device(struct hl_device *hdev, const char *fw_name, size_t fw_size; int rc; - rc = request_firmware(&fw, fw_name, hdev->dev); - if (rc) { - dev_err(hdev->dev, "Firmware file %s is not found!\n", fw_name); - goto out; - } + rc = hl_request_fw(hdev, &fw, fw_name); + if (rc) + return rc; fw_size = fw->size; - if ((fw_size % 4) != 0) { - dev_err(hdev->dev, "Illegal %s firmware size %zu\n", - fw_name, fw_size); - rc = -EINVAL; - goto out; - } - - dev_dbg(hdev->dev, "%s firmware size == %zu\n", fw_name, fw_size); - - if (fw_size > FW_FILE_MAX_SIZE) { - dev_err(hdev->dev, - "FW file size %zu exceeds maximum of %u bytes\n", - fw_size, FW_FILE_MAX_SIZE); - rc = -EINVAL; - goto out; - } if (size - src_offset > fw_size) { dev_err(hdev->dev, -- cgit v1.2.3 From a22f0ec0731ddf6355e6bf93ded189fca2542cdf Mon Sep 17 00:00:00 2001 From: Ohad Sharabi Date: Sun, 11 Apr 2021 23:06:46 +0300 Subject: habanalabs: refactor init device cpu code Replace multiple arguments to init device CPU function by passing firmware loader managing structure that is initialized per ASIC with the loader parameters. In addition, the FW loader management structure is now part of the habanalabs device, this way the loader parameters will be able to be communicated across various boot stages. Signed-off-by: Ohad Sharabi Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 30 +++++++++++++++++--------- drivers/misc/habanalabs/common/habanalabs.h | 32 ++++++++++++++++++++++++---- drivers/misc/habanalabs/gaudi/gaudi.c | 24 +++++++++++++++------ drivers/misc/habanalabs/goya/goya.c | 24 +++++++++++++++------ 4 files changed, 82 insertions(+), 28 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index af9fbebabbfe..e0b0b98b7879 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -977,18 +977,26 @@ int hl_fw_read_preboot_status(struct hl_device *hdev, u32 cpu_boot_status_reg, return -EINVAL; } -int hl_fw_init_cpu(struct hl_device *hdev, u32 cpu_boot_status_reg, - u32 msg_to_cpu_reg, u32 cpu_msg_status_reg, - u32 cpu_security_boot_status_reg, u32 boot_err0_reg, - bool skip_bmc, u32 cpu_timeout, u32 boot_fit_timeout) +int hl_fw_init_cpu(struct hl_device *hdev) { + u32 cpu_msg_status_reg, cpu_timeout, msg_to_cpu_reg, status; + u32 cpu_boot_status_reg, cpu_security_boot_status_reg; struct asic_fixed_properties *prop = &hdev->asic_prop; - u32 status; + struct fw_load_mgr *fw_loader; int rc; if (!(hdev->fw_components & FW_TYPE_BOOT_CPU)) return 0; + /* init loader parameters */ + hdev->asic_funcs->init_firmware_loader(hdev); + fw_loader = &hdev->fw_loader; + cpu_security_boot_status_reg = fw_loader->cpu_boot_status_reg; + cpu_msg_status_reg = fw_loader->cpu_cmd_status_to_host_reg; + cpu_boot_status_reg = fw_loader->cpu_boot_status_reg; + msg_to_cpu_reg = fw_loader->kmd_msg_to_cpu_reg; + cpu_timeout = fw_loader->cpu_timeout; + dev_info(hdev->dev, "Going to wait for device boot (up to %lds)\n", cpu_timeout / USEC_PER_SEC); @@ -999,7 +1007,7 @@ int hl_fw_init_cpu(struct hl_device *hdev, u32 cpu_boot_status_reg, status, status == CPU_BOOT_STATUS_WAITING_FOR_BOOT_FIT, 10000, - boot_fit_timeout); + fw_loader->boot_fit_timeout); if (rc) { dev_dbg(hdev->dev, @@ -1022,7 +1030,7 @@ int hl_fw_init_cpu(struct hl_device *hdev, u32 cpu_boot_status_reg, status, status == CPU_MSG_OK, 10000, - boot_fit_timeout); + fw_loader->boot_fit_timeout); if (rc) { dev_err(hdev->dev, @@ -1092,7 +1100,7 @@ int hl_fw_init_cpu(struct hl_device *hdev, u32 cpu_boot_status_reg, if (rc) goto out; - if (skip_bmc) { + if (fw_loader->skip_bmc) { WREG32(msg_to_cpu_reg, KMD_MSG_SKIP_BMC); rc = hl_poll_timeout( @@ -1139,7 +1147,8 @@ int hl_fw_init_cpu(struct hl_device *hdev, u32 cpu_boot_status_reg, goto out; } - rc = fw_read_errors(hdev, boot_err0_reg, cpu_security_boot_status_reg); + rc = fw_read_errors(hdev, fw_loader->boot_err0_reg, + cpu_security_boot_status_reg); if (rc) return rc; @@ -1168,7 +1177,8 @@ int hl_fw_init_cpu(struct hl_device *hdev, u32 cpu_boot_status_reg, return 0; out: - fw_read_errors(hdev, boot_err0_reg, cpu_security_boot_status_reg); + fw_read_errors(hdev, fw_loader->boot_err0_reg, + cpu_security_boot_status_reg); return rc; } diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index 72726de6575c..f58325b7728a 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -818,6 +818,28 @@ enum div_select_defs { DIV_SEL_DIVIDED_PLL = 3, }; +/** + * struct fw_load_mgr - manager FW loading process + * @kmd_msg_to_cpu_reg: register address for KMD->CPU messages + * @cpu_cmd_status_to_host_reg: register address for CPU command status response + * @cpu_boot_status_reg: boot status register + * @cpu_boot_dev_status_reg: boot device status register + * @boot_err0_reg: boot error register + * @cpu_timeout: CPU response timeout in usec + * @boot_fit_timeout: Boot fit load timeout in usec + * @skip_bmc: should BMC be skipped + */ +struct fw_load_mgr { + u32 kmd_msg_to_cpu_reg; + u32 cpu_cmd_status_to_host_reg; + u32 cpu_boot_status_reg; + u32 cpu_boot_dev_status_reg; + u32 boot_err0_reg; + u32 cpu_timeout; + u32 boot_fit_timeout; + u8 skip_bmc; +}; + /** * struct hl_asic_funcs - ASIC specific functions that are can be called from * common code. @@ -939,6 +961,7 @@ enum div_select_defs { * @get_msi_info: Retrieve asic-specific MSI ID of the f/w async event * @map_pll_idx_to_fw_idx: convert driver specific per asic PLL index to * generic f/w compatible PLL Indexes + *@init_firmware_loader: initialize data for FW loader. */ struct hl_asic_funcs { int (*early_init)(struct hl_device *hdev); @@ -1064,6 +1087,7 @@ struct hl_asic_funcs { void (*enable_events_from_fw)(struct hl_device *hdev); void (*get_msi_info)(u32 *table); int (*map_pll_idx_to_fw_idx)(u32 pll_idx); + void (*init_firmware_loader)(struct hl_device *hdev); }; @@ -1960,6 +1984,7 @@ struct hl_mmu_funcs { * @aggregated_cs_counters: aggregated cs counters among all contexts * @mmu_priv: device-specific MMU data. * @mmu_func: device-related MMU functions. + * @fw_loader: FW loader manager. * @dram_used_mem: current DRAM memory consumption. * @timeout_jiffies: device CS timeout value. * @max_power: the max power of the device, as configured by the sysadmin. This @@ -2085,6 +2110,8 @@ struct hl_device { struct hl_mmu_priv mmu_priv; struct hl_mmu_funcs mmu_func[MMU_NUM_PGT_LOCATIONS]; + struct fw_load_mgr fw_loader; + atomic64_t dram_used_mem; u64 timeout_jiffies; u64 max_power; @@ -2405,10 +2432,7 @@ int get_used_pll_index(struct hl_device *hdev, u32 input_pll_index, int hl_fw_cpucp_pll_info_get(struct hl_device *hdev, u32 pll_index, u16 *pll_freq_arr); int hl_fw_cpucp_power_get(struct hl_device *hdev, u64 *power); -int hl_fw_init_cpu(struct hl_device *hdev, u32 cpu_boot_status_reg, - u32 msg_to_cpu_reg, u32 cpu_msg_status_reg, - u32 cpu_security_boot_status_reg, u32 boot_err0_reg, - bool skip_bmc, u32 cpu_timeout, u32 boot_fit_timeout); +int hl_fw_init_cpu(struct hl_device *hdev); int hl_fw_read_preboot_status(struct hl_device *hdev, u32 cpu_boot_status_reg, u32 cpu_boot_caps_reg, u32 boot_err0_reg, u32 timeout); diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 22f220859b46..42c944efffbc 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -3729,6 +3729,20 @@ static int gaudi_read_device_fw_version(struct hl_device *hdev, return 0; } +static void gaudi_init_firmware_loader(struct hl_device *hdev) +{ + struct fw_load_mgr *fw_loader = &hdev->fw_loader; + + fw_loader->kmd_msg_to_cpu_reg = mmPSOC_GLOBAL_CONF_KMD_MSG_TO_CPU; + fw_loader->cpu_cmd_status_to_host_reg = mmCPU_CMD_STATUS_TO_HOST; + fw_loader->cpu_timeout = GAUDI_CPU_TIMEOUT_USEC; + fw_loader->boot_fit_timeout = GAUDI_BOOT_FIT_REQ_TIMEOUT_USEC; + fw_loader->skip_bmc = !hdev->bmc_enable; + fw_loader->cpu_boot_status_reg = mmPSOC_GLOBAL_CONF_CPU_BOOT_STATUS; + fw_loader->cpu_boot_dev_status_reg = mmCPU_BOOT_DEV_STS0; + fw_loader->boot_err0_reg = mmCPU_BOOT_ERR0; +} + static int gaudi_init_cpu(struct hl_device *hdev) { struct gaudi_device *gaudi = hdev->asic_specific; @@ -3747,12 +3761,7 @@ static int gaudi_init_cpu(struct hl_device *hdev) if (hdev->asic_prop.fw_security_disabled) WREG32(mmCPU_IF_CPU_MSB_ADDR, hdev->cpu_pci_msb_addr); - rc = hl_fw_init_cpu(hdev, mmPSOC_GLOBAL_CONF_CPU_BOOT_STATUS, - mmPSOC_GLOBAL_CONF_KMD_MSG_TO_CPU, - mmCPU_CMD_STATUS_TO_HOST, - mmCPU_BOOT_DEV_STS0, mmCPU_BOOT_ERR0, - !hdev->bmc_enable, GAUDI_CPU_TIMEOUT_USEC, - GAUDI_BOOT_FIT_REQ_TIMEOUT_USEC); + rc = hl_fw_init_cpu(hdev); if (rc) return rc; @@ -8850,7 +8859,8 @@ static const struct hl_asic_funcs gaudi_funcs = { .get_hw_block_id = gaudi_get_hw_block_id, .hw_block_mmap = gaudi_block_mmap, .enable_events_from_fw = gaudi_enable_events_from_fw, - .map_pll_idx_to_fw_idx = gaudi_map_pll_idx_to_fw_idx + .map_pll_idx_to_fw_idx = gaudi_map_pll_idx_to_fw_idx, + .init_firmware_loader = gaudi_init_firmware_loader, }; /** diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c index e0ad2a269779..d554304b6868 100644 --- a/drivers/misc/habanalabs/goya/goya.c +++ b/drivers/misc/habanalabs/goya/goya.c @@ -2445,6 +2445,20 @@ static int goya_read_device_fw_version(struct hl_device *hdev, return 0; } +static void goya_init_firmware_loader(struct hl_device *hdev) +{ + struct fw_load_mgr *fw_loader = &hdev->fw_loader; + + fw_loader->kmd_msg_to_cpu_reg = mmPSOC_GLOBAL_CONF_KMD_MSG_TO_CPU; + fw_loader->cpu_cmd_status_to_host_reg = mmCPU_CMD_STATUS_TO_HOST; + fw_loader->cpu_timeout = GOYA_CPU_TIMEOUT_USEC; + fw_loader->boot_fit_timeout = GOYA_BOOT_FIT_REQ_TIMEOUT_USEC; + fw_loader->skip_bmc = false; + fw_loader->cpu_boot_status_reg = mmPSOC_GLOBAL_CONF_CPU_BOOT_STATUS; + fw_loader->cpu_boot_dev_status_reg = mmCPU_BOOT_DEV_STS0; + fw_loader->boot_err0_reg = mmCPU_BOOT_ERR0; +} + static int goya_init_cpu(struct hl_device *hdev) { struct goya_device *goya = hdev->asic_specific; @@ -2466,12 +2480,7 @@ static int goya_init_cpu(struct hl_device *hdev) return -EIO; } - rc = hl_fw_init_cpu(hdev, mmPSOC_GLOBAL_CONF_CPU_BOOT_STATUS, - mmPSOC_GLOBAL_CONF_UBOOT_MAGIC, - mmCPU_CMD_STATUS_TO_HOST, - mmCPU_BOOT_DEV_STS0, mmCPU_BOOT_ERR0, - false, GOYA_CPU_TIMEOUT_USEC, - GOYA_BOOT_FIT_REQ_TIMEOUT_USEC); + rc = hl_fw_init_cpu(hdev); if (rc) return rc; @@ -5584,7 +5593,8 @@ static const struct hl_asic_funcs goya_funcs = { .get_hw_block_id = goya_get_hw_block_id, .hw_block_mmap = goya_block_mmap, .enable_events_from_fw = goya_enable_events_from_fw, - .map_pll_idx_to_fw_idx = goya_map_pll_idx_to_fw_idx + .map_pll_idx_to_fw_idx = goya_map_pll_idx_to_fw_idx, + .init_firmware_loader = goya_init_firmware_loader }; /* -- cgit v1.2.3 From 08c03a19662fd628e8866d89769d594c1d8c8093 Mon Sep 17 00:00:00 2001 From: Alon Mizrahi Date: Thu, 8 Apr 2021 15:30:59 +0300 Subject: habanalabs: use mmu cache range invalidation Use mmu cache range invalidation instead of entire cache invalidation because it yields better performance. In GOYA and GAUDI, always use entire cache invalidation because these ASICs don't support range invalidation. Signed-off-by: Alon Mizrahi Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/habanalabs.h | 2 +- drivers/misc/habanalabs/common/memory.c | 8 +++-- drivers/misc/habanalabs/gaudi/gaudi.c | 49 +++------------------------ drivers/misc/habanalabs/goya/goya.c | 51 +++-------------------------- 4 files changed, 16 insertions(+), 94 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index f58325b7728a..108ed2d5e9b9 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -1035,7 +1035,7 @@ struct hl_asic_funcs { int (*mmu_invalidate_cache)(struct hl_device *hdev, bool is_hard, u32 flags); int (*mmu_invalidate_cache_range)(struct hl_device *hdev, bool is_hard, - u32 asid, u64 va, u64 size); + u32 flags, u32 asid, u64 va, u64 size); int (*send_heartbeat)(struct hl_device *hdev); void (*set_clock_gating)(struct hl_device *hdev); void (*disable_clock_gating)(struct hl_device *hdev); diff --git a/drivers/misc/habanalabs/common/memory.c b/drivers/misc/habanalabs/common/memory.c index 2938cbbafbbc..b92878d76f23 100644 --- a/drivers/misc/habanalabs/common/memory.c +++ b/drivers/misc/habanalabs/common/memory.c @@ -1117,7 +1117,8 @@ static int map_device_va(struct hl_ctx *ctx, struct hl_mem_in *args, goto map_err; } - rc = hdev->asic_funcs->mmu_invalidate_cache(hdev, false, *vm_type); + rc = hdev->asic_funcs->mmu_invalidate_cache_range(hdev, false, + *vm_type, ctx->asid, ret_vaddr, phys_pg_pack->total_size); mutex_unlock(&ctx->mmu_lock); @@ -1261,8 +1262,9 @@ static int unmap_device_va(struct hl_ctx *ctx, struct hl_mem_in *args, * at the loop end rather than for each iteration */ if (!ctx_free) - rc = hdev->asic_funcs->mmu_invalidate_cache(hdev, true, - *vm_type); + rc = hdev->asic_funcs->mmu_invalidate_cache_range(hdev, true, + *vm_type, ctx->asid, vaddr, + phys_pg_pack->total_size); mutex_unlock(&ctx->mmu_lock); diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 42c944efffbc..05a74f838a16 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -7862,52 +7862,13 @@ static int gaudi_mmu_invalidate_cache(struct hl_device *hdev, bool is_hard, } static int gaudi_mmu_invalidate_cache_range(struct hl_device *hdev, - bool is_hard, u32 asid, u64 va, u64 size) + bool is_hard, u32 flags, + u32 asid, u64 va, u64 size) { - struct gaudi_device *gaudi = hdev->asic_specific; - u32 status, timeout_usec; - u32 inv_data; - u32 pi; - int rc; - - if (!(gaudi->hw_cap_initialized & HW_CAP_MMU) || - hdev->hard_reset_pending) - return 0; - - if (hdev->pldm) - timeout_usec = GAUDI_PLDM_MMU_TIMEOUT_USEC; - else - timeout_usec = MMU_CONFIG_TIMEOUT_USEC; - - /* - * TODO: currently invalidate entire L0 & L1 as in regular hard - * invalidation. Need to apply invalidation of specific cache - * lines with mask of ASID & VA & size. - * Note that L1 with be flushed entirely in any case. + /* Treat as invalidate all because there is no range invalidation + * in Gaudi */ - - /* L0 & L1 invalidation */ - inv_data = RREG32(mmSTLB_CACHE_INV); - /* PI is 8 bit */ - pi = ((inv_data & STLB_CACHE_INV_PRODUCER_INDEX_MASK) + 1) & 0xFF; - WREG32(mmSTLB_CACHE_INV, - (inv_data & STLB_CACHE_INV_INDEX_MASK_MASK) | pi); - - rc = hl_poll_timeout( - hdev, - mmSTLB_INV_CONSUMER_INDEX, - status, - status == pi, - 1000, - timeout_usec); - - if (rc) { - dev_err_ratelimited(hdev->dev, - "MMU cache invalidation timeout\n"); - hl_device_reset(hdev, HL_RESET_HARD); - } - - return rc; + return hdev->asic_funcs->mmu_invalidate_cache(hdev, is_hard, flags); } static int gaudi_mmu_update_asid_hop0_addr(struct hl_device *hdev, diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c index d554304b6868..678fbbc6521b 100644 --- a/drivers/misc/habanalabs/goya/goya.c +++ b/drivers/misc/habanalabs/goya/goya.c @@ -5178,54 +5178,13 @@ static int goya_mmu_invalidate_cache(struct hl_device *hdev, bool is_hard, } static int goya_mmu_invalidate_cache_range(struct hl_device *hdev, - bool is_hard, u32 asid, u64 va, u64 size) + bool is_hard, u32 flags, + u32 asid, u64 va, u64 size) { - struct goya_device *goya = hdev->asic_specific; - u32 status, timeout_usec, inv_data, pi; - int rc; - - if (!(goya->hw_cap_initialized & HW_CAP_MMU) || - hdev->hard_reset_pending) - return 0; - - /* no need in L1 only invalidation in Goya */ - if (!is_hard) - return 0; - - if (hdev->pldm) - timeout_usec = GOYA_PLDM_MMU_TIMEOUT_USEC; - else - timeout_usec = MMU_CONFIG_TIMEOUT_USEC; - - /* - * TODO: currently invalidate entire L0 & L1 as in regular hard - * invalidation. Need to apply invalidation of specific cache lines with - * mask of ASID & VA & size. - * Note that L1 with be flushed entirely in any case. + /* Treat as invalidate all because there is no range invalidation + * in Goya */ - - /* L0 & L1 invalidation */ - inv_data = RREG32(mmSTLB_CACHE_INV); - /* PI is 8 bit */ - pi = ((inv_data & STLB_CACHE_INV_PRODUCER_INDEX_MASK) + 1) & 0xFF; - WREG32(mmSTLB_CACHE_INV, - (inv_data & STLB_CACHE_INV_INDEX_MASK_MASK) | pi); - - rc = hl_poll_timeout( - hdev, - mmSTLB_INV_CONSUMER_INDEX, - status, - status == pi, - 1000, - timeout_usec); - - if (rc) { - dev_err_ratelimited(hdev->dev, - "MMU cache invalidation timeout\n"); - hl_device_reset(hdev, HL_RESET_HARD); - } - - return rc; + return hdev->asic_funcs->mmu_invalidate_cache(hdev, is_hard, flags); } int goya_send_heartbeat(struct hl_device *hdev) -- cgit v1.2.3 From 50f036df476c6e58f597f684345141e406b12099 Mon Sep 17 00:00:00 2001 From: Ohad Sharabi Date: Sun, 11 Apr 2021 15:26:28 +0300 Subject: habanalabs: use common fw_version read Instead of using multiple ASIC specific copies of functions to read the FW version use single common one that gets ASIC specific arguments. Signed-off-by: Ohad Sharabi Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 50 ++++++++++++++++++++++++++-- drivers/misc/habanalabs/common/habanalabs.h | 22 ++++++++---- drivers/misc/habanalabs/gaudi/gaudi.c | 45 ++++--------------------- drivers/misc/habanalabs/goya/goya.c | 50 ++++------------------------ 4 files changed, 74 insertions(+), 93 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index e0b0b98b7879..d62ec5bbdb41 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -891,6 +891,49 @@ static int hl_fw_read_preboot_caps(struct hl_device *hdev, return 0; } +static int hl_read_device_fw_version(struct hl_device *hdev, + enum hl_fw_component fwc) +{ + struct fw_load_mgr *fw_loader = &hdev->fw_loader; + const char *name; + u32 ver_off, limit; + char *dest; + + switch (fwc) { + case FW_COMP_BOOT_FIT: + ver_off = RREG32(fw_loader->boot_fit_version_offset_reg); + dest = hdev->asic_prop.uboot_ver; + name = "Boot-fit"; + limit = fw_loader->boot_fit_version_max_off; + break; + case FW_COMP_PREBOOT: + ver_off = RREG32( + fw_loader->preboot_version_offset_reg); + dest = hdev->asic_prop.preboot_ver; + name = "Preboot"; + limit = fw_loader->preboot_version_max_off; + break; + default: + dev_warn(hdev->dev, "Undefined FW component: %d\n", fwc); + return -EIO; + } + + ver_off &= fw_loader->sram_offset_mask; + + if (ver_off < limit) { + memcpy_fromio(dest, + hdev->pcie_bar[fw_loader->sram_bar_id] + ver_off, + VERSION_MAX_LEN); + } else { + dev_err(hdev->dev, "%s version offset (0x%x) is above SRAM\n", + name, ver_off); + strscpy(dest, "unavailable", VERSION_MAX_LEN); + return -EIO; + } + + return 0; +} + static int hl_fw_read_preboot_status_legacy(struct hl_device *hdev, u32 cpu_boot_status_reg, u32 cpu_security_boot_status_reg, u32 boot_err0_reg, u32 timeout) @@ -899,7 +942,7 @@ static int hl_fw_read_preboot_status_legacy(struct hl_device *hdev, u32 security_status; int rc; - rc = hdev->asic_funcs->read_device_fw_version(hdev, FW_COMP_PREBOOT); + rc = hl_read_device_fw_version(hdev, FW_COMP_PREBOOT); if (rc) return rc; @@ -951,6 +994,8 @@ int hl_fw_read_preboot_status(struct hl_device *hdev, u32 cpu_boot_status_reg, { int rc; + hdev->asic_funcs->init_firmware_loader(hdev); + /* pldm was added for cases in which we use preboot on pldm and want * to load boot fit, but we can't wait for preboot because it runs * very slowly @@ -989,7 +1034,6 @@ int hl_fw_init_cpu(struct hl_device *hdev) return 0; /* init loader parameters */ - hdev->asic_funcs->init_firmware_loader(hdev); fw_loader = &hdev->fw_loader; cpu_security_boot_status_reg = fw_loader->cpu_boot_status_reg; cpu_msg_status_reg = fw_loader->cpu_cmd_status_to_host_reg; @@ -1057,7 +1101,7 @@ int hl_fw_init_cpu(struct hl_device *hdev) dev_dbg(hdev->dev, "uboot status = %d\n", status); /* Read U-Boot version now in case we will later fail */ - hdev->asic_funcs->read_device_fw_version(hdev, FW_COMP_UBOOT); + hl_read_device_fw_version(hdev, FW_COMP_BOOT_FIT); /* Clear reset status since we need to read it again from boot CPU */ prop->hard_reset_done_by_fw = false; diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index 108ed2d5e9b9..a4308d438607 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -178,11 +178,11 @@ enum hl_pci_match_mode { /** * enum hl_fw_component - F/W components to read version through registers. - * @FW_COMP_UBOOT: u-boot. + * @FW_COMP_BOOT_FIT: boot fit. * @FW_COMP_PREBOOT: preboot. */ enum hl_fw_component { - FW_COMP_UBOOT, + FW_COMP_BOOT_FIT, FW_COMP_PREBOOT }; @@ -820,24 +820,36 @@ enum div_select_defs { /** * struct fw_load_mgr - manager FW loading process - * @kmd_msg_to_cpu_reg: register address for KMD->CPU messages + * @preboot_version_max_off: max offset to preboot version + * @boot_fit_version_max_off: max offset to boot fit version + * @kmd_msg_to_cpu_reg: register address for KDM->CPU messages * @cpu_cmd_status_to_host_reg: register address for CPU command status response * @cpu_boot_status_reg: boot status register * @cpu_boot_dev_status_reg: boot device status register * @boot_err0_reg: boot error register + * @preboot_version_offset_reg: SRAM offset to preboot version register + * @boot_fit_version_offset_reg: SRAM offset to boot fit version register + * @sram_offset_mask: mask for getting offset into the SRAM * @cpu_timeout: CPU response timeout in usec * @boot_fit_timeout: Boot fit load timeout in usec * @skip_bmc: should BMC be skipped + * @sram_bar_id: SRAM bar ID */ struct fw_load_mgr { + u64 preboot_version_max_off; + u64 boot_fit_version_max_off; u32 kmd_msg_to_cpu_reg; u32 cpu_cmd_status_to_host_reg; u32 cpu_boot_status_reg; u32 cpu_boot_dev_status_reg; u32 boot_err0_reg; + u32 preboot_version_offset_reg; + u32 boot_fit_version_offset_reg; + u32 sram_offset_mask; u32 cpu_timeout; u32 boot_fit_timeout; u8 skip_bmc; + u8 sram_bar_id; }; /** @@ -929,8 +941,6 @@ struct fw_load_mgr { * @ctx_fini: context dependent cleanup. * @get_clk_rate: Retrieve the ASIC current and maximum clock rate in MHz * @get_queue_id_for_cq: Get the H/W queue id related to the given CQ index. - * @read_device_fw_version: read the device's firmware versions that are - * contained in registers * @load_firmware_to_device: load the firmware to the device's memory * @load_boot_fit_to_device: load boot fit to device's memory * @get_signal_cb_size: Get signal CB size. @@ -1059,8 +1069,6 @@ struct hl_asic_funcs { void (*ctx_fini)(struct hl_ctx *ctx); int (*get_clk_rate)(struct hl_device *hdev, u32 *cur_clk, u32 *max_clk); u32 (*get_queue_id_for_cq)(struct hl_device *hdev, u32 cq_idx); - int (*read_device_fw_version)(struct hl_device *hdev, - enum hl_fw_component fwc); int (*load_firmware_to_device)(struct hl_device *hdev); int (*load_boot_fit_to_device)(struct hl_device *hdev); u32 (*get_signal_cb_size)(struct hl_device *hdev); diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 05a74f838a16..12866875388e 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -3691,56 +3691,24 @@ static int gaudi_load_boot_fit_to_device(struct hl_device *hdev) return hl_fw_load_fw_to_device(hdev, GAUDI_BOOT_FIT_FILE, dst, 0, 0); } -static int gaudi_read_device_fw_version(struct hl_device *hdev, - enum hl_fw_component fwc) -{ - const char *name; - u32 ver_off; - char *dest; - - switch (fwc) { - case FW_COMP_UBOOT: - ver_off = RREG32(mmUBOOT_VER_OFFSET); - dest = hdev->asic_prop.uboot_ver; - name = "U-Boot"; - break; - case FW_COMP_PREBOOT: - ver_off = RREG32(mmPREBOOT_VER_OFFSET); - dest = hdev->asic_prop.preboot_ver; - name = "Preboot"; - break; - default: - dev_warn(hdev->dev, "Undefined FW component: %d\n", fwc); - return -EIO; - } - - ver_off &= ~((u32)SRAM_BASE_ADDR); - - if (ver_off < SRAM_SIZE - VERSION_MAX_LEN) { - memcpy_fromio(dest, hdev->pcie_bar[SRAM_BAR_ID] + ver_off, - VERSION_MAX_LEN); - } else { - dev_err(hdev->dev, "%s version offset (0x%x) is above SRAM\n", - name, ver_off); - strcpy(dest, "unavailable"); - return -EIO; - } - - return 0; -} - static void gaudi_init_firmware_loader(struct hl_device *hdev) { struct fw_load_mgr *fw_loader = &hdev->fw_loader; + fw_loader->preboot_version_max_off = SRAM_SIZE - VERSION_MAX_LEN; + fw_loader->boot_fit_version_max_off = SRAM_SIZE - VERSION_MAX_LEN; fw_loader->kmd_msg_to_cpu_reg = mmPSOC_GLOBAL_CONF_KMD_MSG_TO_CPU; fw_loader->cpu_cmd_status_to_host_reg = mmCPU_CMD_STATUS_TO_HOST; + fw_loader->preboot_version_offset_reg = mmPREBOOT_VER_OFFSET; + fw_loader->boot_fit_version_offset_reg = mmUBOOT_VER_OFFSET; + fw_loader->sram_offset_mask = ~((u32)SRAM_BASE_ADDR); fw_loader->cpu_timeout = GAUDI_CPU_TIMEOUT_USEC; fw_loader->boot_fit_timeout = GAUDI_BOOT_FIT_REQ_TIMEOUT_USEC; fw_loader->skip_bmc = !hdev->bmc_enable; fw_loader->cpu_boot_status_reg = mmPSOC_GLOBAL_CONF_CPU_BOOT_STATUS; fw_loader->cpu_boot_dev_status_reg = mmCPU_BOOT_DEV_STS0; fw_loader->boot_err0_reg = mmCPU_BOOT_ERR0; + fw_loader->sram_bar_id = SRAM_BAR_ID; } static int gaudi_init_cpu(struct hl_device *hdev) @@ -8801,7 +8769,6 @@ static const struct hl_asic_funcs gaudi_funcs = { .ctx_fini = gaudi_ctx_fini, .get_clk_rate = gaudi_get_clk_rate, .get_queue_id_for_cq = gaudi_get_queue_id_for_cq, - .read_device_fw_version = gaudi_read_device_fw_version, .load_firmware_to_device = gaudi_load_firmware_to_device, .load_boot_fit_to_device = gaudi_load_boot_fit_to_device, .get_signal_cb_size = gaudi_get_signal_cb_size, diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c index 678fbbc6521b..dd55fec19e8d 100644 --- a/drivers/misc/habanalabs/goya/goya.c +++ b/drivers/misc/habanalabs/goya/goya.c @@ -2402,61 +2402,24 @@ static int goya_load_boot_fit_to_device(struct hl_device *hdev) return hl_fw_load_fw_to_device(hdev, GOYA_BOOT_FIT_FILE, dst, 0, 0); } -/* - * FW component passes an offset from SRAM_BASE_ADDR in SCRATCHPAD_xx. - * The version string should be located by that offset. - */ -static int goya_read_device_fw_version(struct hl_device *hdev, - enum hl_fw_component fwc) -{ - const char *name; - u32 ver_off; - char *dest; - - switch (fwc) { - case FW_COMP_UBOOT: - ver_off = RREG32(mmUBOOT_VER_OFFSET); - dest = hdev->asic_prop.uboot_ver; - name = "U-Boot"; - break; - case FW_COMP_PREBOOT: - ver_off = RREG32(mmPREBOOT_VER_OFFSET); - dest = hdev->asic_prop.preboot_ver; - name = "Preboot"; - break; - default: - dev_warn(hdev->dev, "Undefined FW component: %d\n", fwc); - return -EIO; - } - - ver_off &= ~((u32)SRAM_BASE_ADDR); - - if (ver_off < SRAM_SIZE - VERSION_MAX_LEN) { - memcpy_fromio(dest, hdev->pcie_bar[SRAM_CFG_BAR_ID] + ver_off, - VERSION_MAX_LEN); - } else { - dev_err(hdev->dev, "%s version offset (0x%x) is above SRAM\n", - name, ver_off); - strcpy(dest, "unavailable"); - - return -EIO; - } - - return 0; -} - static void goya_init_firmware_loader(struct hl_device *hdev) { struct fw_load_mgr *fw_loader = &hdev->fw_loader; + fw_loader->preboot_version_max_off = SRAM_SIZE - VERSION_MAX_LEN; + fw_loader->boot_fit_version_max_off = SRAM_SIZE - VERSION_MAX_LEN; fw_loader->kmd_msg_to_cpu_reg = mmPSOC_GLOBAL_CONF_KMD_MSG_TO_CPU; fw_loader->cpu_cmd_status_to_host_reg = mmCPU_CMD_STATUS_TO_HOST; + fw_loader->preboot_version_offset_reg = mmPREBOOT_VER_OFFSET; + fw_loader->boot_fit_version_offset_reg = mmUBOOT_VER_OFFSET; + fw_loader->sram_offset_mask = ~((u32)SRAM_BASE_ADDR); fw_loader->cpu_timeout = GOYA_CPU_TIMEOUT_USEC; fw_loader->boot_fit_timeout = GOYA_BOOT_FIT_REQ_TIMEOUT_USEC; fw_loader->skip_bmc = false; fw_loader->cpu_boot_status_reg = mmPSOC_GLOBAL_CONF_CPU_BOOT_STATUS; fw_loader->cpu_boot_dev_status_reg = mmCPU_BOOT_DEV_STS0; fw_loader->boot_err0_reg = mmCPU_BOOT_ERR0; + fw_loader->sram_bar_id = SRAM_CFG_BAR_ID; } static int goya_init_cpu(struct hl_device *hdev) @@ -5533,7 +5496,6 @@ static const struct hl_asic_funcs goya_funcs = { .ctx_fini = goya_ctx_fini, .get_clk_rate = goya_get_clk_rate, .get_queue_id_for_cq = goya_get_queue_id_for_cq, - .read_device_fw_version = goya_read_device_fw_version, .load_firmware_to_device = goya_load_firmware_to_device, .load_boot_fit_to_device = goya_load_boot_fit_to_device, .get_signal_cb_size = goya_get_signal_cb_size, -- cgit v1.2.3 From 22a795b4af5a7bc66335166054805c1f103c3e4d Mon Sep 17 00:00:00 2001 From: Ohad Sharabi Date: Thu, 8 Apr 2021 13:42:00 +0300 Subject: habanalabs: dynamic fw load reset protocol First stage of the dynamic FW load protocol is to reset the protocol to avoid residues from former load cycles. Signed-off-by: Ohad Sharabi Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 287 +++++++++++++++++++++++++-- drivers/misc/habanalabs/common/habanalabs.h | 41 +++- drivers/misc/habanalabs/gaudi/gaudi.c | 36 +++- drivers/misc/habanalabs/goya/goya.c | 36 +++- 4 files changed, 360 insertions(+), 40 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index d62ec5bbdb41..374a35e1a587 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -895,30 +895,32 @@ static int hl_read_device_fw_version(struct hl_device *hdev, enum hl_fw_component fwc) { struct fw_load_mgr *fw_loader = &hdev->fw_loader; + struct static_fw_load_mgr *static_loader; const char *name; u32 ver_off, limit; char *dest; + static_loader = &hdev->fw_loader.static_loader; + switch (fwc) { case FW_COMP_BOOT_FIT: - ver_off = RREG32(fw_loader->boot_fit_version_offset_reg); + ver_off = RREG32(static_loader->boot_fit_version_offset_reg); dest = hdev->asic_prop.uboot_ver; name = "Boot-fit"; - limit = fw_loader->boot_fit_version_max_off; + limit = static_loader->boot_fit_version_max_off; break; case FW_COMP_PREBOOT: - ver_off = RREG32( - fw_loader->preboot_version_offset_reg); + ver_off = RREG32(static_loader->preboot_version_offset_reg); dest = hdev->asic_prop.preboot_ver; name = "Preboot"; - limit = fw_loader->preboot_version_max_off; + limit = static_loader->preboot_version_max_off; break; default: dev_warn(hdev->dev, "Undefined FW component: %d\n", fwc); return -EIO; } - ver_off &= fw_loader->sram_offset_mask; + ver_off &= static_loader->sram_offset_mask; if (ver_off < limit) { memcpy_fromio(dest, @@ -1022,25 +1024,262 @@ int hl_fw_read_preboot_status(struct hl_device *hdev, u32 cpu_boot_status_reg, return -EINVAL; } -int hl_fw_init_cpu(struct hl_device *hdev) +/* associate string with COMM status */ +static char *hl_dynamic_fw_status_str[COMMS_STS_INVLD_LAST] = { + [COMMS_STS_NOOP] = "NOOP", + [COMMS_STS_ACK] = "ACK", + [COMMS_STS_OK] = "OK", + [COMMS_STS_ERR] = "ERR", + [COMMS_STS_VALID_ERR] = "VALID_ERR", + [COMMS_STS_TIMEOUT_ERR] = "TIMEOUT_ERR", +}; + +/** + * hl_fw_dynamic_report_error_status - report error status + * + * @hdev: pointer to the habanalabs device structure + * @status: value of FW status register + * @expected_status: the expected status + */ +static void hl_fw_dynamic_report_error_status(struct hl_device *hdev, + u32 status, + enum comms_sts expected_status) +{ + enum comms_sts comm_status = + FIELD_GET(COMMS_STATUS_STATUS_MASK, status); + + if (comm_status < COMMS_STS_INVLD_LAST) + dev_err(hdev->dev, "Device status %s, expected status: %s\n", + hl_dynamic_fw_status_str[comm_status], + hl_dynamic_fw_status_str[expected_status]); + else + dev_err(hdev->dev, "Device status unknown %d, expected status: %s\n", + comm_status, + hl_dynamic_fw_status_str[expected_status]); +} + +/** + * hl_fw_dynamic_send_cmd - send LKD to FW cmd + * + * @hdev: pointer to the habanalabs device structure + * @fw_loader: managing structure for loading device's FW + * @lkd_cmd: LKD to FW cmd code + * @size: size of next FW component to be loaded (0 if not necessary) + * + * LDK to FW exact command layout is defined at struct comms_command. + * note: the size argument is used only when the next FW component should be + * loaded, otherwise it shall be 0. the size is used by the FW in later + * protocol stages and when sending only indicating the amount of memory + * to be allocated by the FW to receive the next boot component. + */ +static void hl_fw_dynamic_send_cmd(struct hl_device *hdev, + struct fw_load_mgr *fw_loader, + enum comms_cmd cmd, unsigned int size) +{ + struct comms_command lkd_cmd; + + lkd_cmd.val = FIELD_PREP(COMMS_COMMAND_CMD_MASK, cmd); + lkd_cmd.val |= FIELD_PREP(COMMS_COMMAND_SIZE_MASK, size); + + WREG32(fw_loader->kmd_msg_to_cpu_reg, lkd_cmd.val); +} + +/** + * hl_fw_dynamic_wait_for_status - wait for status in dynamic FW load + * + * @hdev: pointer to the habanalabs device structure + * @fw_loader: managing structure for loading device's FW + * @expected_status: expected status to wait for + * @timeout: timeout for status wait + * + * @return 0 on success, otherwise non-zero error code + * + * waiting for status from FW include polling the FW status register until + * expected status is received or timeout occurs (whatever occurs first). + */ +static int hl_fw_dynamic_wait_for_status(struct hl_device *hdev, + struct fw_load_mgr *fw_loader, + enum comms_sts expected_status, + u32 timeout) +{ + u32 status; + int rc; + + /* Wait for expected status */ + rc = hl_poll_timeout( + hdev, + fw_loader->cpu_cmd_status_to_host_reg, + status, + FIELD_GET(COMMS_STATUS_STATUS_MASK, status) == expected_status, + 10000, + timeout); + + if (rc) { + hl_fw_dynamic_report_error_status(hdev, status, + expected_status); + return -EIO; + } + + return 0; +} + +/** + * hl_fw_dynamic_send_clear_cmd - send clear command to FW + * + * @hdev: pointer to the habanalabs device structure + * @fw_loader: managing structure for loading device's FW + * + * @return 0 on success, otherwise non-zero error code + * + * after command cycle between LKD to FW CPU (i.e. LKD got an expected status + * from FW) we need to clear the CPU status register in order to avoid garbage + * between command cycles. + * This is done by sending clear command and polling the CPU to LKD status + * register to hold the status NOOP + */ +static int hl_fw_dynamic_send_clear_cmd(struct hl_device *hdev, + struct fw_load_mgr *fw_loader) +{ + hl_fw_dynamic_send_cmd(hdev, fw_loader, COMMS_CLR_STS, 0); + + return hl_fw_dynamic_wait_for_status(hdev, fw_loader, COMMS_STS_NOOP, + fw_loader->cpu_timeout); +} + +/** + * hl_fw_dynamic_send_protocol_cmd - send LKD to FW cmd and wait for ACK + * + * @hdev: pointer to the habanalabs device structure + * @fw_loader: managing structure for loading device's FW + * @lkd_cmd: LKD to FW cmd code + * @size: size of next FW component to be loaded (0 if not necessary) + * @wait_ok: if true also wait for OK response from FW + * @timeout: timeout for status wait + * + * @return 0 on success, otherwise non-zero error code + * + * brief: + * when sending protocol command we have the following steps: + * - send clear (clear command and verify clear status register) + * - send the actual protocol command + * - wait for ACK on the protocol command + * - send clear + * - send NOOP + * if, in addition, the specific protocol command should wait for OK then: + * - wait for OK + * - send clear + * - send NOOP + * + * NOTES: + * send clear: this is necessary in order to clear the status register to avoid + * leftovers between command + * NOOP command: necessary to avoid loop on the clear command by the FW + */ +static int hl_fw_dynamic_send_protocol_cmd(struct hl_device *hdev, + struct fw_load_mgr *fw_loader, + enum comms_cmd cmd, unsigned int size, + bool wait_ok, u32 timeout) +{ + int rc; + + /* first send clear command to clean former commands */ + rc = hl_fw_dynamic_send_clear_cmd(hdev, fw_loader); + + /* send the actual command */ + hl_fw_dynamic_send_cmd(hdev, fw_loader, cmd, size); + + /* wait for ACK for the command */ + rc = hl_fw_dynamic_wait_for_status(hdev, fw_loader, COMMS_STS_ACK, + timeout); + if (rc) + return rc; + + /* clear command to prepare for NOOP command */ + rc = hl_fw_dynamic_send_clear_cmd(hdev, fw_loader); + if (rc) + return rc; + + /* send the actual NOOP command */ + hl_fw_dynamic_send_cmd(hdev, fw_loader, COMMS_NOOP, 0); + + if (!wait_ok) + return 0; + + rc = hl_fw_dynamic_wait_for_status(hdev, fw_loader, COMMS_STS_OK, + timeout); + if (rc) + return rc; + + /* clear command to prepare for NOOP command */ + rc = hl_fw_dynamic_send_clear_cmd(hdev, fw_loader); + if (rc) + return rc; + + /* send the actual NOOP command */ + hl_fw_dynamic_send_cmd(hdev, fw_loader, COMMS_NOOP, 0); + + return 0; +} + +/** + * hl_fw_dynamic_init_cpu - initialize the device CPU using dynamic protocol + * + * @hdev: pointer to the habanalabs device structure + * @fw_loader: managing structure for loading device's FW + * + * @return 0 on success, otherwise non-zero error code + * + * brief: the dynamic protocol is master (LKD) slave (FW CPU) protocol. + * the communication is done using registers: + * - LKD command register + * - FW status register + * the protocol is race free. this goal is achieved by splitting the requests + * and response to known synchronization points between the LKD and the FW. + * each response to LKD request is known and bound to a predefined timeout. + * in case of timeout expiration without the desired status from FW- the + * protocol (and hence the boot) will fail. + */ +static int hl_fw_dynamic_init_cpu(struct hl_device *hdev, + struct fw_load_mgr *fw_loader) +{ + int rc; + + rc = hl_fw_dynamic_send_protocol_cmd(hdev, fw_loader, COMMS_RST_STATE, + 0, true, + fw_loader->cpu_timeout); + return rc; +} + +/** + * hl_fw_static_init_cpu - initialize the device CPU using static protocol + * + * @hdev: pointer to the habanalabs device structure + * @fw_loader: managing structure for loading device's FW + * + * @return 0 on success, otherwise non-zero error code + */ +static int hl_fw_static_init_cpu(struct hl_device *hdev, + struct fw_load_mgr *fw_loader) { u32 cpu_msg_status_reg, cpu_timeout, msg_to_cpu_reg, status; u32 cpu_boot_status_reg, cpu_security_boot_status_reg; struct asic_fixed_properties *prop = &hdev->asic_prop; - struct fw_load_mgr *fw_loader; + struct static_fw_load_mgr *static_loader; int rc; if (!(hdev->fw_components & FW_TYPE_BOOT_CPU)) return 0; - /* init loader parameters */ - fw_loader = &hdev->fw_loader; - cpu_security_boot_status_reg = fw_loader->cpu_boot_status_reg; + /* init common loader parameters */ + static_loader = &fw_loader->static_loader; cpu_msg_status_reg = fw_loader->cpu_cmd_status_to_host_reg; - cpu_boot_status_reg = fw_loader->cpu_boot_status_reg; msg_to_cpu_reg = fw_loader->kmd_msg_to_cpu_reg; cpu_timeout = fw_loader->cpu_timeout; + /* init static loader parameters */ + cpu_security_boot_status_reg = static_loader->cpu_boot_status_reg; + cpu_boot_status_reg = static_loader->cpu_boot_status_reg; + dev_info(hdev->dev, "Going to wait for device boot (up to %lds)\n", cpu_timeout / USEC_PER_SEC); @@ -1191,7 +1430,7 @@ int hl_fw_init_cpu(struct hl_device *hdev) goto out; } - rc = fw_read_errors(hdev, fw_loader->boot_err0_reg, + rc = fw_read_errors(hdev, fw_loader->static_loader.boot_err0_reg, cpu_security_boot_status_reg); if (rc) return rc; @@ -1221,8 +1460,28 @@ int hl_fw_init_cpu(struct hl_device *hdev) return 0; out: - fw_read_errors(hdev, fw_loader->boot_err0_reg, + fw_read_errors(hdev, fw_loader->static_loader.boot_err0_reg, cpu_security_boot_status_reg); return rc; } + +/** + * hl_fw_init_cpu - initialize the device CPU + * + * @hdev: pointer to the habanalabs device structure + * + * @return 0 on success, otherwise non-zero error code + * + * perform necessary initializations for device's CPU. takes into account if + * init protocol is static or dynamic. + */ +int hl_fw_init_cpu(struct hl_device *hdev) +{ + struct asic_fixed_properties *prop = &hdev->asic_prop; + struct fw_load_mgr *fw_loader = &hdev->fw_loader; + + return prop->dynamic_fw_load ? + hl_fw_dynamic_init_cpu(hdev, fw_loader) : + hl_fw_static_init_cpu(hdev, fw_loader); +} diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index a4308d438607..b1517ed22ca3 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -819,37 +819,58 @@ enum div_select_defs { }; /** - * struct fw_load_mgr - manager FW loading process + * struct static_fw_load_mgr - static FW load manager * @preboot_version_max_off: max offset to preboot version * @boot_fit_version_max_off: max offset to boot fit version - * @kmd_msg_to_cpu_reg: register address for KDM->CPU messages - * @cpu_cmd_status_to_host_reg: register address for CPU command status response * @cpu_boot_status_reg: boot status register * @cpu_boot_dev_status_reg: boot device status register * @boot_err0_reg: boot error register * @preboot_version_offset_reg: SRAM offset to preboot version register * @boot_fit_version_offset_reg: SRAM offset to boot fit version register * @sram_offset_mask: mask for getting offset into the SRAM - * @cpu_timeout: CPU response timeout in usec - * @boot_fit_timeout: Boot fit load timeout in usec - * @skip_bmc: should BMC be skipped - * @sram_bar_id: SRAM bar ID */ -struct fw_load_mgr { +struct static_fw_load_mgr { u64 preboot_version_max_off; u64 boot_fit_version_max_off; - u32 kmd_msg_to_cpu_reg; - u32 cpu_cmd_status_to_host_reg; u32 cpu_boot_status_reg; u32 cpu_boot_dev_status_reg; u32 boot_err0_reg; u32 preboot_version_offset_reg; u32 boot_fit_version_offset_reg; u32 sram_offset_mask; +}; + +/** + * struct dynamic_fw_load_mgr - dynamic FW load manager + * TODO: currently empty, will be filled once boot stages implementation will + * progress. + */ +struct dynamic_fw_load_mgr { +}; + +/** + * struct fw_load_mgr - manager FW loading process + * @kmd_msg_to_cpu_reg: register address for KDM->CPU messages + * @cpu_cmd_status_to_host_reg: register address for CPU command status response + * @cpu_timeout: CPU response timeout in usec + * @boot_fit_timeout: Boot fit load timeout in usec + * @skip_bmc: should BMC be skipped + * @sram_bar_id: SRAM bar ID + * @static_loader: specific structure for static load + * @dynamic_loader: specific structure for dynamic load + */ +struct fw_load_mgr { + u32 kmd_msg_to_cpu_reg; + u32 cpu_cmd_status_to_host_reg; u32 cpu_timeout; u32 boot_fit_timeout; u8 skip_bmc; u8 sram_bar_id; + + union { + struct static_fw_load_mgr static_loader; + struct dynamic_fw_load_mgr dynamic_loader; + }; }; /** diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 12866875388e..245ced9c3e13 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -3691,24 +3691,44 @@ static int gaudi_load_boot_fit_to_device(struct hl_device *hdev) return hl_fw_load_fw_to_device(hdev, GAUDI_BOOT_FIT_FILE, dst, 0, 0); } +static void gaudi_init_dynamic_firmware_loader(struct hl_device *hdev) +{ + +} + +static void gaudi_init_static_firmware_loader(struct hl_device *hdev) +{ + struct static_fw_load_mgr *static_loader; + + static_loader = &hdev->fw_loader.static_loader; + + static_loader->preboot_version_max_off = SRAM_SIZE - VERSION_MAX_LEN; + static_loader->boot_fit_version_max_off = SRAM_SIZE - VERSION_MAX_LEN; + static_loader->cpu_boot_status_reg = mmPSOC_GLOBAL_CONF_CPU_BOOT_STATUS; + static_loader->cpu_boot_dev_status_reg = mmCPU_BOOT_DEV_STS0; + static_loader->boot_err0_reg = mmCPU_BOOT_ERR0; + static_loader->preboot_version_offset_reg = mmPREBOOT_VER_OFFSET; + static_loader->boot_fit_version_offset_reg = mmUBOOT_VER_OFFSET; + static_loader->sram_offset_mask = ~((u32)SRAM_BASE_ADDR); +} + static void gaudi_init_firmware_loader(struct hl_device *hdev) { + struct asic_fixed_properties *prop = &hdev->asic_prop; struct fw_load_mgr *fw_loader = &hdev->fw_loader; - fw_loader->preboot_version_max_off = SRAM_SIZE - VERSION_MAX_LEN; - fw_loader->boot_fit_version_max_off = SRAM_SIZE - VERSION_MAX_LEN; + /* fill common fields */ fw_loader->kmd_msg_to_cpu_reg = mmPSOC_GLOBAL_CONF_KMD_MSG_TO_CPU; fw_loader->cpu_cmd_status_to_host_reg = mmCPU_CMD_STATUS_TO_HOST; - fw_loader->preboot_version_offset_reg = mmPREBOOT_VER_OFFSET; - fw_loader->boot_fit_version_offset_reg = mmUBOOT_VER_OFFSET; - fw_loader->sram_offset_mask = ~((u32)SRAM_BASE_ADDR); fw_loader->cpu_timeout = GAUDI_CPU_TIMEOUT_USEC; fw_loader->boot_fit_timeout = GAUDI_BOOT_FIT_REQ_TIMEOUT_USEC; fw_loader->skip_bmc = !hdev->bmc_enable; - fw_loader->cpu_boot_status_reg = mmPSOC_GLOBAL_CONF_CPU_BOOT_STATUS; - fw_loader->cpu_boot_dev_status_reg = mmCPU_BOOT_DEV_STS0; - fw_loader->boot_err0_reg = mmCPU_BOOT_ERR0; fw_loader->sram_bar_id = SRAM_BAR_ID; + + if (prop->dynamic_fw_load) + gaudi_init_dynamic_firmware_loader(hdev); + else + gaudi_init_static_firmware_loader(hdev); } static int gaudi_init_cpu(struct hl_device *hdev) diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c index dd55fec19e8d..dc5659340220 100644 --- a/drivers/misc/habanalabs/goya/goya.c +++ b/drivers/misc/habanalabs/goya/goya.c @@ -2402,24 +2402,44 @@ static int goya_load_boot_fit_to_device(struct hl_device *hdev) return hl_fw_load_fw_to_device(hdev, GOYA_BOOT_FIT_FILE, dst, 0, 0); } +static void goya_init_dynamic_firmware_loader(struct hl_device *hdev) +{ + +} + +static void goya_init_static_firmware_loader(struct hl_device *hdev) +{ + struct static_fw_load_mgr *static_loader; + + static_loader = &hdev->fw_loader.static_loader; + + static_loader->preboot_version_max_off = SRAM_SIZE - VERSION_MAX_LEN; + static_loader->boot_fit_version_max_off = SRAM_SIZE - VERSION_MAX_LEN; + static_loader->cpu_boot_status_reg = mmPSOC_GLOBAL_CONF_CPU_BOOT_STATUS; + static_loader->cpu_boot_dev_status_reg = mmCPU_BOOT_DEV_STS0; + static_loader->boot_err0_reg = mmCPU_BOOT_ERR0; + static_loader->preboot_version_offset_reg = mmPREBOOT_VER_OFFSET; + static_loader->boot_fit_version_offset_reg = mmUBOOT_VER_OFFSET; + static_loader->sram_offset_mask = ~((u32)SRAM_BASE_ADDR); +} + static void goya_init_firmware_loader(struct hl_device *hdev) { + struct asic_fixed_properties *prop = &hdev->asic_prop; struct fw_load_mgr *fw_loader = &hdev->fw_loader; - fw_loader->preboot_version_max_off = SRAM_SIZE - VERSION_MAX_LEN; - fw_loader->boot_fit_version_max_off = SRAM_SIZE - VERSION_MAX_LEN; + /* fill common fields */ fw_loader->kmd_msg_to_cpu_reg = mmPSOC_GLOBAL_CONF_KMD_MSG_TO_CPU; fw_loader->cpu_cmd_status_to_host_reg = mmCPU_CMD_STATUS_TO_HOST; - fw_loader->preboot_version_offset_reg = mmPREBOOT_VER_OFFSET; - fw_loader->boot_fit_version_offset_reg = mmUBOOT_VER_OFFSET; - fw_loader->sram_offset_mask = ~((u32)SRAM_BASE_ADDR); fw_loader->cpu_timeout = GOYA_CPU_TIMEOUT_USEC; fw_loader->boot_fit_timeout = GOYA_BOOT_FIT_REQ_TIMEOUT_USEC; fw_loader->skip_bmc = false; - fw_loader->cpu_boot_status_reg = mmPSOC_GLOBAL_CONF_CPU_BOOT_STATUS; - fw_loader->cpu_boot_dev_status_reg = mmCPU_BOOT_DEV_STS0; - fw_loader->boot_err0_reg = mmCPU_BOOT_ERR0; fw_loader->sram_bar_id = SRAM_CFG_BAR_ID; + + if (prop->dynamic_fw_load) + goya_init_dynamic_firmware_loader(hdev); + else + goya_init_static_firmware_loader(hdev); } static int goya_init_cpu(struct hl_device *hdev) -- cgit v1.2.3 From c592c270fe1f24668ba9c9991d762e850333e63d Mon Sep 17 00:00:00 2001 From: Ohad Sharabi Date: Wed, 21 Apr 2021 13:03:21 +0300 Subject: habanalabs: expose ASIC specific PCI info to common code LKD has interfaces in which it receives device address. For instance the debugfs_read/write variants receives device address for CFG/SRAM/DRAM for read/write and need to translate to the mapped PCI BAR address. In addition, the dynamic FW load protocol dictates that the address to which the LKD will copy the image for the next FW component will be received as a device address and can be placed either in SRAM or DRAM. We need to distinguish those regions as the access methods to those regions are different (in DRAM we possibly need to set the BAR base). Looking forward this code will be used to remove duplicated code in the debugfs_read/write that search the memory region for the input device address. Signed-off-by: Ohad Sharabi Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/habanalabs.h | 28 +++++++++++++++++++++ drivers/misc/habanalabs/common/pci/pci.c | 26 +++++++++++++++++++ drivers/misc/habanalabs/gaudi/gaudi.c | 39 +++++++++++++++++++++++++++++ drivers/misc/habanalabs/goya/goya.c | 31 +++++++++++++++++++++++ 4 files changed, 124 insertions(+) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index b1517ed22ca3..4dd7108674b3 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -818,6 +818,30 @@ enum div_select_defs { DIV_SEL_DIVIDED_PLL = 3, }; +enum pci_region { + PCI_REGION_CFG, + PCI_REGION_SRAM, + PCI_REGION_DRAM, + PCI_REGION_SP_SRAM, + PCI_REGION_NUMBER, +}; + +/** + * struct pci_mem_region - describe memory region in a PCI bar + * @region_base: region base address + * @region_size: region size + * @offset_in_bar: region offset into the bar + * @bar_id: bar ID of the region + * @used: if used 1, otherwise 0 + */ +struct pci_mem_region { + u64 region_base; + u64 region_size; + u32 offset_in_bar; + u8 bar_id; + u8 used; +}; + /** * struct static_fw_load_mgr - static FW load manager * @preboot_version_max_off: max offset to preboot version @@ -2014,6 +2038,7 @@ struct hl_mmu_funcs { * @mmu_priv: device-specific MMU data. * @mmu_func: device-related MMU functions. * @fw_loader: FW loader manager. + * @pci_mem_region: array of memory regions in the PCI * @dram_used_mem: current DRAM memory consumption. * @timeout_jiffies: device CS timeout value. * @max_power: the max power of the device, as configured by the sysadmin. This @@ -2141,6 +2166,8 @@ struct hl_device { struct fw_load_mgr fw_loader; + struct pci_mem_region pci_mem_region[PCI_REGION_NUMBER]; + atomic64_t dram_used_mem; u64 timeout_jiffies; u64 max_power; @@ -2474,6 +2501,7 @@ int hl_pci_set_inbound_region(struct hl_device *hdev, u8 region, struct hl_inbound_pci_region *pci_region); int hl_pci_set_outbound_region(struct hl_device *hdev, struct hl_outbound_pci_region *pci_region); +enum pci_region hl_get_pci_memory_region(struct hl_device *hdev, u64 addr); int hl_pci_init(struct hl_device *hdev); void hl_pci_fini(struct hl_device *hdev); diff --git a/drivers/misc/habanalabs/common/pci/pci.c b/drivers/misc/habanalabs/common/pci/pci.c index 5d07ca53d9ce..9ef6c46a3146 100644 --- a/drivers/misc/habanalabs/common/pci/pci.c +++ b/drivers/misc/habanalabs/common/pci/pci.c @@ -359,6 +359,32 @@ int hl_pci_set_outbound_region(struct hl_device *hdev, return rc; } +/** + * hl_get_pci_memory_region() - get PCI region for given address + * @hdev: Pointer to hl_device structure. + * @addr: device address + * + * @return region index on success, otherwise PCI_REGION_NUMBER (invalid + * region index) + */ +enum pci_region hl_get_pci_memory_region(struct hl_device *hdev, u64 addr) +{ + int i; + + for (i = 0 ; i < PCI_REGION_NUMBER ; i++) { + struct pci_mem_region *region = &hdev->pci_mem_region[i]; + + if (!region->used) + continue; + + if ((addr >= region->region_base) && + (addr < region->region_base + region->region_size)) + return i; + } + + return PCI_REGION_NUMBER; +} + /** * hl_pci_init() - PCI initialization code. * @hdev: Pointer to hl_device structure. diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 245ced9c3e13..8b1bd1126f71 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -1590,6 +1590,43 @@ free_internal_qmans_pq_mem: return rc; } +static void gaudi_set_pci_memory_regions(struct hl_device *hdev) +{ + struct pci_mem_region *region; + + /* CFG */ + region = &hdev->pci_mem_region[PCI_REGION_CFG]; + region->region_base = CFG_BASE; + region->region_size = CFG_SIZE; + region->offset_in_bar = CFG_BASE - SPI_FLASH_BASE_ADDR; + region->bar_id = CFG_BAR_ID; + region->used = 1; + + /* SRAM */ + region = &hdev->pci_mem_region[PCI_REGION_SRAM]; + region->region_base = SRAM_BASE_ADDR; + region->region_size = SRAM_SIZE; + region->offset_in_bar = 0; + region->bar_id = SRAM_BAR_ID; + region->used = 1; + + /* DRAM */ + region = &hdev->pci_mem_region[PCI_REGION_DRAM]; + region->region_base = DRAM_PHYS_BASE; + region->region_size = hdev->asic_prop.dram_size; + region->offset_in_bar = 0; + region->bar_id = HBM_BAR_ID; + region->used = 1; + + /* SP SRAM */ + region = &hdev->pci_mem_region[PCI_REGION_SP_SRAM]; + region->region_base = PSOC_SCRATCHPAD_ADDR; + region->region_size = PSOC_SCRATCHPAD_SIZE; + region->offset_in_bar = PSOC_SCRATCHPAD_ADDR - SPI_FLASH_BASE_ADDR; + region->bar_id = CFG_BAR_ID; + region->used = 1; +} + static int gaudi_sw_init(struct hl_device *hdev) { struct gaudi_device *gaudi; @@ -1664,6 +1701,8 @@ static int gaudi_sw_init(struct hl_device *hdev) hdev->supports_coresight = true; hdev->supports_staged_submission = true; + gaudi_set_pci_memory_regions(hdev); + return 0; free_cpu_accessible_dma_pool: diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c index dc5659340220..c3a241227fe0 100644 --- a/drivers/misc/habanalabs/goya/goya.c +++ b/drivers/misc/habanalabs/goya/goya.c @@ -849,6 +849,35 @@ void goya_late_fini(struct hl_device *hdev) hdev->hl_chip_info->info = NULL; } +static void goya_set_pci_memory_regions(struct hl_device *hdev) +{ + struct pci_mem_region *region; + + /* CFG */ + region = &hdev->pci_mem_region[PCI_REGION_CFG]; + region->region_base = CFG_BASE; + region->region_size = CFG_SIZE; + region->offset_in_bar = CFG_BASE - SRAM_BASE_ADDR; + region->bar_id = SRAM_CFG_BAR_ID; + region->used = 1; + + /* SRAM */ + region = &hdev->pci_mem_region[PCI_REGION_SRAM]; + region->region_base = SRAM_BASE_ADDR; + region->region_size = SRAM_SIZE; + region->offset_in_bar = 0; + region->bar_id = SRAM_CFG_BAR_ID; + region->used = 1; + + /* DRAM */ + region = &hdev->pci_mem_region[PCI_REGION_DRAM]; + region->region_base = DRAM_PHYS_BASE; + region->region_size = hdev->asic_prop.dram_size; + region->offset_in_bar = 0; + region->bar_id = DDR_BAR_ID; + region->used = 1; +} + /* * goya_sw_init - Goya software initialization code * @@ -919,6 +948,8 @@ static int goya_sw_init(struct hl_device *hdev) hdev->supports_coresight = true; hdev->supports_soft_reset = true; + goya_set_pci_memory_regions(hdev); + return 0; free_cpu_accessible_dma_pool: -- cgit v1.2.3 From 90bd4798a8bbea05a0383c5f430db9105b40391e Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Fri, 23 Apr 2021 15:57:39 +0300 Subject: habanalabs: update to latest f/w headers Update the common and GAUDI firmware header files to the latest version. The latest version use the correct endianness types so this commit also contains minor changes to the code to use the correct conversions when reading/writing to the firmware structures. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 7 +- drivers/misc/habanalabs/common/habanalabs.h | 2 +- drivers/misc/habanalabs/include/common/cpucp_if.h | 3 + .../misc/habanalabs/include/common/hl_boot_if.h | 80 +++++++++++----------- .../misc/habanalabs/include/gaudi/gaudi_fw_if.h | 39 +++++++++++ 5 files changed, 88 insertions(+), 43 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index 374a35e1a587..6ecc591b82a0 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -140,7 +140,7 @@ int hl_fw_send_cpu_message(struct hl_device *hdev, u32 hw_queue_id, u32 *msg, } /* set fence to a non valid value */ - pkt->fence = UINT_MAX; + pkt->fence = cpu_to_le32(UINT_MAX); rc = hl_hw_queue_send_cb_no_cmpl(hdev, hw_queue_id, len, pkt_dma_addr); if (rc) { @@ -524,7 +524,8 @@ static int hl_fw_send_msi_info_msg(struct hl_device *hdev) pkt->length = cpu_to_le32(CPUCP_NUM_OF_MSI_TYPES); - hdev->asic_funcs->get_msi_info((u32 *)&pkt->data); + memset((void *) &pkt->data, 0xFF, data_size); + hdev->asic_funcs->get_msi_info(pkt->data); pkt->cpucp_pkt.ctl = cpu_to_le32(CPUCP_PACKET_MSI_INFO_SET << CPUCP_PKT_CTL_OPCODE_SHIFT); @@ -1108,7 +1109,7 @@ static int hl_fw_dynamic_wait_for_status(struct hl_device *hdev, /* Wait for expected status */ rc = hl_poll_timeout( hdev, - fw_loader->cpu_cmd_status_to_host_reg, + le32_to_cpu(fw_loader->cpu_cmd_status_to_host_reg), status, FIELD_GET(COMMS_STATUS_STATUS_MASK, status) == expected_status, 10000, diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index 4dd7108674b3..e57ccfdb5286 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -1138,7 +1138,7 @@ struct hl_asic_funcs { int (*hw_block_mmap)(struct hl_device *hdev, struct vm_area_struct *vma, u32 block_id, u32 block_size); void (*enable_events_from_fw)(struct hl_device *hdev); - void (*get_msi_info)(u32 *table); + void (*get_msi_info)(__le32 *table); int (*map_pll_idx_to_fw_idx)(u32 pll_idx); void (*init_firmware_loader)(struct hl_device *hdev); }; diff --git a/drivers/misc/habanalabs/include/common/cpucp_if.h b/drivers/misc/habanalabs/include/common/cpucp_if.h index bf10ca8d2457..4f1123102968 100644 --- a/drivers/misc/habanalabs/include/common/cpucp_if.h +++ b/drivers/misc/habanalabs/include/common/cpucp_if.h @@ -631,6 +631,8 @@ struct cpucp_security_info { * @card_name: card name that will be displayed in HWMON subsystem on the host * @sec_info: security information * @pll_map: Bit map of supported PLLs for current ASIC version. + * @mme_binning_mask: MME binning mask, + * (0 = functional, 1 = binned) */ struct cpucp_info { struct cpucp_sensor sensors[CPUCP_MAX_SENSORS]; @@ -653,6 +655,7 @@ struct cpucp_info { struct cpucp_security_info sec_info; __le32 reserved6; __u8 pll_map[PLL_MAP_LEN]; + __le64 mme_binning_mask; }; struct cpucp_mac_addr { diff --git a/drivers/misc/habanalabs/include/common/hl_boot_if.h b/drivers/misc/habanalabs/include/common/hl_boot_if.h index 84c14688d69a..0fd749c92fc2 100644 --- a/drivers/misc/habanalabs/include/common/hl_boot_if.h +++ b/drivers/misc/habanalabs/include/common/hl_boot_if.h @@ -99,6 +99,7 @@ #define CPU_BOOT_ERR0_PLL_FAIL (1 << 12) #define CPU_BOOT_ERR0_DEVICE_UNUSABLE_FAIL (1 << 13) #define CPU_BOOT_ERR0_ENABLED (1 << 31) +#define CPU_BOOT_ERR1_ENABLED (1 << 31) /* * BOOT DEVICE STATUS bits in BOOT_DEVICE_STS registers @@ -219,6 +220,7 @@ #define CPU_BOOT_DEV_STS0_FW_IATU_CONF_EN (1 << 17) #define CPU_BOOT_DEV_STS0_DYN_PLL_EN (1 << 19) #define CPU_BOOT_DEV_STS0_ENABLED (1 << 31) +#define CPU_BOOT_DEV_STS1_ENABLED (1 << 31) enum cpu_boot_status { CPU_BOOT_STATUS_NA = 0, /* Default value after reset of chip */ @@ -264,33 +266,33 @@ enum cpu_msg_status { /* communication registers mapping - consider ABI when changing */ struct cpu_dyn_regs { - uint32_t cpu_pq_base_addr_low; - uint32_t cpu_pq_base_addr_high; - uint32_t cpu_pq_length; - uint32_t cpu_pq_init_status; - uint32_t cpu_eq_base_addr_low; - uint32_t cpu_eq_base_addr_high; - uint32_t cpu_eq_length; - uint32_t cpu_eq_ci; - uint32_t cpu_cq_base_addr_low; - uint32_t cpu_cq_base_addr_high; - uint32_t cpu_cq_length; - uint32_t cpu_pf_pq_pi; - uint32_t cpu_boot_dev_sts0; - uint32_t cpu_boot_dev_sts1; - uint32_t cpu_boot_err0; - uint32_t cpu_boot_err1; - uint32_t cpu_boot_status; - uint32_t fw_upd_sts; - uint32_t fw_upd_cmd; - uint32_t fw_upd_pending_sts; - uint32_t fuse_ver_offset; - uint32_t preboot_ver_offset; - uint32_t uboot_ver_offset; - uint32_t hw_state; - uint32_t kmd_msg_to_cpu; - uint32_t cpu_cmd_status_to_host; - uint32_t reserved1[32]; /* reserve for future use */ + __le32 cpu_pq_base_addr_low; + __le32 cpu_pq_base_addr_high; + __le32 cpu_pq_length; + __le32 cpu_pq_init_status; + __le32 cpu_eq_base_addr_low; + __le32 cpu_eq_base_addr_high; + __le32 cpu_eq_length; + __le32 cpu_eq_ci; + __le32 cpu_cq_base_addr_low; + __le32 cpu_cq_base_addr_high; + __le32 cpu_cq_length; + __le32 cpu_pf_pq_pi; + __le32 cpu_boot_dev_sts0; + __le32 cpu_boot_dev_sts1; + __le32 cpu_boot_err0; + __le32 cpu_boot_err1; + __le32 cpu_boot_status; + __le32 fw_upd_sts; + __le32 fw_upd_cmd; + __le32 fw_upd_pending_sts; + __le32 fuse_ver_offset; + __le32 preboot_ver_offset; + __le32 uboot_ver_offset; + __le32 hw_state; + __le32 kmd_msg_to_cpu; + __le32 cpu_cmd_status_to_host; + __le32 reserved1[32]; /* reserve for future use */ }; /* HCDM - Habana Communications Descriptor Magic */ @@ -299,11 +301,11 @@ struct cpu_dyn_regs { /* this is the comms descriptor header - meta data */ struct comms_desc_header { - uint32_t magic; /* magic for validation */ - uint32_t crc32; /* CRC32 of the descriptor w/o header */ - uint16_t size; /* size of the descriptor w/o header */ - uint8_t version; /* descriptor version */ - uint8_t reserved[5]; /* pad to 64 bit */ + __le32 magic; /* magic for validation */ + __le32 crc32; /* CRC32 of the descriptor w/o header */ + __le16 size; /* size of the descriptor w/o header */ + __u8 version; /* descriptor version */ + __u8 reserved[5]; /* pad to 64 bit */ }; /* this is the main FW descriptor - consider ABI when changing */ @@ -314,7 +316,7 @@ struct lkd_fw_comms_desc { char cur_fw_ver[VERSION_MAX_LEN]; /* can be used for 1 more version w/o ABI change */ char reserved0[VERSION_MAX_LEN]; - uint64_t img_addr; /* address for next FW component load */ + __le64 img_addr; /* address for next FW component load */ }; /* @@ -386,11 +388,11 @@ enum comms_cmd { struct comms_command { union { /* bit fields are only for FW use */ struct { - unsigned int size :25; /* 32MB max. */ - unsigned int reserved :2; + u32 size :25; /* 32MB max. */ + u32 reserved :2; enum comms_cmd cmd :5; /* 32 commands */ }; - unsigned int val; + __le32 val; }; }; @@ -449,11 +451,11 @@ enum comms_ram_types { struct comms_status { union { /* bit fields are only for FW use */ struct { - unsigned int offset :26; - unsigned int ram_type :2; + u32 offset :26; + enum comms_ram_types ram_type :2; enum comms_sts status :4; /* 16 statuses */ }; - unsigned int val; + __le32 val; }; }; diff --git a/drivers/misc/habanalabs/include/gaudi/gaudi_fw_if.h b/drivers/misc/habanalabs/include/gaudi/gaudi_fw_if.h index a9f51f9f9e92..a4afb984d0ae 100644 --- a/drivers/misc/habanalabs/include/gaudi/gaudi_fw_if.h +++ b/drivers/misc/habanalabs/include/gaudi/gaudi_fw_if.h @@ -27,6 +27,7 @@ enum gaudi_nic_axi_error { TXE, QPC_RESP, NON_AXI_ERR, + TMR, }; /* @@ -42,6 +43,44 @@ struct eq_nic_sei_event { __u8 pad[6]; }; +/* + * struct gaudi_nic_status - describes the status of a NIC port. + * @port: NIC port index. + * @bad_format_cnt: e.g. CRC. + * @responder_out_of_sequence_psn_cnt: e.g NAK. + * @high_ber_reinit_cnt: link reinit due to high BER. + * @correctable_err_cnt: e.g. bit-flip. + * @uncorrectable_err_cnt: e.g. MAC errors. + * @retraining_cnt: re-training counter. + * @up: is port up. + * @pcs_link: has PCS link. + * @phy_ready: is PHY ready. + * @auto_neg: is Autoneg enabled. + */ +struct gaudi_nic_status { + __u32 port; + __u32 bad_format_cnt; + __u32 responder_out_of_sequence_psn_cnt; + __u32 high_ber_reinit; + __u32 correctable_err_cnt; + __u32 uncorrectable_err_cnt; + __u32 retraining_cnt; + __u8 up; + __u8 pcs_link; + __u8 phy_ready; + __u8 auto_neg; +}; + +struct gaudi_flops_2_data { + union { + struct { + __u32 spsram_init_done : 1; + __u32 reserved : 31; + }; + __u32 data; + }; +}; + #define GAUDI_PLL_FREQ_LOW 200000000 /* 200 MHz */ #endif /* GAUDI_FW_IF_H */ -- cgit v1.2.3 From 38fbcc6ec9a3812f355c0360f6e37966ceb24a7c Mon Sep 17 00:00:00 2001 From: Ofir Bitton Date: Tue, 20 Apr 2021 10:15:25 +0300 Subject: habanalabs: give FW a grace time for configuring iATU iATU (internal Address Translation Unit of the PCI controller) configuration is being done by FW right after driver enables the PCI device. Hence, driver must add a minor sleep afterwards in order to make sure FW finishes configuring iATU regions. Signed-off-by: Ofir Bitton Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/pci/pci.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/pci/pci.c b/drivers/misc/habanalabs/common/pci/pci.c index 9ef6c46a3146..8e7982be6191 100644 --- a/drivers/misc/habanalabs/common/pci/pci.c +++ b/drivers/misc/habanalabs/common/pci/pci.c @@ -430,6 +430,10 @@ int hl_pci_init(struct hl_device *hdev) goto unmap_pci_bars; } + /* Driver must sleep in order for FW to finish the iATU configuration */ + if (hdev->asic_prop.iatu_done_by_fw) + usleep_range(2000, 3000); + return 0; unmap_pci_bars: -- cgit v1.2.3 From a5d4f2e92f0d0032a2fce492a483310e4bae1d3f Mon Sep 17 00:00:00 2001 From: Guy Nisan Date: Wed, 7 Apr 2021 18:31:29 +0300 Subject: habanalabs: modify progress status messages Indicate "progress" instead of "error" when reporting progress status. Change "u-boot stopped by user" to "Cannot boot" message as CPU_BOOT_STATUS_UBOOT_NOT_READY may indicate a fatal error that prevent u-boot from loading firmware. Signed-off-by: Guy Nisan Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index 6ecc591b82a0..55f922b7ed09 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -791,43 +791,43 @@ static void detect_cpu_boot_status(struct hl_device *hdev, u32 status) switch (status) { case CPU_BOOT_STATUS_NA: dev_err(hdev->dev, - "Device boot error - BTL did NOT run\n"); + "Device boot progress - BTL did NOT run\n"); break; case CPU_BOOT_STATUS_IN_WFE: dev_err(hdev->dev, - "Device boot error - Stuck inside WFE loop\n"); + "Device boot progress - Stuck inside WFE loop\n"); break; case CPU_BOOT_STATUS_IN_BTL: dev_err(hdev->dev, - "Device boot error - Stuck in BTL\n"); + "Device boot progress - Stuck in BTL\n"); break; case CPU_BOOT_STATUS_IN_PREBOOT: dev_err(hdev->dev, - "Device boot error - Stuck in Preboot\n"); + "Device boot progress - Stuck in Preboot\n"); break; case CPU_BOOT_STATUS_IN_SPL: dev_err(hdev->dev, - "Device boot error - Stuck in SPL\n"); + "Device boot progress - Stuck in SPL\n"); break; case CPU_BOOT_STATUS_IN_UBOOT: dev_err(hdev->dev, - "Device boot error - Stuck in u-boot\n"); + "Device boot progress - Stuck in u-boot\n"); break; case CPU_BOOT_STATUS_DRAM_INIT_FAIL: dev_err(hdev->dev, - "Device boot error - DRAM initialization failed\n"); + "Device boot progress - DRAM initialization failed\n"); break; case CPU_BOOT_STATUS_UBOOT_NOT_READY: dev_err(hdev->dev, - "Device boot error - u-boot stopped by user\n"); + "Device boot progress - Cannot boot\n"); break; case CPU_BOOT_STATUS_TS_INIT_FAIL: dev_err(hdev->dev, - "Device boot error - Thermal Sensor initialization failed\n"); + "Device boot progress - Thermal Sensor initialization failed\n"); break; default: dev_err(hdev->dev, - "Device boot error - Invalid status code %d\n", + "Device boot progress - Invalid status code %d\n", status); break; } -- cgit v1.2.3 From b8e785c559c066e747d3391c126ea19db9d5e736 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Mon, 26 Apr 2021 18:32:25 +0300 Subject: habanalabs: use dev_dbg upon hint address failure Hint address failure that results in a valid mapping with an address that was allocated by the driver is not a real failure. Therefore, the driver shouldn't notify about this in kernel log. The user is responsible to check the returned address. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/memory.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/memory.c b/drivers/misc/habanalabs/common/memory.c index b92878d76f23..43924e1c0315 100644 --- a/drivers/misc/habanalabs/common/memory.c +++ b/drivers/misc/habanalabs/common/memory.c @@ -570,8 +570,10 @@ static u64 get_va_block(struct hl_device *hdev, if ((is_align_pow_2 && (hint_addr & (va_block_align - 1))) || (!is_align_pow_2 && do_div(tmp_hint_addr, va_range->page_size))) { - dev_info(hdev->dev, "Hint address 0x%llx will be ignored\n", - hint_addr); + + dev_dbg(hdev->dev, + "Hint address 0x%llx will be ignored because it is not aligned\n", + hint_addr); hint_addr = 0; } -- cgit v1.2.3 From 8a43c83fec120185db1308a2641a310d15243a79 Mon Sep 17 00:00:00 2001 From: Ohad Sharabi Date: Sun, 11 Apr 2021 10:32:18 +0300 Subject: habanalabs: load boot fit to device Implementing dynamic boot fit image load to the device. Note that some necessary adjustment were added to the static loader as well so that both loaders can co-exist. as this is not the final FW load stage the dynamic FW load is still forced to be non functional. Signed-off-by: Ohad Sharabi Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 577 ++++++++++++++++++++++++--- drivers/misc/habanalabs/common/habanalabs.h | 61 ++- drivers/misc/habanalabs/gaudi/gaudi.c | 23 +- drivers/misc/habanalabs/goya/goya.c | 23 +- 4 files changed, 615 insertions(+), 69 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index 55f922b7ed09..fc386ad8a302 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -9,9 +9,18 @@ #include "../include/common/hl_boot_if.h" #include +#include #include -#define FW_FILE_MAX_SIZE 0x1400000 /* maximum size of 20MB */ +#define FW_FILE_MAX_SIZE 0x1400000 /* maximum size of 20MB */ + +/* + * when copying image to FW we assume that PCI bar should not be re-set + * (refers mainly to DRAM in which we do such it to access arbitrary region's + * memory address) and we limit the BAR offset to 1G which should be more than + * reasonable for image copy purposes. + */ +#define FW_IMAGE_MAX_BAR_OFFSET (1024 * 1024 * 1024) static int hl_request_fw(struct hl_device *hdev, const struct firmware **firmware_p, @@ -53,6 +62,53 @@ out: return rc; } +/** + * hl_release_firmware() - release FW + * + * @fw: fw descriptor + * + * note: this inline function added to serve as a comprehensive mirror for the + * hl_request_fw function. + */ +static inline void hl_release_firmware(const struct firmware *fw) +{ + release_firmware(fw); +} + +/** + * hl_fw_copy_fw_to_device() - copy FW to device + * + * @hdev: pointer to hl_device structure. + * @fw: fw descriptor + * @dst: IO memory mapped address space to copy firmware to + * @src_offset: offset in src FW to copy from + * @size: amount of bytes to copy (0 to copy the whole binary) + * + * actual copy of FW binary data to device, shared by static and dynamic loaders + */ +static int hl_fw_copy_fw_to_device(struct hl_device *hdev, + const struct firmware *fw, void __iomem *dst, + u32 src_offset, u32 size) +{ + const void *fw_data; + + /* size 0 indicates to copy the whole file */ + if (!size) + size = fw->size; + + if (src_offset + size > fw->size) { + dev_err(hdev->dev, + "size to copy(%u) and offset(%u) are invalid\n", + size, src_offset); + return -EINVAL; + } + + fw_data = (const void *) fw->data; + + memcpy_toio(dst, fw_data + src_offset, size); + return 0; +} + /** * hl_fw_load_fw_to_device() - Load F/W code to device's memory. * @@ -70,33 +126,15 @@ int hl_fw_load_fw_to_device(struct hl_device *hdev, const char *fw_name, void __iomem *dst, u32 src_offset, u32 size) { const struct firmware *fw; - const void *fw_data; - size_t fw_size; int rc; rc = hl_request_fw(hdev, &fw, fw_name); if (rc) return rc; - fw_size = fw->size; - - if (size - src_offset > fw_size) { - dev_err(hdev->dev, - "size to copy(%u) and offset(%u) are invalid\n", - size, src_offset); - rc = -EINVAL; - goto out; - } - - if (size) - fw_size = size; - - fw_data = (const void *) fw->data; + rc = hl_fw_copy_fw_to_device(hdev, fw, dst, src_offset, size); - memcpy_toio(dst, fw_data + src_offset, fw_size); - -out: - release_firmware(fw); + hl_release_firmware(fw); return rc; } @@ -887,12 +925,15 @@ static int hl_fw_read_preboot_caps(struct hl_device *hdev, */ prop->dynamic_fw_load = 0; + /* initialize FW loader once we know what load protocol is used */ + hdev->asic_funcs->init_firmware_loader(hdev); + dev_dbg(hdev->dev, "Attempting %s FW load\n", prop->dynamic_fw_load ? "dynamic" : "legacy"); return 0; } -static int hl_read_device_fw_version(struct hl_device *hdev, +static int hl_fw_static_read_device_fw_version(struct hl_device *hdev, enum hl_fw_component fwc) { struct fw_load_mgr *fw_loader = &hdev->fw_loader; @@ -937,19 +978,21 @@ static int hl_read_device_fw_version(struct hl_device *hdev, return 0; } -static int hl_fw_read_preboot_status_legacy(struct hl_device *hdev, - u32 cpu_boot_status_reg, u32 cpu_security_boot_status_reg, - u32 boot_err0_reg, u32 timeout) +/** + * hl_fw_preboot_update_state - update internal data structures during + * handshake with preboot + * + * + * @hdev: pointer to the habanalabs device structure + * + * @return 0 on success, otherwise non-zero error code + */ +static void hl_fw_preboot_update_state(struct hl_device *hdev) { struct asic_fixed_properties *prop = &hdev->asic_prop; - u32 security_status; - int rc; - - rc = hl_read_device_fw_version(hdev, FW_COMP_PREBOOT); - if (rc) - return rc; + u32 preboot_caps; - security_status = prop->fw_preboot_caps_map; + preboot_caps = prop->fw_preboot_caps_map; /* We read security status multiple times during boot: * 1. preboot - a. Check whether the security status bits are valid @@ -964,29 +1007,42 @@ static int hl_fw_read_preboot_status_legacy(struct hl_device *hdev, * Check security status bit (CPU_BOOT_DEV_STS0_ENABLED), if it is set * check security enabled bit (CPU_BOOT_DEV_STS0_SECURITY_EN) */ - if (security_status & CPU_BOOT_DEV_STS0_ENABLED) { + if (preboot_caps & CPU_BOOT_DEV_STS0_ENABLED) { prop->fw_security_status_valid = 1; /* FW security should be derived from PCI ID, we keep this * check for backward compatibility */ - if (security_status & CPU_BOOT_DEV_STS0_SECURITY_EN) + if (preboot_caps & CPU_BOOT_DEV_STS0_SECURITY_EN) prop->fw_security_disabled = false; - if (security_status & CPU_BOOT_DEV_STS0_FW_HARD_RST_EN) + if (preboot_caps & CPU_BOOT_DEV_STS0_FW_HARD_RST_EN) prop->hard_reset_done_by_fw = true; } else { prop->fw_security_status_valid = 0; } dev_dbg(hdev->dev, "Firmware preboot security status %#x\n", - security_status); + preboot_caps); dev_dbg(hdev->dev, "Firmware preboot hard-reset is %s\n", prop->hard_reset_done_by_fw ? "enabled" : "disabled"); dev_info(hdev->dev, "firmware-level security is %s\n", prop->fw_security_disabled ? "disabled" : "enabled"); +} + +static int hl_fw_static_read_preboot_status(struct hl_device *hdev, + u32 cpu_boot_status_reg, u32 cpu_security_boot_status_reg, + u32 boot_err0_reg, u32 timeout) +{ + int rc; + + rc = hl_fw_static_read_device_fw_version(hdev, FW_COMP_PREBOOT); + if (rc) + return rc; + + hl_fw_preboot_update_state(hdev); return 0; } @@ -997,8 +1053,6 @@ int hl_fw_read_preboot_status(struct hl_device *hdev, u32 cpu_boot_status_reg, { int rc; - hdev->asic_funcs->init_firmware_loader(hdev); - /* pldm was added for cases in which we use preboot on pldm and want * to load boot fit, but we can't wait for preboot because it runs * very slowly @@ -1017,7 +1071,7 @@ int hl_fw_read_preboot_status(struct hl_device *hdev, u32 cpu_boot_status_reg, return rc; if (!hdev->asic_prop.dynamic_fw_load) - return hl_fw_read_preboot_status_legacy(hdev, cpu_boot_status_reg, + return hl_fw_static_read_preboot_status(hdev, cpu_boot_status_reg, cpu_boot_caps_reg, boot_err0_reg, timeout); @@ -1064,7 +1118,7 @@ static void hl_fw_dynamic_report_error_status(struct hl_device *hdev, * * @hdev: pointer to the habanalabs device structure * @fw_loader: managing structure for loading device's FW - * @lkd_cmd: LKD to FW cmd code + * @cmd: LKD to FW cmd code * @size: size of next FW component to be loaded (0 if not necessary) * * LDK to FW exact command layout is defined at struct comms_command. @@ -1077,12 +1131,45 @@ static void hl_fw_dynamic_send_cmd(struct hl_device *hdev, struct fw_load_mgr *fw_loader, enum comms_cmd cmd, unsigned int size) { - struct comms_command lkd_cmd; + struct cpu_dyn_regs *dyn_regs; + u32 val; - lkd_cmd.val = FIELD_PREP(COMMS_COMMAND_CMD_MASK, cmd); - lkd_cmd.val |= FIELD_PREP(COMMS_COMMAND_SIZE_MASK, size); + dyn_regs = &fw_loader->dynamic_loader.comm_desc.cpu_dyn_regs; - WREG32(fw_loader->kmd_msg_to_cpu_reg, lkd_cmd.val); + val = FIELD_PREP(COMMS_COMMAND_CMD_MASK, cmd); + val |= FIELD_PREP(COMMS_COMMAND_SIZE_MASK, size); + + WREG32(le32_to_cpu(dyn_regs->kmd_msg_to_cpu), val); +} + +/** + * hl_fw_dynamic_extract_fw_response - update the FW response + * + * @hdev: pointer to the habanalabs device structure + * @fw_loader: managing structure for loading device's FW + * @response: FW response + * @status: the status read from CPU status register + * + * @return 0 on success, otherwise non-zero error code + */ +static int hl_fw_dynamic_extract_fw_response(struct hl_device *hdev, + struct fw_load_mgr *fw_loader, + struct fw_response *response, + u32 status) +{ + response->status = FIELD_GET(COMMS_STATUS_STATUS_MASK, status); + response->ram_offset = FIELD_GET(COMMS_STATUS_OFFSET_MASK, status) << + COMMS_STATUS_OFFSET_ALIGN_SHIFT; + response->ram_type = FIELD_GET(COMMS_STATUS_RAM_TYPE_MASK, status); + + if ((response->ram_type != COMMS_SRAM) && + (response->ram_type != COMMS_DRAM)) { + dev_err(hdev->dev, "FW status: invalid RAM type %u\n", + response->ram_type); + return -EIO; + } + + return 0; } /** @@ -1103,13 +1190,16 @@ static int hl_fw_dynamic_wait_for_status(struct hl_device *hdev, enum comms_sts expected_status, u32 timeout) { + struct cpu_dyn_regs *dyn_regs; u32 status; int rc; + dyn_regs = &fw_loader->dynamic_loader.comm_desc.cpu_dyn_regs; + /* Wait for expected status */ rc = hl_poll_timeout( hdev, - le32_to_cpu(fw_loader->cpu_cmd_status_to_host_reg), + le32_to_cpu(dyn_regs->cpu_cmd_status_to_host), status, FIELD_GET(COMMS_STATUS_STATUS_MASK, status) == expected_status, 10000, @@ -1121,7 +1211,17 @@ static int hl_fw_dynamic_wait_for_status(struct hl_device *hdev, return -EIO; } - return 0; + /* + * skip storing FW response for NOOP to preserve the actual desired + * FW status + */ + if (expected_status == COMMS_STS_NOOP) + return 0; + + rc = hl_fw_dynamic_extract_fw_response(hdev, fw_loader, + &fw_loader->dynamic_loader.response, + status); + return rc; } /** @@ -1152,7 +1252,7 @@ static int hl_fw_dynamic_send_clear_cmd(struct hl_device *hdev, * * @hdev: pointer to the habanalabs device structure * @fw_loader: managing structure for loading device's FW - * @lkd_cmd: LKD to FW cmd code + * @cmd: LKD to FW cmd code * @size: size of next FW component to be loaded (0 if not necessary) * @wait_ok: if true also wait for OK response from FW * @timeout: timeout for status wait @@ -1222,6 +1322,353 @@ static int hl_fw_dynamic_send_protocol_cmd(struct hl_device *hdev, return 0; } +/** + * hl_fw_compat_crc32 - CRC compatible with FW + * + * @data: pointer to the data + * @size: size of the data + * + * @return the CRC32 result + * + * NOTE: kernel's CRC32 differ's from standard CRC32 calculation. + * in order to be aligned we need to flip the bits of both the input + * initial CRC and kernel's CRC32 result. + * in addition both sides use initial CRC of 0, + */ +static u32 hl_fw_compat_crc32(u8 *data, size_t size) +{ + return ~crc32_le(~((u32)0), data, size); +} + +/** + * hl_fw_dynamic_validate_memory_bound - validate memory bounds for memory + * transfer (image or descriptor) between + * host and FW + * + * @hdev: pointer to the habanalabs device structure + * @addr: device address of memory transfer + * @size: memory transter size + * @region: PCI memory region + * + * @return 0 on success, otherwise non-zero error code + */ +static int hl_fw_dynamic_validate_memory_bound(struct hl_device *hdev, + u64 addr, size_t size, + struct pci_mem_region *region) +{ + u64 end_addr; + + /* now make sure that the memory transfer is within region's bounds */ + end_addr = addr + size; + if (end_addr >= region->region_base + region->region_size) { + dev_err(hdev->dev, + "dynamic FW load: memory transfer end address out of memory region bounds. addr: %llx\n", + end_addr); + return -EIO; + } + + /* + * now make sure memory transfer is within predefined BAR bounds. + * this is to make sure we do not need to set the bar (e.g. for DRAM + * memory transfers) + */ + if (end_addr >= region->region_base - region->offset_in_bar + + FW_IMAGE_MAX_BAR_OFFSET) { + dev_err(hdev->dev, + "FW image beyond PCI BAR bounds\n"); + return -EIO; + } + + return 0; +} + +/** + * hl_fw_dynamic_validate_descriptor - validate FW descriptor + * + * @hdev: pointer to the habanalabs device structure + * @fw_loader: managing structure for loading device's FW + * @fw_desc: the descriptor form FW + * + * @return 0 on success, otherwise non-zero error code + */ +static int hl_fw_dynamic_validate_descriptor(struct hl_device *hdev, + struct fw_load_mgr *fw_loader, + struct lkd_fw_comms_desc *fw_desc) +{ + struct pci_mem_region *region; + enum pci_region region_id; + size_t data_size; + u32 data_crc32; + u8 *data_ptr; + u64 addr; + int rc; + + if (le32_to_cpu(fw_desc->header.magic) != HL_COMMS_DESC_MAGIC) { + dev_err(hdev->dev, "Invalid magic for dynamic FW descriptor (%x)\n", + fw_desc->header.magic); + return -EIO; + } + + if (fw_desc->header.version != HL_COMMS_DESC_VER) { + dev_err(hdev->dev, "Invalid version for dynamic FW descriptor (%x)\n", + fw_desc->header.version); + return -EIO; + } + + /* + * calc CRC32 of data without header. + * note that no alignment/stride address issues here as all structures + * are 64 bit padded + */ + data_size = sizeof(struct lkd_fw_comms_desc) - + sizeof(struct comms_desc_header); + data_ptr = (u8 *)fw_desc + sizeof(struct comms_desc_header); + + if (le16_to_cpu(fw_desc->header.size) != data_size) { + dev_err(hdev->dev, + "Invalid descriptor size 0x%x, expected size 0x%zx\n", + le16_to_cpu(fw_desc->header.size), data_size); + return -EIO; + } + + data_crc32 = hl_fw_compat_crc32(data_ptr, data_size); + + if (data_crc32 != le32_to_cpu(fw_desc->header.crc32)) { + dev_err(hdev->dev, + "CRC32 mismatch for dynamic FW descriptor (%x:%x)\n", + data_crc32, fw_desc->header.crc32); + return -EIO; + } + + /* find memory region to which to copy the image */ + addr = le64_to_cpu(fw_desc->img_addr); + region_id = hl_get_pci_memory_region(hdev, addr); + if ((region_id != PCI_REGION_SRAM) && + ((region_id != PCI_REGION_DRAM))) { + dev_err(hdev->dev, + "Invalid region to copy FW image address=%llx\n", addr); + return -EIO; + } + + region = &hdev->pci_mem_region[region_id]; + + /* store the region for the copy stage */ + fw_loader->dynamic_loader.image_region = region; + + /* + * here we know that the start address is valid, now make sure that the + * image is within region's bounds + */ + rc = hl_fw_dynamic_validate_memory_bound(hdev, addr, + fw_loader->dynamic_loader.fw_image_size, + region); + if (rc) { + dev_err(hdev->dev, + "invalid mem transfer request for FW image\n"); + return rc; + } + + return 0; +} + +static int hl_fw_dynamic_validate_response(struct hl_device *hdev, + struct fw_response *response, + struct pci_mem_region *region) +{ + u64 device_addr; + int rc; + + device_addr = region->region_base + response->ram_offset; + + /* + * validate that the descriptor is within region's bounds + * Note that as the start address was supplied according to the RAM + * type- testing only the end address is enough + */ + rc = hl_fw_dynamic_validate_memory_bound(hdev, device_addr, + sizeof(struct lkd_fw_comms_desc), + region); + return rc; +} + +/** + * hl_fw_dynamic_read_and_validate_descriptor - read and validate FW descriptor + * + * @hdev: pointer to the habanalabs device structure + * @fw_loader: managing structure for loading device's FW + * + * @return 0 on success, otherwise non-zero error code + */ +static int hl_fw_dynamic_read_and_validate_descriptor(struct hl_device *hdev, + struct fw_load_mgr *fw_loader) +{ + struct lkd_fw_comms_desc *fw_desc; + struct pci_mem_region *region; + struct fw_response *response; + enum pci_region region_id; + void __iomem *src; + int rc; + + fw_desc = &fw_loader->dynamic_loader.comm_desc; + response = &fw_loader->dynamic_loader.response; + + region_id = (response->ram_type == COMMS_SRAM) ? + PCI_REGION_SRAM : PCI_REGION_DRAM; + + region = &hdev->pci_mem_region[region_id]; + + rc = hl_fw_dynamic_validate_response(hdev, response, region); + if (rc) { + dev_err(hdev->dev, + "invalid mem transfer request for FW descriptor\n"); + return rc; + } + + /* extract address copy the descriptor from */ + src = hdev->pcie_bar[region->bar_id] + region->offset_in_bar + + response->ram_offset; + memcpy_fromio(fw_desc, src, sizeof(struct lkd_fw_comms_desc)); + + return hl_fw_dynamic_validate_descriptor(hdev, fw_loader, fw_desc); +} + +/** + * hl_fw_dynamic_request_descriptor - handshake with CPU to get FW descriptor + * + * @hdev: pointer to the habanalabs device structure + * @fw_loader: managing structure for loading device's FW + * @next_image_size: size to allocate for next FW component + * + * @return 0 on success, otherwise non-zero error code + */ +static int hl_fw_dynamic_request_descriptor(struct hl_device *hdev, + struct fw_load_mgr *fw_loader, + size_t next_image_size) +{ + int rc; + + rc = hl_fw_dynamic_send_protocol_cmd(hdev, fw_loader, COMMS_PREP_DESC, + next_image_size, true, + fw_loader->cpu_timeout); + if (rc) + return rc; + + return hl_fw_dynamic_read_and_validate_descriptor(hdev, fw_loader); +} + +/** + * hl_fw_dynamic_read_device_fw_version - read FW version to exposed properties + * + * @hdev: pointer to the habanalabs device structure + * @fwc: the firmware component + * @fw_version: fw component's version string + */ +static void hl_fw_dynamic_read_device_fw_version(struct hl_device *hdev, + enum hl_fw_component fwc, + const char *fw_version) +{ + char *dest; + + switch (fwc) { + case FW_COMP_BOOT_FIT: + dest = hdev->asic_prop.uboot_ver; + break; + case FW_COMP_PREBOOT: + dest = hdev->asic_prop.preboot_ver; + break; + default: + dev_warn(hdev->dev, "Undefined FW component: %d\n", fwc); + } + + strscpy(dest, fw_version, VERSION_MAX_LEN); +} + +/** + * hl_fw_dynamic_copy_image - copy image to memory allocated by the FW + * + * @hdev: pointer to the habanalabs device structure + * @fw: fw descriptor + * @fw_loader: managing structure for loading device's FW + */ +static int hl_fw_dynamic_copy_image(struct hl_device *hdev, + const struct firmware *fw, + struct fw_load_mgr *fw_loader) +{ + struct lkd_fw_comms_desc *fw_desc; + struct pci_mem_region *region; + void __iomem *dest; + u64 addr; + int rc; + + fw_desc = &fw_loader->dynamic_loader.comm_desc; + addr = le64_to_cpu(fw_desc->img_addr); + + /* find memory region to which to copy the image */ + region = fw_loader->dynamic_loader.image_region; + + dest = hdev->pcie_bar[region->bar_id] + region->offset_in_bar + + (addr - region->region_base); + + rc = hl_fw_copy_fw_to_device(hdev, fw, dest, + fw_loader->boot_fit_img.src_off, + fw_loader->boot_fit_img.copy_size); + + return rc; +} + +/** + * hl_fw_dynamic_load_boot_fit - load boot fit using dynamic protocol + * + * @hdev: pointer to the habanalabs device structure + * @fw_loader: managing structure for loading device's FW + * + * @return 0 on success, otherwise non-zero error code + */ +static int hl_fw_dynamic_load_boot_fit(struct hl_device *hdev, + struct fw_load_mgr *fw_loader) +{ + const struct firmware *fw; + int rc = 0; + + /* request FW in order to communicate to FW the size to be allocated */ + rc = hl_request_fw(hdev, &fw, fw_loader->boot_fit_img.image_name); + if (rc) + return rc; + + /* store the image size for future validation */ + fw_loader->dynamic_loader.fw_image_size = fw->size; + + rc = hl_fw_dynamic_request_descriptor(hdev, fw_loader, fw->size); + if (rc) + goto release_fw; + + /* read preboot version */ + hl_fw_dynamic_read_device_fw_version(hdev, FW_COMP_PREBOOT, + fw_loader->dynamic_loader.comm_desc.cur_fw_ver); + + /* update state during preboot handshake */ + hl_fw_preboot_update_state(hdev); + + /* copy boot fit to space allocated by FW */ + rc = hl_fw_dynamic_copy_image(hdev, fw, fw_loader); + if (rc) + goto release_fw; + + rc = hl_fw_dynamic_send_protocol_cmd(hdev, fw_loader, COMMS_DATA_RDY, + 0, true, + fw_loader->cpu_timeout); + if (rc) + goto release_fw; + + rc = hl_fw_dynamic_send_protocol_cmd(hdev, fw_loader, COMMS_EXEC, + 0, false, + fw_loader->boot_fit_timeout); + +release_fw: + hl_release_firmware(fw); + return rc; +} + /** * hl_fw_dynamic_init_cpu - initialize the device CPU using dynamic protocol * @@ -1243,11 +1690,37 @@ static int hl_fw_dynamic_send_protocol_cmd(struct hl_device *hdev, static int hl_fw_dynamic_init_cpu(struct hl_device *hdev, struct fw_load_mgr *fw_loader) { + struct cpu_dyn_regs *dyn_regs; int rc; rc = hl_fw_dynamic_send_protocol_cmd(hdev, fw_loader, COMMS_RST_STATE, 0, true, fw_loader->cpu_timeout); + if (rc) + goto protocol_err; + + if (!(hdev->fw_components & FW_TYPE_BOOT_CPU)) { + rc = hl_fw_dynamic_request_descriptor(hdev, fw_loader, 0); + if (rc) + goto protocol_err; + + /* read preboot version */ + hl_fw_dynamic_read_device_fw_version(hdev, FW_COMP_PREBOOT, + fw_loader->dynamic_loader.comm_desc.cur_fw_ver); + return 0; + } + + /* load boot fit to FW */ + rc = hl_fw_dynamic_load_boot_fit(hdev, fw_loader); + if (rc) + goto protocol_err; + + return 0; + +protocol_err: + dyn_regs = &fw_loader->dynamic_loader.comm_desc.cpu_dyn_regs; + fw_read_errors(hdev, le32_to_cpu(dyn_regs->cpu_boot_err0), + le32_to_cpu(dyn_regs->cpu_boot_status)); return rc; } @@ -1272,13 +1745,13 @@ static int hl_fw_static_init_cpu(struct hl_device *hdev, return 0; /* init common loader parameters */ - static_loader = &fw_loader->static_loader; - cpu_msg_status_reg = fw_loader->cpu_cmd_status_to_host_reg; - msg_to_cpu_reg = fw_loader->kmd_msg_to_cpu_reg; cpu_timeout = fw_loader->cpu_timeout; /* init static loader parameters */ - cpu_security_boot_status_reg = static_loader->cpu_boot_status_reg; + static_loader = &fw_loader->static_loader; + cpu_msg_status_reg = static_loader->cpu_cmd_status_to_host_reg; + msg_to_cpu_reg = static_loader->kmd_msg_to_cpu_reg; + cpu_security_boot_status_reg = static_loader->cpu_boot_dev_status_reg; cpu_boot_status_reg = static_loader->cpu_boot_status_reg; dev_info(hdev->dev, "Going to wait for device boot (up to %lds)\n", @@ -1341,7 +1814,7 @@ static int hl_fw_static_init_cpu(struct hl_device *hdev, dev_dbg(hdev->dev, "uboot status = %d\n", status); /* Read U-Boot version now in case we will later fail */ - hl_read_device_fw_version(hdev, FW_COMP_BOOT_FIT); + hl_fw_static_read_device_fw_version(hdev, FW_COMP_BOOT_FIT); /* Clear reset status since we need to read it again from boot CPU */ prop->hard_reset_done_by_fw = false; diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index e57ccfdb5286..e0fb9f443ab6 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -846,6 +846,8 @@ struct pci_mem_region { * struct static_fw_load_mgr - static FW load manager * @preboot_version_max_off: max offset to preboot version * @boot_fit_version_max_off: max offset to boot fit version + * @kmd_msg_to_cpu_reg: register address for KDM->CPU messages + * @cpu_cmd_status_to_host_reg: register address for CPU command status response * @cpu_boot_status_reg: boot status register * @cpu_boot_dev_status_reg: boot device status register * @boot_err0_reg: boot error register @@ -856,6 +858,8 @@ struct pci_mem_region { struct static_fw_load_mgr { u64 preboot_version_max_off; u64 boot_fit_version_max_off; + u32 kmd_msg_to_cpu_reg; + u32 cpu_cmd_status_to_host_reg; u32 cpu_boot_status_reg; u32 cpu_boot_dev_status_reg; u32 boot_err0_reg; @@ -864,37 +868,68 @@ struct static_fw_load_mgr { u32 sram_offset_mask; }; +/** + * struct fw_response - FW response to LKD command + * @ram_offset: descriptor offset into the RAM + * @ram_type: RAM type containing the descriptor (SRAM/DRAM) + * @status: command status + */ +struct fw_response { + u32 ram_offset; + u8 ram_type; + u8 status; +}; + /** * struct dynamic_fw_load_mgr - dynamic FW load manager - * TODO: currently empty, will be filled once boot stages implementation will - * progress. + * @response: FW to LKD response + * @comm_desc: the communication descriptor with FW + * @image_region: region to copy the FW image to + * @fw_image_size: FW image size */ struct dynamic_fw_load_mgr { + struct fw_response response; + struct lkd_fw_comms_desc comm_desc; + struct pci_mem_region *image_region; + size_t fw_image_size; +}; + +/** + * struct fw_image_props - properties of FW image + * @image_name: name of the image + * @src_off: offset in src FW to copy from + * @copy_size: amount of bytes to copy (0 to copy the whole binary) + */ +struct fw_image_props { + char *image_name; + u32 src_off; + u32 copy_size; }; /** * struct fw_load_mgr - manager FW loading process - * @kmd_msg_to_cpu_reg: register address for KDM->CPU messages - * @cpu_cmd_status_to_host_reg: register address for CPU command status response + * @dynamic_loader: specific structure for dynamic load + * @static_loader: specific structure for static load + * @boot_fit_img: boot fit image properties + * @linux_img: linux image properties * @cpu_timeout: CPU response timeout in usec * @boot_fit_timeout: Boot fit load timeout in usec * @skip_bmc: should BMC be skipped * @sram_bar_id: SRAM bar ID - * @static_loader: specific structure for static load - * @dynamic_loader: specific structure for dynamic load + * @dram_bar_id: DRAM bar ID */ struct fw_load_mgr { - u32 kmd_msg_to_cpu_reg; - u32 cpu_cmd_status_to_host_reg; + union { + struct dynamic_fw_load_mgr dynamic_loader; + struct static_fw_load_mgr static_loader; + }; + struct fw_image_props boot_fit_img; + struct fw_image_props linux_img; u32 cpu_timeout; u32 boot_fit_timeout; u8 skip_bmc; u8 sram_bar_id; - - union { - struct static_fw_load_mgr static_loader; - struct dynamic_fw_load_mgr dynamic_loader; - }; + u8 dram_bar_id; }; /** diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 8b1bd1126f71..d8afcb064d88 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -3732,7 +3732,23 @@ static int gaudi_load_boot_fit_to_device(struct hl_device *hdev) static void gaudi_init_dynamic_firmware_loader(struct hl_device *hdev) { + struct dynamic_fw_load_mgr *dynamic_loader; + struct cpu_dyn_regs *dyn_regs; + dynamic_loader = &hdev->fw_loader.dynamic_loader; + + /* + * here we update initial values for few specific dynamic regs (as + * before reading the first descriptor from FW those value has to be + * hard-coded) in later stages of the protocol those values will be + * updated automatically by reading the FW descriptor so data there + * will always be up-to-date + */ + dyn_regs = &dynamic_loader->comm_desc.cpu_dyn_regs; + dyn_regs->kmd_msg_to_cpu = + cpu_to_le32(mmPSOC_GLOBAL_CONF_KMD_MSG_TO_CPU); + dyn_regs->cpu_cmd_status_to_host = + cpu_to_le32(mmCPU_CMD_STATUS_TO_HOST); } static void gaudi_init_static_firmware_loader(struct hl_device *hdev) @@ -3743,6 +3759,8 @@ static void gaudi_init_static_firmware_loader(struct hl_device *hdev) static_loader->preboot_version_max_off = SRAM_SIZE - VERSION_MAX_LEN; static_loader->boot_fit_version_max_off = SRAM_SIZE - VERSION_MAX_LEN; + static_loader->kmd_msg_to_cpu_reg = mmPSOC_GLOBAL_CONF_KMD_MSG_TO_CPU; + static_loader->cpu_cmd_status_to_host_reg = mmCPU_CMD_STATUS_TO_HOST; static_loader->cpu_boot_status_reg = mmPSOC_GLOBAL_CONF_CPU_BOOT_STATUS; static_loader->cpu_boot_dev_status_reg = mmCPU_BOOT_DEV_STS0; static_loader->boot_err0_reg = mmCPU_BOOT_ERR0; @@ -3757,12 +3775,13 @@ static void gaudi_init_firmware_loader(struct hl_device *hdev) struct fw_load_mgr *fw_loader = &hdev->fw_loader; /* fill common fields */ - fw_loader->kmd_msg_to_cpu_reg = mmPSOC_GLOBAL_CONF_KMD_MSG_TO_CPU; - fw_loader->cpu_cmd_status_to_host_reg = mmCPU_CMD_STATUS_TO_HOST; + fw_loader->boot_fit_img.image_name = GAUDI_BOOT_FIT_FILE; + fw_loader->linux_img.image_name = GAUDI_LINUX_FW_FILE; fw_loader->cpu_timeout = GAUDI_CPU_TIMEOUT_USEC; fw_loader->boot_fit_timeout = GAUDI_BOOT_FIT_REQ_TIMEOUT_USEC; fw_loader->skip_bmc = !hdev->bmc_enable; fw_loader->sram_bar_id = SRAM_BAR_ID; + fw_loader->dram_bar_id = HBM_BAR_ID; if (prop->dynamic_fw_load) gaudi_init_dynamic_firmware_loader(hdev); diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c index c3a241227fe0..469587a63804 100644 --- a/drivers/misc/habanalabs/goya/goya.c +++ b/drivers/misc/habanalabs/goya/goya.c @@ -2435,7 +2435,23 @@ static int goya_load_boot_fit_to_device(struct hl_device *hdev) static void goya_init_dynamic_firmware_loader(struct hl_device *hdev) { + struct dynamic_fw_load_mgr *dynamic_loader; + struct cpu_dyn_regs *dyn_regs; + dynamic_loader = &hdev->fw_loader.dynamic_loader; + + /* + * here we update initial values for few specific dynamic regs (as + * before reading the first descriptor from FW those value has to be + * hard-coded) in later stages of the protocol those values will be + * updated automatically by reading the FW descriptor so data there + * will always be up-to-date + */ + dyn_regs = &dynamic_loader->comm_desc.cpu_dyn_regs; + dyn_regs->kmd_msg_to_cpu = + cpu_to_le32(mmPSOC_GLOBAL_CONF_KMD_MSG_TO_CPU); + dyn_regs->cpu_cmd_status_to_host = + cpu_to_le32(mmCPU_CMD_STATUS_TO_HOST); } static void goya_init_static_firmware_loader(struct hl_device *hdev) @@ -2446,6 +2462,8 @@ static void goya_init_static_firmware_loader(struct hl_device *hdev) static_loader->preboot_version_max_off = SRAM_SIZE - VERSION_MAX_LEN; static_loader->boot_fit_version_max_off = SRAM_SIZE - VERSION_MAX_LEN; + static_loader->kmd_msg_to_cpu_reg = mmPSOC_GLOBAL_CONF_KMD_MSG_TO_CPU; + static_loader->cpu_cmd_status_to_host_reg = mmCPU_CMD_STATUS_TO_HOST; static_loader->cpu_boot_status_reg = mmPSOC_GLOBAL_CONF_CPU_BOOT_STATUS; static_loader->cpu_boot_dev_status_reg = mmCPU_BOOT_DEV_STS0; static_loader->boot_err0_reg = mmCPU_BOOT_ERR0; @@ -2460,12 +2478,13 @@ static void goya_init_firmware_loader(struct hl_device *hdev) struct fw_load_mgr *fw_loader = &hdev->fw_loader; /* fill common fields */ - fw_loader->kmd_msg_to_cpu_reg = mmPSOC_GLOBAL_CONF_KMD_MSG_TO_CPU; - fw_loader->cpu_cmd_status_to_host_reg = mmCPU_CMD_STATUS_TO_HOST; + fw_loader->boot_fit_img.image_name = GOYA_BOOT_FIT_FILE; + fw_loader->linux_img.image_name = GOYA_LINUX_FW_FILE; fw_loader->cpu_timeout = GOYA_CPU_TIMEOUT_USEC; fw_loader->boot_fit_timeout = GOYA_BOOT_FIT_REQ_TIMEOUT_USEC; fw_loader->skip_bmc = false; fw_loader->sram_bar_id = SRAM_CFG_BAR_ID; + fw_loader->dram_bar_id = DDR_BAR_ID; if (prop->dynamic_fw_load) goya_init_dynamic_firmware_loader(hdev); -- cgit v1.2.3 From b31e59bc55435fd2e43817344dfaea85219e39a4 Mon Sep 17 00:00:00 2001 From: Ohad Sharabi Date: Thu, 22 Apr 2021 10:01:22 +0300 Subject: habanalabs: load linux image to device Implementing dynamic linux image load to the device. This patch also implements the FW communication steps during the boot-fit. This patch also enables the dynamic protocol based on the compatibility flag. Signed-off-by: Ohad Sharabi Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 305 ++++++++++++++++++++------- drivers/misc/habanalabs/common/habanalabs.h | 10 +- drivers/misc/habanalabs/gaudi/gaudi.c | 8 + drivers/misc/habanalabs/goya/goya.c | 7 + 4 files changed, 249 insertions(+), 81 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index fc386ad8a302..0f6cee8af0b6 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -14,13 +14,7 @@ #define FW_FILE_MAX_SIZE 0x1400000 /* maximum size of 20MB */ -/* - * when copying image to FW we assume that PCI bar should not be re-set - * (refers mainly to DRAM in which we do such it to access arbitrary region's - * memory address) and we limit the BAR offset to 1G which should be more than - * reasonable for image copy purposes. - */ -#define FW_IMAGE_MAX_BAR_OFFSET (1024 * 1024 * 1024) +#define FW_CPU_STATUS_POLL_INTERVAL_USEC 10000 static int hl_request_fw(struct hl_device *hdev, const struct firmware **firmware_p, @@ -898,7 +892,7 @@ static int hl_fw_read_preboot_caps(struct hl_device *hdev, (status == CPU_BOOT_STATUS_READY_TO_BOOT) || (status == CPU_BOOT_STATUS_SRAM_AVAIL) || (status == CPU_BOOT_STATUS_WAITING_FOR_BOOT_FIT), - 10000, + FW_CPU_STATUS_POLL_INTERVAL_USEC, timeout); if (rc) { @@ -916,14 +910,8 @@ static int hl_fw_read_preboot_caps(struct hl_device *hdev, prop->fw_preboot_caps_map = RREG32(cpu_boot_caps_reg); - /* - * For now- force dynamic_fw_load to false as LKD does not yet - * implements all necessary parts of it. - * TODO: once dynamic load is ready set to: - * prop->dynamic_fw_load = !!(prop->fw_preboot_caps_map & - * CPU_BOOT_DEV_STS0_FW_LD_COM_EN) - */ - prop->dynamic_fw_load = 0; + prop->dynamic_fw_load = !!(prop->fw_preboot_caps_map & + CPU_BOOT_DEV_STS0_FW_LD_COM_EN); /* initialize FW loader once we know what load protocol is used */ hdev->asic_funcs->init_firmware_loader(hdev); @@ -1070,13 +1058,13 @@ int hl_fw_read_preboot_status(struct hl_device *hdev, u32 cpu_boot_status_reg, if (rc) return rc; - if (!hdev->asic_prop.dynamic_fw_load) - return hl_fw_static_read_preboot_status(hdev, cpu_boot_status_reg, + /* no need to read preboot status in dynamic load */ + if (hdev->asic_prop.dynamic_fw_load) + return 0; + + return hl_fw_static_read_preboot_status(hdev, cpu_boot_status_reg, cpu_boot_caps_reg, boot_err0_reg, timeout); - - dev_err(hdev->dev, "Dynamic FW load is not supported\n"); - return -EINVAL; } /* associate string with COMM status */ @@ -1202,7 +1190,7 @@ static int hl_fw_dynamic_wait_for_status(struct hl_device *hdev, le32_to_cpu(dyn_regs->cpu_cmd_status_to_host), status, FIELD_GET(COMMS_STATUS_STATUS_MASK, status) == expected_status, - 10000, + FW_CPU_STATUS_POLL_INTERVAL_USEC, timeout); if (rc) { @@ -1373,7 +1361,7 @@ static int hl_fw_dynamic_validate_memory_bound(struct hl_device *hdev, * memory transfers) */ if (end_addr >= region->region_base - region->offset_in_bar + - FW_IMAGE_MAX_BAR_OFFSET) { + region->bar_size) { dev_err(hdev->dev, "FW image beyond PCI BAR bounds\n"); return -EIO; @@ -1617,21 +1605,76 @@ static int hl_fw_dynamic_copy_image(struct hl_device *hdev, } /** - * hl_fw_dynamic_load_boot_fit - load boot fit using dynamic protocol + * hl_fw_boot_fit_update_state - update internal data structures after boot-fit + * is loaded + * + * @hdev: pointer to the habanalabs device structure + * @cpu_security_boot_status_reg: register holding security status props + * + * @return 0 on success, otherwise non-zero error code + */ +static void hl_fw_boot_fit_update_state(struct hl_device *hdev, + u32 cpu_security_boot_status_reg) +{ + struct asic_fixed_properties *prop = &hdev->asic_prop; + + /* Clear reset status since we need to read it again from boot CPU */ + prop->hard_reset_done_by_fw = false; + + /* Read boot_cpu security bits */ + if (prop->fw_security_status_valid) { + prop->fw_boot_cpu_security_map = + RREG32(cpu_security_boot_status_reg); + + if (prop->fw_boot_cpu_security_map & + CPU_BOOT_DEV_STS0_FW_HARD_RST_EN) + prop->hard_reset_done_by_fw = true; + + dev_dbg(hdev->dev, + "Firmware boot CPU security status %#x\n", + prop->fw_boot_cpu_security_map); + } + + dev_dbg(hdev->dev, "Firmware boot CPU hard-reset is %s\n", + prop->hard_reset_done_by_fw ? "enabled" : "disabled"); +} + +/** + * hl_fw_dynamic_load_image - load FW image using dynamic protocol * * @hdev: pointer to the habanalabs device structure * @fw_loader: managing structure for loading device's FW + * @load_fwc: the FW component to be loaded + * @img_ld_timeout: image load timeout * * @return 0 on success, otherwise non-zero error code */ -static int hl_fw_dynamic_load_boot_fit(struct hl_device *hdev, - struct fw_load_mgr *fw_loader) +static int hl_fw_dynamic_load_image(struct hl_device *hdev, + struct fw_load_mgr *fw_loader, + enum hl_fw_component load_fwc, + u32 img_ld_timeout) { + enum hl_fw_component cur_fwc; const struct firmware *fw; + char *fw_name; int rc = 0; + /* + * when loading image we have one of 2 scenarios: + * 1. current FW component is preboot and we want to load boot-fit + * 2. current FW component is boot-fit and we want to load linux + */ + if (load_fwc == FW_COMP_BOOT_FIT) { + cur_fwc = FW_COMP_PREBOOT; + fw_name = fw_loader->boot_fit_img.image_name; + } else { + cur_fwc = FW_COMP_BOOT_FIT; + fw_name = fw_loader->linux_img.image_name; + + } + /* request FW in order to communicate to FW the size to be allocated */ - rc = hl_request_fw(hdev, &fw, fw_loader->boot_fit_img.image_name); + rc = hl_request_fw(hdev, &fw, fw_name); if (rc) return rc; @@ -1643,11 +1686,21 @@ static int hl_fw_dynamic_load_boot_fit(struct hl_device *hdev, goto release_fw; /* read preboot version */ - hl_fw_dynamic_read_device_fw_version(hdev, FW_COMP_PREBOOT, + hl_fw_dynamic_read_device_fw_version(hdev, cur_fwc, fw_loader->dynamic_loader.comm_desc.cur_fw_ver); - /* update state during preboot handshake */ - hl_fw_preboot_update_state(hdev); + + /* update state according to boot stage */ + if (cur_fwc == FW_COMP_BOOT_FIT) { + struct cpu_dyn_regs *dyn_regs; + + dyn_regs = &fw_loader->dynamic_loader.comm_desc.cpu_dyn_regs; + hl_fw_boot_fit_update_state(hdev, + le32_to_cpu(dyn_regs->cpu_boot_status)); + } else { + /* update state during preboot handshake */ + hl_fw_preboot_update_state(hdev); + } /* copy boot fit to space allocated by FW */ rc = hl_fw_dynamic_copy_image(hdev, fw, fw_loader); @@ -1662,13 +1715,104 @@ static int hl_fw_dynamic_load_boot_fit(struct hl_device *hdev, rc = hl_fw_dynamic_send_protocol_cmd(hdev, fw_loader, COMMS_EXEC, 0, false, - fw_loader->boot_fit_timeout); + img_ld_timeout); release_fw: hl_release_firmware(fw); return rc; } +static int hl_fw_dynamic_wait_for_boot_fit_active(struct hl_device *hdev, + struct fw_load_mgr *fw_loader) +{ + struct dynamic_fw_load_mgr *dyn_loader; + u32 status; + int rc; + + dyn_loader = &fw_loader->dynamic_loader; + + /* Make sure CPU boot-loader is running */ + rc = hl_poll_timeout( + hdev, + le32_to_cpu(dyn_loader->comm_desc.cpu_dyn_regs.cpu_boot_status), + status, + (status == CPU_BOOT_STATUS_NIC_FW_RDY) || + (status == CPU_BOOT_STATUS_READY_TO_BOOT), + FW_CPU_STATUS_POLL_INTERVAL_USEC, + dyn_loader->wait_for_bl_timeout); + if (rc) { + dev_err(hdev->dev, "failed to wait for boot\n"); + return rc; + } + + dev_dbg(hdev->dev, "uboot status = %d\n", status); + return 0; +} + +static int hl_fw_dynamic_wait_for_linux_active(struct hl_device *hdev, + struct fw_load_mgr *fw_loader) +{ + struct dynamic_fw_load_mgr *dyn_loader; + u32 status; + int rc; + + dyn_loader = &fw_loader->dynamic_loader; + + /* Make sure CPU boot-loader is running */ + + rc = hl_poll_timeout( + hdev, + le32_to_cpu(dyn_loader->comm_desc.cpu_dyn_regs.cpu_boot_status), + status, + (status == CPU_BOOT_STATUS_SRAM_AVAIL), + FW_CPU_STATUS_POLL_INTERVAL_USEC, + fw_loader->cpu_timeout); + if (rc) { + dev_err(hdev->dev, "failed to wait for Linux\n"); + return rc; + } + + dev_dbg(hdev->dev, "Boot status = %d\n", status); + return 0; +} + +/** + * hl_fw_linux_update_state - update internal data structures after loading + * Linux + * + * + * @hdev: pointer to the habanalabs device structure + * + * @return 0 on success, otherwise non-zero error code + */ +static void hl_fw_linux_update_state(struct hl_device *hdev, + u32 cpu_boot_status_reg) +{ + struct asic_fixed_properties *prop = &hdev->asic_prop; + + /* Clear reset status since we need to read again from app */ + prop->hard_reset_done_by_fw = false; + + /* Read FW application security bits */ + if (prop->fw_security_status_valid) { + prop->fw_app_security_map = + RREG32(cpu_boot_status_reg); + + if (prop->fw_app_security_map & + CPU_BOOT_DEV_STS0_FW_HARD_RST_EN) + prop->hard_reset_done_by_fw = true; + + dev_dbg(hdev->dev, + "Firmware application CPU security status %#x\n", + prop->fw_app_security_map); + } + + dev_dbg(hdev->dev, "Firmware application CPU hard-reset is %s\n", + prop->hard_reset_done_by_fw ? "enabled" : "disabled"); + + dev_info(hdev->dev, "Successfully loaded firmware to device\n"); +} + /** * hl_fw_dynamic_init_cpu - initialize the device CPU using dynamic protocol * @@ -1693,6 +1837,8 @@ static int hl_fw_dynamic_init_cpu(struct hl_device *hdev, struct cpu_dyn_regs *dyn_regs; int rc; + dyn_regs = &fw_loader->dynamic_loader.comm_desc.cpu_dyn_regs; + rc = hl_fw_dynamic_send_protocol_cmd(hdev, fw_loader, COMMS_RST_STATE, 0, true, fw_loader->cpu_timeout); @@ -1700,6 +1846,9 @@ static int hl_fw_dynamic_init_cpu(struct hl_device *hdev, goto protocol_err; if (!(hdev->fw_components & FW_TYPE_BOOT_CPU)) { + /* update the preboot state */ + hl_fw_preboot_update_state(hdev); + rc = hl_fw_dynamic_request_descriptor(hdev, fw_loader, 0); if (rc) goto protocol_err; @@ -1711,14 +1860,50 @@ static int hl_fw_dynamic_init_cpu(struct hl_device *hdev, } /* load boot fit to FW */ - rc = hl_fw_dynamic_load_boot_fit(hdev, fw_loader); + rc = hl_fw_dynamic_load_image(hdev, fw_loader, FW_COMP_BOOT_FIT, + fw_loader->boot_fit_timeout); + if (rc) { + dev_err(hdev->dev, "failed to load boot fit\n"); + goto protocol_err; + } + + rc = hl_fw_dynamic_wait_for_boot_fit_active(hdev, fw_loader); if (rc) goto protocol_err; + if (!(hdev->fw_components & FW_TYPE_LINUX)) { + dev_info(hdev->dev, "Skip loading Linux F/W\n"); + return 0; + } + + if (fw_loader->skip_bmc) { + rc = hl_fw_dynamic_send_protocol_cmd(hdev, fw_loader, + COMMS_SKIP_BMC, 0, + true, + fw_loader->cpu_timeout); + if (rc) { + dev_err(hdev->dev, "failed to load boot fit\n"); + goto protocol_err; + } + } + + /* load Linux image to FW */ + rc = hl_fw_dynamic_load_image(hdev, fw_loader, FW_COMP_LINUX, + fw_loader->cpu_timeout); + if (rc) { + dev_err(hdev->dev, "failed to load Linux\n"); + goto protocol_err; + } + + rc = hl_fw_dynamic_wait_for_linux_active(hdev, fw_loader); + if (rc) + goto protocol_err; + + hl_fw_linux_update_state(hdev, le32_to_cpu(dyn_regs->cpu_boot_status)); + return 0; protocol_err: - dyn_regs = &fw_loader->dynamic_loader.comm_desc.cpu_dyn_regs; fw_read_errors(hdev, le32_to_cpu(dyn_regs->cpu_boot_err0), le32_to_cpu(dyn_regs->cpu_boot_status)); return rc; @@ -1737,7 +1922,6 @@ static int hl_fw_static_init_cpu(struct hl_device *hdev, { u32 cpu_msg_status_reg, cpu_timeout, msg_to_cpu_reg, status; u32 cpu_boot_status_reg, cpu_security_boot_status_reg; - struct asic_fixed_properties *prop = &hdev->asic_prop; struct static_fw_load_mgr *static_loader; int rc; @@ -1763,7 +1947,7 @@ static int hl_fw_static_init_cpu(struct hl_device *hdev, cpu_boot_status_reg, status, status == CPU_BOOT_STATUS_WAITING_FOR_BOOT_FIT, - 10000, + FW_CPU_STATUS_POLL_INTERVAL_USEC, fw_loader->boot_fit_timeout); if (rc) { @@ -1786,7 +1970,7 @@ static int hl_fw_static_init_cpu(struct hl_device *hdev, cpu_msg_status_reg, status, status == CPU_MSG_OK, - 10000, + FW_CPU_STATUS_POLL_INTERVAL_USEC, fw_loader->boot_fit_timeout); if (rc) { @@ -1808,7 +1992,7 @@ static int hl_fw_static_init_cpu(struct hl_device *hdev, (status == CPU_BOOT_STATUS_NIC_FW_RDY) || (status == CPU_BOOT_STATUS_READY_TO_BOOT) || (status == CPU_BOOT_STATUS_SRAM_AVAIL), - 10000, + FW_CPU_STATUS_POLL_INTERVAL_USEC, cpu_timeout); dev_dbg(hdev->dev, "uboot status = %d\n", status); @@ -1816,25 +2000,8 @@ static int hl_fw_static_init_cpu(struct hl_device *hdev, /* Read U-Boot version now in case we will later fail */ hl_fw_static_read_device_fw_version(hdev, FW_COMP_BOOT_FIT); - /* Clear reset status since we need to read it again from boot CPU */ - prop->hard_reset_done_by_fw = false; - - /* Read boot_cpu security bits */ - if (prop->fw_security_status_valid) { - prop->fw_boot_cpu_security_map = - RREG32(cpu_security_boot_status_reg); - - if (prop->fw_boot_cpu_security_map & - CPU_BOOT_DEV_STS0_FW_HARD_RST_EN) - prop->hard_reset_done_by_fw = true; - - dev_dbg(hdev->dev, - "Firmware boot CPU security status %#x\n", - prop->fw_boot_cpu_security_map); - } - - dev_dbg(hdev->dev, "Firmware boot CPU hard-reset is %s\n", - prop->hard_reset_done_by_fw ? "enabled" : "disabled"); + /* update state according to boot stage */ + hl_fw_boot_fit_update_state(hdev, cpu_security_boot_status_reg); if (rc) { detect_cpu_boot_status(hdev, status); @@ -1865,7 +2032,7 @@ static int hl_fw_static_init_cpu(struct hl_device *hdev, cpu_boot_status_reg, status, (status == CPU_BOOT_STATUS_BMC_WAITING_SKIPPED), - 10000, + FW_CPU_STATUS_POLL_INTERVAL_USEC, cpu_timeout); if (rc) { @@ -1885,7 +2052,7 @@ static int hl_fw_static_init_cpu(struct hl_device *hdev, cpu_boot_status_reg, status, (status == CPU_BOOT_STATUS_SRAM_AVAIL), - 10000, + FW_CPU_STATUS_POLL_INTERVAL_USEC, cpu_timeout); /* Clear message */ @@ -1909,27 +2076,7 @@ static int hl_fw_static_init_cpu(struct hl_device *hdev, if (rc) return rc; - /* Clear reset status since we need to read again from app */ - prop->hard_reset_done_by_fw = false; - - /* Read FW application security bits */ - if (prop->fw_security_status_valid) { - prop->fw_app_security_map = - RREG32(cpu_security_boot_status_reg); - - if (prop->fw_app_security_map & - CPU_BOOT_DEV_STS0_FW_HARD_RST_EN) - prop->hard_reset_done_by_fw = true; - - dev_dbg(hdev->dev, - "Firmware application CPU security status %#x\n", - prop->fw_app_security_map); - } - - dev_dbg(hdev->dev, "Firmware application CPU hard-reset is %s\n", - prop->hard_reset_done_by_fw ? "enabled" : "disabled"); - - dev_info(hdev->dev, "Successfully loaded firmware to device\n"); + hl_fw_linux_update_state(hdev, cpu_security_boot_status_reg); return 0; diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index e0fb9f443ab6..f2f04a1a2418 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -180,10 +180,12 @@ enum hl_pci_match_mode { * enum hl_fw_component - F/W components to read version through registers. * @FW_COMP_BOOT_FIT: boot fit. * @FW_COMP_PREBOOT: preboot. + * @FW_COMP_LINUX: linux. */ enum hl_fw_component { FW_COMP_BOOT_FIT, - FW_COMP_PREBOOT + FW_COMP_PREBOOT, + FW_COMP_LINUX, }; /** @@ -830,6 +832,7 @@ enum pci_region { * struct pci_mem_region - describe memory region in a PCI bar * @region_base: region base address * @region_size: region size + * @bar_size: size of the BAR * @offset_in_bar: region offset into the bar * @bar_id: bar ID of the region * @used: if used 1, otherwise 0 @@ -837,6 +840,7 @@ enum pci_region { struct pci_mem_region { u64 region_base; u64 region_size; + u64 bar_size; u32 offset_in_bar; u8 bar_id; u8 used; @@ -885,13 +889,15 @@ struct fw_response { * @response: FW to LKD response * @comm_desc: the communication descriptor with FW * @image_region: region to copy the FW image to - * @fw_image_size: FW image size + * @fw_image_size: size of FW image to load + * @wait_for_bl_timeout: timeout for waiting for boot loader to respond */ struct dynamic_fw_load_mgr { struct fw_response response; struct lkd_fw_comms_desc comm_desc; struct pci_mem_region *image_region; size_t fw_image_size; + u32 wait_for_bl_timeout; }; /** diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index d8afcb064d88..99914a893ded 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -78,6 +78,7 @@ #define GAUDI_PLDM_TPC_KERNEL_WAIT_USEC (HL_DEVICE_TIMEOUT_USEC * 30) #define GAUDI_BOOT_FIT_REQ_TIMEOUT_USEC 1000000 /* 1s */ #define GAUDI_MSG_TO_CPU_TIMEOUT_USEC 4000000 /* 4s */ +#define GAUDI_WAIT_FOR_BL_TIMEOUT_USEC 15000000 /* 15s */ #define GAUDI_QMAN0_FENCE_VAL 0x72E91AB9 @@ -1592,6 +1593,7 @@ free_internal_qmans_pq_mem: static void gaudi_set_pci_memory_regions(struct hl_device *hdev) { + struct asic_fixed_properties *prop = &hdev->asic_prop; struct pci_mem_region *region; /* CFG */ @@ -1599,6 +1601,7 @@ static void gaudi_set_pci_memory_regions(struct hl_device *hdev) region->region_base = CFG_BASE; region->region_size = CFG_SIZE; region->offset_in_bar = CFG_BASE - SPI_FLASH_BASE_ADDR; + region->bar_size = CFG_BAR_SIZE; region->bar_id = CFG_BAR_ID; region->used = 1; @@ -1607,6 +1610,7 @@ static void gaudi_set_pci_memory_regions(struct hl_device *hdev) region->region_base = SRAM_BASE_ADDR; region->region_size = SRAM_SIZE; region->offset_in_bar = 0; + region->bar_size = SRAM_BAR_SIZE; region->bar_id = SRAM_BAR_ID; region->used = 1; @@ -1615,6 +1619,7 @@ static void gaudi_set_pci_memory_regions(struct hl_device *hdev) region->region_base = DRAM_PHYS_BASE; region->region_size = hdev->asic_prop.dram_size; region->offset_in_bar = 0; + region->bar_size = prop->dram_pci_bar_size; region->bar_id = HBM_BAR_ID; region->used = 1; @@ -1623,6 +1628,7 @@ static void gaudi_set_pci_memory_regions(struct hl_device *hdev) region->region_base = PSOC_SCRATCHPAD_ADDR; region->region_size = PSOC_SCRATCHPAD_SIZE; region->offset_in_bar = PSOC_SCRATCHPAD_ADDR - SPI_FLASH_BASE_ADDR; + region->bar_size = CFG_BAR_SIZE; region->bar_id = CFG_BAR_ID; region->used = 1; } @@ -3749,6 +3755,8 @@ static void gaudi_init_dynamic_firmware_loader(struct hl_device *hdev) cpu_to_le32(mmPSOC_GLOBAL_CONF_KMD_MSG_TO_CPU); dyn_regs->cpu_cmd_status_to_host = cpu_to_le32(mmCPU_CMD_STATUS_TO_HOST); + + dynamic_loader->wait_for_bl_timeout = GAUDI_WAIT_FOR_BL_TIMEOUT_USEC; } static void gaudi_init_static_firmware_loader(struct hl_device *hdev) diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c index 469587a63804..ef0e3f7965cd 100644 --- a/drivers/misc/habanalabs/goya/goya.c +++ b/drivers/misc/habanalabs/goya/goya.c @@ -87,6 +87,7 @@ #define GOYA_PLDM_QMAN0_TIMEOUT_USEC (HL_DEVICE_TIMEOUT_USEC * 30) #define GOYA_BOOT_FIT_REQ_TIMEOUT_USEC 1000000 /* 1s */ #define GOYA_MSG_TO_CPU_TIMEOUT_USEC 4000000 /* 4s */ +#define GOYA_WAIT_FOR_BL_TIMEOUT_USEC 15000000 /* 15s */ #define GOYA_QMAN0_FENCE_VAL 0xD169B243 @@ -851,6 +852,7 @@ void goya_late_fini(struct hl_device *hdev) static void goya_set_pci_memory_regions(struct hl_device *hdev) { + struct asic_fixed_properties *prop = &hdev->asic_prop; struct pci_mem_region *region; /* CFG */ @@ -858,6 +860,7 @@ static void goya_set_pci_memory_regions(struct hl_device *hdev) region->region_base = CFG_BASE; region->region_size = CFG_SIZE; region->offset_in_bar = CFG_BASE - SRAM_BASE_ADDR; + region->bar_size = CFG_BAR_SIZE; region->bar_id = SRAM_CFG_BAR_ID; region->used = 1; @@ -866,6 +869,7 @@ static void goya_set_pci_memory_regions(struct hl_device *hdev) region->region_base = SRAM_BASE_ADDR; region->region_size = SRAM_SIZE; region->offset_in_bar = 0; + region->bar_size = CFG_BAR_SIZE; region->bar_id = SRAM_CFG_BAR_ID; region->used = 1; @@ -874,6 +878,7 @@ static void goya_set_pci_memory_regions(struct hl_device *hdev) region->region_base = DRAM_PHYS_BASE; region->region_size = hdev->asic_prop.dram_size; region->offset_in_bar = 0; + region->bar_size = prop->dram_pci_bar_size; region->bar_id = DDR_BAR_ID; region->used = 1; } @@ -2452,6 +2457,8 @@ static void goya_init_dynamic_firmware_loader(struct hl_device *hdev) cpu_to_le32(mmPSOC_GLOBAL_CONF_KMD_MSG_TO_CPU); dyn_regs->cpu_cmd_status_to_host = cpu_to_le32(mmCPU_CMD_STATUS_TO_HOST); + + dynamic_loader->wait_for_bl_timeout = GOYA_WAIT_FOR_BL_TIMEOUT_USEC; } static void goya_init_static_firmware_loader(struct hl_device *hdev) -- cgit v1.2.3 From 7693f5d39ee0134b1398a57c2998a0b67ef56700 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Thu, 29 Apr 2021 16:50:05 +0300 Subject: habanalabs: ignore device unusable status Some users might want to implement their own policy of when the device is unusable so we need to ignore this status in the driver and continue loading as normal. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index 0f6cee8af0b6..03e26a1fd9c1 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -438,9 +438,9 @@ static int fw_read_errors(struct hl_device *hdev, u32 boot_err0_reg, } if (err_val & CPU_BOOT_ERR0_DEVICE_UNUSABLE_FAIL) { - dev_err(hdev->dev, - "Device boot error - device unusable\n"); - err_exists = true; + /* Ignore this bit, don't prevent driver loading */ + dev_dbg(hdev->dev, "device unusable status is set\n"); + err_val &= ~CPU_BOOT_ERR0_DEVICE_UNUSABLE_FAIL; } security_val = RREG32(cpu_security_boot_status_reg); -- cgit v1.2.3 From 3f18b8421fcd1e9370c240245756f6179d6f357c Mon Sep 17 00:00:00 2001 From: Omer Shpigelman Date: Thu, 29 Apr 2021 22:29:29 +0300 Subject: habanalabs: add missing space after casting Change casting code according to kernel coding style. Signed-off-by: Omer Shpigelman Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/habanalabs_ioctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/habanalabs_ioctl.c b/drivers/misc/habanalabs/common/habanalabs_ioctl.c index 33841c272eb6..6604d30246e6 100644 --- a/drivers/misc/habanalabs/common/habanalabs_ioctl.c +++ b/drivers/misc/habanalabs/common/habanalabs_ioctl.c @@ -95,7 +95,7 @@ static int hw_ip_info(struct hl_device *hdev, struct hl_info_args *args) hw_ip.first_available_interrupt_id = prop->first_available_user_msix_interrupt; return copy_to_user(out, &hw_ip, - min((size_t)size, sizeof(hw_ip))) ? -EFAULT : 0; + min((size_t) size, sizeof(hw_ip))) ? -EFAULT : 0; } static int hw_events_info(struct hl_device *hdev, bool aggregate, -- cgit v1.2.3 From c07c54e9de32ea8e89e7c2a112c14f59602a402c Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Sun, 2 May 2021 12:28:48 +0300 Subject: habanalabs: better error print for pin failure Print the user given pointer and error code on failure to get user pages for easier debugging. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/memory.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/memory.c b/drivers/misc/habanalabs/common/memory.c index 43924e1c0315..a7a8984e6af2 100644 --- a/drivers/misc/habanalabs/common/memory.c +++ b/drivers/misc/habanalabs/common/memory.c @@ -1612,7 +1612,8 @@ static int get_user_memory(struct hl_device *hdev, u64 addr, u64 size, if (rc != npages) { dev_err(hdev->dev, - "Failed to map host memory, user ptr probably wrong\n"); + "Failed (%d) to pin host memory with user ptr 0x%llx\n", + rc, addr); if (rc < 0) goto destroy_pages; npages = rc; -- cgit v1.2.3 From 6542c3541d0f9405626faff9509aa28671fc3804 Mon Sep 17 00:00:00 2001 From: Ohad Sharabi Date: Sun, 2 May 2021 09:56:51 +0300 Subject: habanalabs: set dma mask from fw once fw done iatu config When setting "DMA mask from FW" we are reading PSOC_GLOBAL_CONF register which is allowed only once FW has done it's iATU configuration. Signed-off-by: Ohad Sharabi Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/pci/pci.c | 10 ++++++---- drivers/misc/habanalabs/gaudi/gaudi.c | 4 +--- drivers/misc/habanalabs/goya/goya.c | 4 +--- 3 files changed, 8 insertions(+), 10 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/pci/pci.c b/drivers/misc/habanalabs/common/pci/pci.c index 8e7982be6191..d5bedf5ba011 100644 --- a/drivers/misc/habanalabs/common/pci/pci.c +++ b/drivers/misc/habanalabs/common/pci/pci.c @@ -421,6 +421,12 @@ int hl_pci_init(struct hl_device *hdev) goto unmap_pci_bars; } + /* Driver must sleep in order for FW to finish the iATU configuration */ + if (hdev->asic_prop.iatu_done_by_fw) { + usleep_range(2000, 3000); + hdev->asic_funcs->set_dma_mask_from_fw(hdev); + } + rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(hdev->dma_mask)); if (rc) { @@ -430,10 +436,6 @@ int hl_pci_init(struct hl_device *hdev) goto unmap_pci_bars; } - /* Driver must sleep in order for FW to finish the iATU configuration */ - if (hdev->asic_prop.iatu_done_by_fw) - usleep_range(2000, 3000); - return 0; unmap_pci_bars: diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 99914a893ded..b41c3bc9746d 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -600,10 +600,8 @@ static int gaudi_init_iatu(struct hl_device *hdev) struct hl_outbound_pci_region outbound_region; int rc; - if (hdev->asic_prop.iatu_done_by_fw) { - hdev->asic_funcs->set_dma_mask_from_fw(hdev); + if (hdev->asic_prop.iatu_done_by_fw) return 0; - } /* Inbound Region 0 - Bar 0 - Point to SRAM + CFG */ inbound_region.mode = PCI_BAR_MATCH_MODE; diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c index ef0e3f7965cd..3b995e354c50 100644 --- a/drivers/misc/habanalabs/goya/goya.c +++ b/drivers/misc/habanalabs/goya/goya.c @@ -532,10 +532,8 @@ static int goya_init_iatu(struct hl_device *hdev) struct hl_outbound_pci_region outbound_region; int rc; - if (hdev->asic_prop.iatu_done_by_fw) { - hdev->asic_funcs->set_dma_mask_from_fw(hdev); + if (hdev->asic_prop.iatu_done_by_fw) return 0; - } /* Inbound Region 0 - Bar 0 - Point to SRAM and CFG */ inbound_region.mode = PCI_BAR_MATCH_MODE; -- cgit v1.2.3 From ea7d5e7b102bf0bd41eef1faa6b2337e45791a62 Mon Sep 17 00:00:00 2001 From: Ohad Sharabi Date: Mon, 3 May 2021 09:44:22 +0300 Subject: habanalabs: avoid using uninitialized pointer When attempting to read FW component's version we should break if input FW component is invalid in order to avoid using uninitialized destination pointer. Signed-off-by: Ohad Sharabi Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index 03e26a1fd9c1..e0fe2d5d4c57 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -1566,6 +1566,7 @@ static void hl_fw_dynamic_read_device_fw_version(struct hl_device *hdev, break; default: dev_warn(hdev->dev, "Undefined FW component: %d\n", fwc); + return; } strscpy(dest, fw_version, VERSION_MAX_LEN); -- cgit v1.2.3 From e67a60400ffc75f52705ae8cac937fd8f00e153a Mon Sep 17 00:00:00 2001 From: Ohad Sharabi Date: Sun, 2 May 2021 15:45:21 +0300 Subject: habanalabs: read f/w's 2-nd sts and err registers Maintain both STS1 and ERR1 registers used for status communication with F/W. Those are not maintained as we currently have less than 31 statuses/error defined and so LKD did not refer to those register. The reason to read them now is to try to support future f/w versions with current driver. Signed-off-by: Ohad Sharabi Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 287 +++++++++++++++++++-------- drivers/misc/habanalabs/common/habanalabs.h | 70 ++++--- drivers/misc/habanalabs/gaudi/gaudi.c | 43 ++-- drivers/misc/habanalabs/goya/goya.c | 24 ++- 4 files changed, 291 insertions(+), 133 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index e0fe2d5d4c57..3cf177e2ac1e 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -146,6 +146,7 @@ int hl_fw_send_cpu_message(struct hl_device *hdev, u32 hw_queue_id, u32 *msg, u16 len, u32 timeout, u64 *result) { struct hl_hw_queue *queue = &hdev->kernel_queues[hw_queue_id]; + struct asic_fixed_properties *prop = &hdev->asic_prop; struct cpucp_packet *pkt; dma_addr_t pkt_dma_addr; u32 tmp, expected_ack_val; @@ -180,8 +181,9 @@ int hl_fw_send_cpu_message(struct hl_device *hdev, u32 hw_queue_id, u32 *msg, goto out; } - if (hdev->asic_prop.fw_app_security_map & - CPU_BOOT_DEV_STS0_PKT_PI_ACK_EN) + if (prop->fw_cpu_boot_dev_sts0_valid && + (prop->fw_app_cpu_boot_dev_sts0 & + CPU_BOOT_DEV_STS0_PKT_PI_ACK_EN)) expected_ack_val = queue->pi; else expected_ack_val = CPUCP_PACKET_FENCE_VAL; @@ -344,24 +346,13 @@ int hl_fw_send_heartbeat(struct hl_device *hdev) return rc; } -static int fw_read_errors(struct hl_device *hdev, u32 boot_err0_reg, - u32 cpu_security_boot_status_reg) +static bool fw_report_boot_dev0(struct hl_device *hdev, u32 err_val, + u32 sts_val) { - u32 err_val, security_val; bool err_exists = false; - /* Some of the firmware status codes are deprecated in newer f/w - * versions. In those versions, the errors are reported - * in different registers. Therefore, we need to check those - * registers and print the exact errors. Moreover, there - * may be multiple errors, so we need to report on each error - * separately. Some of the error codes might indicate a state - * that is not an error per-se, but it is an error in production - * environment - */ - err_val = RREG32(boot_err0_reg); if (!(err_val & CPU_BOOT_ERR0_ENABLED)) - return 0; + return false; if (err_val & CPU_BOOT_ERR0_DRAM_INIT_FAIL) { dev_err(hdev->dev, @@ -432,6 +423,20 @@ static int fw_read_errors(struct hl_device *hdev, u32 boot_err0_reg, err_exists = true; } + if (err_val & CPU_BOOT_ERR0_PRI_IMG_VER_FAIL) { + dev_warn(hdev->dev, + "Device boot warning - Failed to load preboot primary image\n"); + /* This is a warning so we don't want it to disable the + * device as we have a secondary preboot image + */ + err_val &= ~CPU_BOOT_ERR0_PRI_IMG_VER_FAIL; + } + + if (err_val & CPU_BOOT_ERR0_SEC_IMG_VER_FAIL) { + dev_err(hdev->dev, "Device boot error - Failed to load preboot secondary image\n"); + err_exists = true; + } + if (err_val & CPU_BOOT_ERR0_PLL_FAIL) { dev_err(hdev->dev, "Device boot error - PLL failure\n"); err_exists = true; @@ -443,28 +448,89 @@ static int fw_read_errors(struct hl_device *hdev, u32 boot_err0_reg, err_val &= ~CPU_BOOT_ERR0_DEVICE_UNUSABLE_FAIL; } - security_val = RREG32(cpu_security_boot_status_reg); - if (security_val & CPU_BOOT_DEV_STS0_ENABLED) - dev_dbg(hdev->dev, "Device security status %#x\n", - security_val); + if (sts_val & CPU_BOOT_DEV_STS0_ENABLED) + dev_dbg(hdev->dev, "Device status0 %#x\n", sts_val); if (!err_exists && (err_val & ~CPU_BOOT_ERR0_ENABLED)) { dev_err(hdev->dev, - "Device boot error - unknown error 0x%08x\n", - err_val); + "Device boot error - unknown ERR0 error 0x%08x\n", err_val); err_exists = true; } + /* return error only if it's in the predefined mask */ if (err_exists && ((err_val & ~CPU_BOOT_ERR0_ENABLED) & lower_32_bits(hdev->boot_error_status_mask))) + return true; + + return false; +} + +/* placeholder for ERR1 as no errors defined there yet */ +static bool fw_report_boot_dev1(struct hl_device *hdev, u32 err_val, + u32 sts_val) +{ + /* + * keep this variable to preserve the logic of the function. + * this way it would require less modifications when error will be + * added to DEV_ERR1 + */ + bool err_exists = false; + + if (!(err_val & CPU_BOOT_ERR1_ENABLED)) + return false; + + if (sts_val & CPU_BOOT_DEV_STS1_ENABLED) + dev_dbg(hdev->dev, "Device status1 %#x\n", sts_val); + + if (!err_exists && (err_val & ~CPU_BOOT_ERR1_ENABLED)) { + dev_err(hdev->dev, + "Device boot error - unknown ERR1 error 0x%08x\n", + err_val); + err_exists = true; + } + + /* return error only if it's in the predefined mask */ + if (err_exists && ((err_val & ~CPU_BOOT_ERR1_ENABLED) & + upper_32_bits(hdev->boot_error_status_mask))) + return true; + + return false; +} + +static int fw_read_errors(struct hl_device *hdev, u32 boot_err0_reg, + u32 boot_err1_reg, u32 cpu_boot_dev_status0_reg, + u32 cpu_boot_dev_status1_reg) +{ + u32 err_val, status_val; + bool err_exists = false; + + /* Some of the firmware status codes are deprecated in newer f/w + * versions. In those versions, the errors are reported + * in different registers. Therefore, we need to check those + * registers and print the exact errors. Moreover, there + * may be multiple errors, so we need to report on each error + * separately. Some of the error codes might indicate a state + * that is not an error per-se, but it is an error in production + * environment + */ + err_val = RREG32(boot_err0_reg); + status_val = RREG32(cpu_boot_dev_status0_reg); + err_exists = fw_report_boot_dev0(hdev, err_val, status_val); + + err_val = RREG32(boot_err1_reg); + status_val = RREG32(cpu_boot_dev_status1_reg); + err_exists |= fw_report_boot_dev1(hdev, err_val, status_val); + + if (err_exists) return -EIO; return 0; } int hl_fw_cpucp_info_get(struct hl_device *hdev, - u32 cpu_security_boot_status_reg, - u32 boot_err0_reg) + u32 sts_boot_dev_sts0_reg, + u32 sts_boot_dev_sts1_reg, u32 boot_err0_reg, + u32 boot_err1_reg) { struct asic_fixed_properties *prop = &hdev->asic_prop; struct cpucp_packet pkt = {}; @@ -498,7 +564,8 @@ int hl_fw_cpucp_info_get(struct hl_device *hdev, goto out; } - rc = fw_read_errors(hdev, boot_err0_reg, cpu_security_boot_status_reg); + rc = fw_read_errors(hdev, boot_err0_reg, boot_err1_reg, + sts_boot_dev_sts0_reg, sts_boot_dev_sts1_reg); if (rc) { dev_err(hdev->dev, "Errors in device boot\n"); goto out; @@ -516,9 +583,13 @@ int hl_fw_cpucp_info_get(struct hl_device *hdev, } /* Read FW application security bits again */ - if (hdev->asic_prop.fw_security_status_valid) - hdev->asic_prop.fw_app_security_map = - RREG32(cpu_security_boot_status_reg); + if (hdev->asic_prop.fw_cpu_boot_dev_sts0_valid) + hdev->asic_prop.fw_app_cpu_boot_dev_sts0 = + RREG32(sts_boot_dev_sts0_reg); + + if (hdev->asic_prop.fw_cpu_boot_dev_sts1_valid) + hdev->asic_prop.fw_app_cpu_boot_dev_sts1 = + RREG32(sts_boot_dev_sts1_reg); out: hdev->asic_funcs->cpu_accessible_dma_pool_free(hdev, @@ -582,13 +653,15 @@ static int hl_fw_send_msi_info_msg(struct hl_device *hdev) } int hl_fw_cpucp_handshake(struct hl_device *hdev, - u32 cpu_security_boot_status_reg, - u32 boot_err0_reg) + u32 sts_boot_dev_sts0_reg, + u32 sts_boot_dev_sts1_reg, u32 boot_err0_reg, + u32 boot_err1_reg) { int rc; - rc = hl_fw_cpucp_info_get(hdev, cpu_security_boot_status_reg, - boot_err0_reg); + rc = hl_fw_cpucp_info_get(hdev, sts_boot_dev_sts0_reg, + sts_boot_dev_sts1_reg, boot_err0_reg, + boot_err1_reg); if (rc) return rc; @@ -723,8 +796,8 @@ int get_used_pll_index(struct hl_device *hdev, u32 input_pll_index, bool dynamic_pll; int fw_pll_idx; - dynamic_pll = prop->fw_security_status_valid && - (prop->fw_app_security_map & CPU_BOOT_DEV_STS0_DYN_PLL_EN); + dynamic_pll = prop->fw_cpu_boot_dev_sts0_valid && + (prop->fw_app_cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_DYN_PLL_EN); if (!dynamic_pll) { /* @@ -867,8 +940,10 @@ static void detect_cpu_boot_status(struct hl_device *hdev, u32 status) static int hl_fw_read_preboot_caps(struct hl_device *hdev, u32 cpu_boot_status_reg, - u32 cpu_boot_caps_reg, - u32 boot_err0_reg, u32 timeout) + u32 sts_boot_dev_sts0_reg, + u32 sts_boot_dev_sts1_reg, + u32 boot_err0_reg, u32 boot_err1_reg, + u32 timeout) { struct asic_fixed_properties *prop = &hdev->asic_prop; u32 status; @@ -903,15 +978,20 @@ static int hl_fw_read_preboot_caps(struct hl_device *hdev, * of reading specific errors */ if (status != -1) - fw_read_errors(hdev, boot_err0_reg, - cpu_boot_status_reg); + fw_read_errors(hdev, boot_err0_reg, boot_err1_reg, + sts_boot_dev_sts0_reg, + sts_boot_dev_sts1_reg); return -EIO; } - prop->fw_preboot_caps_map = RREG32(cpu_boot_caps_reg); + prop->fw_preboot_cpu_boot_dev_sts0 = RREG32(sts_boot_dev_sts0_reg); + prop->fw_preboot_cpu_boot_dev_sts1 = RREG32(sts_boot_dev_sts1_reg); - prop->dynamic_fw_load = !!(prop->fw_preboot_caps_map & + if (prop->fw_preboot_cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_ENABLED) + prop->dynamic_fw_load = !!(prop->fw_preboot_cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_FW_LD_COM_EN); + else + prop->dynamic_fw_load = 0; /* initialize FW loader once we know what load protocol is used */ hdev->asic_funcs->init_firmware_loader(hdev); @@ -978,9 +1058,10 @@ static int hl_fw_static_read_device_fw_version(struct hl_device *hdev, static void hl_fw_preboot_update_state(struct hl_device *hdev) { struct asic_fixed_properties *prop = &hdev->asic_prop; - u32 preboot_caps; + u32 cpu_boot_dev_sts0, cpu_boot_dev_sts1; - preboot_caps = prop->fw_preboot_caps_map; + cpu_boot_dev_sts0 = prop->fw_preboot_cpu_boot_dev_sts0; + cpu_boot_dev_sts1 = prop->fw_preboot_cpu_boot_dev_sts1; /* We read security status multiple times during boot: * 1. preboot - a. Check whether the security status bits are valid @@ -995,23 +1076,30 @@ static void hl_fw_preboot_update_state(struct hl_device *hdev) * Check security status bit (CPU_BOOT_DEV_STS0_ENABLED), if it is set * check security enabled bit (CPU_BOOT_DEV_STS0_SECURITY_EN) */ - if (preboot_caps & CPU_BOOT_DEV_STS0_ENABLED) { - prop->fw_security_status_valid = 1; + if (cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_ENABLED) { + prop->fw_cpu_boot_dev_sts0_valid = 1; /* FW security should be derived from PCI ID, we keep this * check for backward compatibility */ - if (preboot_caps & CPU_BOOT_DEV_STS0_SECURITY_EN) + if (cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_SECURITY_EN) prop->fw_security_disabled = false; - if (preboot_caps & CPU_BOOT_DEV_STS0_FW_HARD_RST_EN) + if (cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_FW_HARD_RST_EN) prop->hard_reset_done_by_fw = true; } else { - prop->fw_security_status_valid = 0; + prop->fw_cpu_boot_dev_sts0_valid = 0; } - dev_dbg(hdev->dev, "Firmware preboot security status %#x\n", - preboot_caps); + /* place holder for STS1 as no statuses are defined yet */ + prop->fw_cpu_boot_dev_sts1_valid = + !!(cpu_boot_dev_sts1 & CPU_BOOT_DEV_STS1_ENABLED); + + dev_dbg(hdev->dev, "Firmware preboot boot device status0 %#x\n", + cpu_boot_dev_sts0); + + dev_dbg(hdev->dev, "Firmware preboot boot device status1 %#x\n", + cpu_boot_dev_sts1); dev_dbg(hdev->dev, "Firmware preboot hard-reset is %s\n", prop->hard_reset_done_by_fw ? "enabled" : "disabled"); @@ -1020,9 +1108,7 @@ static void hl_fw_preboot_update_state(struct hl_device *hdev) prop->fw_security_disabled ? "disabled" : "enabled"); } -static int hl_fw_static_read_preboot_status(struct hl_device *hdev, - u32 cpu_boot_status_reg, u32 cpu_security_boot_status_reg, - u32 boot_err0_reg, u32 timeout) +static int hl_fw_static_read_preboot_status(struct hl_device *hdev) { int rc; @@ -1036,8 +1122,9 @@ static int hl_fw_static_read_preboot_status(struct hl_device *hdev, } int hl_fw_read_preboot_status(struct hl_device *hdev, u32 cpu_boot_status_reg, - u32 cpu_boot_caps_reg, u32 boot_err0_reg, - u32 timeout) + u32 sts_boot_dev_sts0_reg, + u32 sts_boot_dev_sts1_reg, u32 boot_err0_reg, + u32 boot_err1_reg, u32 timeout) { int rc; @@ -1053,8 +1140,9 @@ int hl_fw_read_preboot_status(struct hl_device *hdev, u32 cpu_boot_status_reg, * read the boot caps register */ rc = hl_fw_read_preboot_caps(hdev, cpu_boot_status_reg, - cpu_boot_caps_reg, boot_err0_reg, - timeout); + sts_boot_dev_sts0_reg, + sts_boot_dev_sts1_reg, boot_err0_reg, + boot_err1_reg, timeout); if (rc) return rc; @@ -1062,9 +1150,7 @@ int hl_fw_read_preboot_status(struct hl_device *hdev, u32 cpu_boot_status_reg, if (hdev->asic_prop.dynamic_fw_load) return 0; - return hl_fw_static_read_preboot_status(hdev, cpu_boot_status_reg, - cpu_boot_caps_reg, boot_err0_reg, - timeout); + return hl_fw_static_read_preboot_status(hdev); } /* associate string with COMM status */ @@ -1610,30 +1696,37 @@ static int hl_fw_dynamic_copy_image(struct hl_device *hdev, * is loaded * * @hdev: pointer to the habanalabs device structure - * @cpu_security_boot_status_reg: register holding security status props + * @cpu_boot_dev_sts0_reg: register holding CPU boot dev status 0 + * @cpu_boot_dev_sts1_reg: register holding CPU boot dev status 1 * * @return 0 on success, otherwise non-zero error code */ static void hl_fw_boot_fit_update_state(struct hl_device *hdev, - u32 cpu_security_boot_status_reg) + u32 cpu_boot_dev_sts0_reg, + u32 cpu_boot_dev_sts1_reg) { struct asic_fixed_properties *prop = &hdev->asic_prop; /* Clear reset status since we need to read it again from boot CPU */ prop->hard_reset_done_by_fw = false; - /* Read boot_cpu security bits */ - if (prop->fw_security_status_valid) { - prop->fw_boot_cpu_security_map = - RREG32(cpu_security_boot_status_reg); + /* Read boot_cpu status bits */ + if (prop->fw_cpu_boot_dev_sts0_valid) { + prop->fw_bootfit_cpu_boot_dev_sts0 = RREG32(cpu_boot_dev_sts0_reg); - if (prop->fw_boot_cpu_security_map & + if (prop->fw_bootfit_cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_FW_HARD_RST_EN) prop->hard_reset_done_by_fw = true; - dev_dbg(hdev->dev, - "Firmware boot CPU security status %#x\n", - prop->fw_boot_cpu_security_map); + dev_dbg(hdev->dev, "Firmware boot CPU status0 %#x\n", + prop->fw_bootfit_cpu_boot_dev_sts0); + } + + if (prop->fw_cpu_boot_dev_sts1_valid) { + prop->fw_bootfit_cpu_boot_dev_sts1 = RREG32(cpu_boot_dev_sts1_reg); + + dev_dbg(hdev->dev, "Firmware boot CPU status1 %#x\n", + prop->fw_bootfit_cpu_boot_dev_sts1); } dev_dbg(hdev->dev, "Firmware boot CPU hard-reset is %s\n", @@ -1697,7 +1790,8 @@ static int hl_fw_dynamic_load_image(struct hl_device *hdev, dyn_regs = &fw_loader->dynamic_loader.comm_desc.cpu_dyn_regs; hl_fw_boot_fit_update_state(hdev, - le32_to_cpu(dyn_regs->cpu_boot_status)); + le32_to_cpu(dyn_regs->cpu_boot_dev_sts0), + le32_to_cpu(dyn_regs->cpu_boot_dev_sts1)); } else { /* update state during preboot handshake */ hl_fw_preboot_update_state(hdev); @@ -1783,11 +1877,14 @@ static int hl_fw_dynamic_wait_for_linux_active(struct hl_device *hdev, * * * @hdev: pointer to the habanalabs device structure + * @cpu_boot_dev_sts0_reg: register holding CPU boot dev status 0 + * @cpu_boot_dev_sts1_reg: register holding CPU boot dev status 1 * * @return 0 on success, otherwise non-zero error code */ static void hl_fw_linux_update_state(struct hl_device *hdev, - u32 cpu_boot_status_reg) + u32 cpu_boot_dev_sts0_reg, + u32 cpu_boot_dev_sts1_reg) { struct asic_fixed_properties *prop = &hdev->asic_prop; @@ -1795,17 +1892,26 @@ static void hl_fw_linux_update_state(struct hl_device *hdev, prop->hard_reset_done_by_fw = false; /* Read FW application security bits */ - if (prop->fw_security_status_valid) { - prop->fw_app_security_map = - RREG32(cpu_boot_status_reg); + if (prop->fw_cpu_boot_dev_sts0_valid) { + prop->fw_app_cpu_boot_dev_sts0 = + RREG32(cpu_boot_dev_sts0_reg); - if (prop->fw_app_security_map & + if (prop->fw_app_cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_FW_HARD_RST_EN) prop->hard_reset_done_by_fw = true; dev_dbg(hdev->dev, - "Firmware application CPU security status %#x\n", - prop->fw_app_security_map); + "Firmware application CPU status0 %#x\n", + prop->fw_app_cpu_boot_dev_sts0); + } + + if (prop->fw_cpu_boot_dev_sts1_valid) { + prop->fw_app_cpu_boot_dev_sts1 = + RREG32(cpu_boot_dev_sts1_reg); + + dev_dbg(hdev->dev, + "Firmware application CPU status1 %#x\n", + prop->fw_app_cpu_boot_dev_sts1); } dev_dbg(hdev->dev, "Firmware application CPU hard-reset is %s\n", @@ -1900,13 +2006,16 @@ static int hl_fw_dynamic_init_cpu(struct hl_device *hdev, if (rc) goto protocol_err; - hl_fw_linux_update_state(hdev, le32_to_cpu(dyn_regs->cpu_boot_status)); + hl_fw_linux_update_state(hdev, le32_to_cpu(dyn_regs->cpu_boot_dev_sts0), + le32_to_cpu(dyn_regs->cpu_boot_dev_sts1)); return 0; protocol_err: fw_read_errors(hdev, le32_to_cpu(dyn_regs->cpu_boot_err0), - le32_to_cpu(dyn_regs->cpu_boot_status)); + le32_to_cpu(dyn_regs->cpu_boot_err1), + le32_to_cpu(dyn_regs->cpu_boot_dev_sts0), + le32_to_cpu(dyn_regs->cpu_boot_dev_sts1)); return rc; } @@ -1922,8 +2031,9 @@ static int hl_fw_static_init_cpu(struct hl_device *hdev, struct fw_load_mgr *fw_loader) { u32 cpu_msg_status_reg, cpu_timeout, msg_to_cpu_reg, status; - u32 cpu_boot_status_reg, cpu_security_boot_status_reg; + u32 cpu_boot_dev_status0_reg, cpu_boot_dev_status1_reg; struct static_fw_load_mgr *static_loader; + u32 cpu_boot_status_reg; int rc; if (!(hdev->fw_components & FW_TYPE_BOOT_CPU)) @@ -1936,7 +2046,8 @@ static int hl_fw_static_init_cpu(struct hl_device *hdev, static_loader = &fw_loader->static_loader; cpu_msg_status_reg = static_loader->cpu_cmd_status_to_host_reg; msg_to_cpu_reg = static_loader->kmd_msg_to_cpu_reg; - cpu_security_boot_status_reg = static_loader->cpu_boot_dev_status_reg; + cpu_boot_dev_status0_reg = static_loader->cpu_boot_dev_status0_reg; + cpu_boot_dev_status1_reg = static_loader->cpu_boot_dev_status1_reg; cpu_boot_status_reg = static_loader->cpu_boot_status_reg; dev_info(hdev->dev, "Going to wait for device boot (up to %lds)\n", @@ -2002,7 +2113,8 @@ static int hl_fw_static_init_cpu(struct hl_device *hdev, hl_fw_static_read_device_fw_version(hdev, FW_COMP_BOOT_FIT); /* update state according to boot stage */ - hl_fw_boot_fit_update_state(hdev, cpu_security_boot_status_reg); + hl_fw_boot_fit_update_state(hdev, cpu_boot_dev_status0_reg, + cpu_boot_dev_status1_reg); if (rc) { detect_cpu_boot_status(hdev, status); @@ -2073,17 +2185,22 @@ static int hl_fw_static_init_cpu(struct hl_device *hdev, } rc = fw_read_errors(hdev, fw_loader->static_loader.boot_err0_reg, - cpu_security_boot_status_reg); + fw_loader->static_loader.boot_err1_reg, + cpu_boot_dev_status0_reg, + cpu_boot_dev_status1_reg); if (rc) return rc; - hl_fw_linux_update_state(hdev, cpu_security_boot_status_reg); + hl_fw_linux_update_state(hdev, cpu_boot_dev_status0_reg, + cpu_boot_dev_status1_reg); return 0; out: fw_read_errors(hdev, fw_loader->static_loader.boot_err0_reg, - cpu_security_boot_status_reg); + fw_loader->static_loader.boot_err1_reg, + cpu_boot_dev_status0_reg, + cpu_boot_dev_status1_reg); return rc; } diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index f2f04a1a2418..afa3175ddfb7 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -422,15 +422,24 @@ struct hl_mmu_properties { * @cb_pool_cb_size: size of each CB in the CB pool. * @max_pending_cs: maximum of concurrent pending command submissions * @max_queues: maximum amount of queues in the system - * @fw_preboot_caps_map: bitmap representation of preboot cpu capabilities - * reported by FW, bit description can be found in - * CPU_BOOT_DEV_STS* - * @fw_boot_cpu_security_map: bitmap representation of boot cpu security status - * reported by FW, bit description can be found in - * CPU_BOOT_DEV_STS* - * @fw_app_security_map: bitmap representation of application security status - * reported by FW, bit description can be found in - * CPU_BOOT_DEV_STS* + * @fw_preboot_cpu_boot_dev_sts0: bitmap representation of preboot cpu + * capabilities reported by FW, bit description + * can be found in CPU_BOOT_DEV_STS0 + * @fw_preboot_cpu_boot_dev_sts1: bitmap representation of preboot cpu + * capabilities reported by FW, bit description + * can be found in CPU_BOOT_DEV_STS1 + * @fw_bootfit_cpu_boot_dev_sts0: bitmap representation of boot cpu security + * status reported by FW, bit description can be + * found in CPU_BOOT_DEV_STS0 + * @fw_bootfit_cpu_boot_dev_sts1: bitmap representation of boot cpu security + * status reported by FW, bit description can be + * found in CPU_BOOT_DEV_STS1 + * @fw_app_cpu_boot_dev_sts0: bitmap representation of application security + * status reported by FW, bit description can be + * found in CPU_BOOT_DEV_STS0 + * @fw_app_cpu_boot_dev_sts1: bitmap representation of application security + * status reported by FW, bit description can be + * found in CPU_BOOT_DEV_STS1 * @collective_first_sob: first sync object available for collective use * @collective_first_mon: first monitor available for collective use * @sync_stream_first_sob: first sync object available for sync stream use @@ -445,8 +454,10 @@ struct hl_mmu_properties { * @completion_queues_count: number of completion queues. * @fw_security_disabled: true if security measures are disabled in firmware, * false otherwise - * @fw_security_status_valid: security status bits are valid and can be fetched - * from BOOT_DEV_STS0 + * @fw_cpu_boot_dev_sts0_valid: status bits are valid and can be fetched from + * BOOT_DEV_STS0 + * @fw_cpu_boot_dev_sts1_valid: status bits are valid and can be fetched from + * BOOT_DEV_STS1 * @dram_supports_virtual_memory: is there an MMU towards the DRAM * @hard_reset_done_by_fw: true if firmware is handling hard reset flow * @num_functional_hbms: number of functional HBMs in each DCORE. @@ -497,9 +508,12 @@ struct asic_fixed_properties { u32 cb_pool_cb_size; u32 max_pending_cs; u32 max_queues; - u32 fw_preboot_caps_map; - u32 fw_boot_cpu_security_map; - u32 fw_app_security_map; + u32 fw_preboot_cpu_boot_dev_sts0; + u32 fw_preboot_cpu_boot_dev_sts1; + u32 fw_bootfit_cpu_boot_dev_sts0; + u32 fw_bootfit_cpu_boot_dev_sts1; + u32 fw_app_cpu_boot_dev_sts0; + u32 fw_app_cpu_boot_dev_sts1; u16 collective_first_sob; u16 collective_first_mon; u16 sync_stream_first_sob; @@ -512,7 +526,8 @@ struct asic_fixed_properties { u8 tpc_enabled_mask; u8 completion_queues_count; u8 fw_security_disabled; - u8 fw_security_status_valid; + u8 fw_cpu_boot_dev_sts0_valid; + u8 fw_cpu_boot_dev_sts1_valid; u8 dram_supports_virtual_memory; u8 hard_reset_done_by_fw; u8 num_functional_hbms; @@ -853,8 +868,10 @@ struct pci_mem_region { * @kmd_msg_to_cpu_reg: register address for KDM->CPU messages * @cpu_cmd_status_to_host_reg: register address for CPU command status response * @cpu_boot_status_reg: boot status register - * @cpu_boot_dev_status_reg: boot device status register - * @boot_err0_reg: boot error register + * @cpu_boot_dev_status0_reg: boot device status register 0 + * @cpu_boot_dev_status1_reg: boot device status register 1 + * @boot_err0_reg: boot error register 0 + * @boot_err1_reg: boot error register 1 * @preboot_version_offset_reg: SRAM offset to preboot version register * @boot_fit_version_offset_reg: SRAM offset to boot fit version register * @sram_offset_mask: mask for getting offset into the SRAM @@ -865,8 +882,10 @@ struct static_fw_load_mgr { u32 kmd_msg_to_cpu_reg; u32 cpu_cmd_status_to_host_reg; u32 cpu_boot_status_reg; - u32 cpu_boot_dev_status_reg; + u32 cpu_boot_dev_status0_reg; + u32 cpu_boot_dev_status1_reg; u32 boot_err0_reg; + u32 boot_err1_reg; u32 preboot_version_offset_reg; u32 boot_fit_version_offset_reg; u32 sram_offset_mask; @@ -2514,11 +2533,13 @@ void hl_fw_cpu_accessible_dma_pool_free(struct hl_device *hdev, size_t size, void *vaddr); int hl_fw_send_heartbeat(struct hl_device *hdev); int hl_fw_cpucp_info_get(struct hl_device *hdev, - u32 cpu_security_boot_status_reg, - u32 boot_err0_reg); + u32 sts_boot_dev_sts0_reg, + u32 sts_boot_dev_sts1_reg, u32 boot_err0_reg, + u32 boot_err1_reg); int hl_fw_cpucp_handshake(struct hl_device *hdev, - u32 cpu_security_boot_status_reg, - u32 boot_err0_reg); + u32 sts_boot_dev_sts0_reg, + u32 sts_boot_dev_sts1_reg, u32 boot_err0_reg, + u32 boot_err1_reg); int hl_fw_get_eeprom_data(struct hl_device *hdev, void *data, size_t max_size); int hl_fw_cpucp_pci_counters_get(struct hl_device *hdev, struct hl_info_pci_counters *counters); @@ -2531,8 +2552,9 @@ int hl_fw_cpucp_pll_info_get(struct hl_device *hdev, u32 pll_index, int hl_fw_cpucp_power_get(struct hl_device *hdev, u64 *power); int hl_fw_init_cpu(struct hl_device *hdev); int hl_fw_read_preboot_status(struct hl_device *hdev, u32 cpu_boot_status_reg, - u32 cpu_boot_caps_reg, u32 boot_err0_reg, - u32 timeout); + u32 sts_boot_dev_sts0_reg, + u32 sts_boot_dev_sts1_reg, u32 boot_err0_reg, + u32 boot_err1_reg, u32 timeout); int hl_pci_bars_map(struct hl_device *hdev, const char * const name[3], bool is_wc[3]); diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index b41c3bc9746d..26c653375450 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -546,7 +546,8 @@ static int gaudi_get_fixed_properties(struct hl_device *hdev) for (i = 0 ; i < HL_MAX_DCORES ; i++) prop->first_available_cq[i] = USHRT_MAX; - prop->fw_security_status_valid = false; + prop->fw_cpu_boot_dev_sts0_valid = false; + prop->fw_cpu_boot_dev_sts1_valid = false; prop->hard_reset_done_by_fw = false; return 0; @@ -706,8 +707,10 @@ pci_init: * version to determine whether we run with a security-enabled firmware */ rc = hl_fw_read_preboot_status(hdev, mmPSOC_GLOBAL_CONF_CPU_BOOT_STATUS, - mmCPU_BOOT_DEV_STS0, mmCPU_BOOT_ERR0, - GAUDI_BOOT_FIT_REQ_TIMEOUT_USEC); + mmCPU_BOOT_DEV_STS0, + mmCPU_BOOT_DEV_STS1, mmCPU_BOOT_ERR0, + mmCPU_BOOT_ERR1, + GAUDI_BOOT_FIT_REQ_TIMEOUT_USEC); if (rc) { if (hdev->reset_on_preboot_fail) hdev->asic_funcs->hw_fini(hdev, true); @@ -1925,8 +1928,8 @@ static void gaudi_init_scrambler_sram(struct hl_device *hdev) if (!hdev->asic_prop.fw_security_disabled) return; - if (hdev->asic_prop.fw_security_status_valid && - (hdev->asic_prop.fw_app_security_map & + if (hdev->asic_prop.fw_cpu_boot_dev_sts0_valid && + (hdev->asic_prop.fw_app_cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_SRAM_SCR_EN)) return; @@ -1997,8 +2000,8 @@ static void gaudi_init_scrambler_hbm(struct hl_device *hdev) if (!hdev->asic_prop.fw_security_disabled) return; - if (hdev->asic_prop.fw_security_status_valid && - (hdev->asic_prop.fw_boot_cpu_security_map & + if (hdev->asic_prop.fw_cpu_boot_dev_sts0_valid && + (hdev->asic_prop.fw_bootfit_cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_DRAM_SCR_EN)) return; @@ -2067,8 +2070,8 @@ static void gaudi_init_e2e(struct hl_device *hdev) if (!hdev->asic_prop.fw_security_disabled) return; - if (hdev->asic_prop.fw_security_status_valid && - (hdev->asic_prop.fw_boot_cpu_security_map & + if (hdev->asic_prop.fw_cpu_boot_dev_sts0_valid && + (hdev->asic_prop.fw_bootfit_cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_E2E_CRED_EN)) return; @@ -2442,8 +2445,8 @@ static void gaudi_init_hbm_cred(struct hl_device *hdev) if (!hdev->asic_prop.fw_security_disabled) return; - if (hdev->asic_prop.fw_security_status_valid && - (hdev->asic_prop.fw_boot_cpu_security_map & + if (hdev->asic_prop.fw_cpu_boot_dev_sts0_valid && + (hdev->asic_prop.fw_bootfit_cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_HBM_CRED_EN)) return; @@ -3768,8 +3771,10 @@ static void gaudi_init_static_firmware_loader(struct hl_device *hdev) static_loader->kmd_msg_to_cpu_reg = mmPSOC_GLOBAL_CONF_KMD_MSG_TO_CPU; static_loader->cpu_cmd_status_to_host_reg = mmCPU_CMD_STATUS_TO_HOST; static_loader->cpu_boot_status_reg = mmPSOC_GLOBAL_CONF_CPU_BOOT_STATUS; - static_loader->cpu_boot_dev_status_reg = mmCPU_BOOT_DEV_STS0; + static_loader->cpu_boot_dev_status0_reg = mmCPU_BOOT_DEV_STS0; + static_loader->cpu_boot_dev_status1_reg = mmCPU_BOOT_DEV_STS1; static_loader->boot_err0_reg = mmCPU_BOOT_ERR0; + static_loader->boot_err1_reg = mmCPU_BOOT_ERR1; static_loader->preboot_version_offset_reg = mmPREBOOT_VER_OFFSET; static_loader->boot_fit_version_offset_reg = mmUBOOT_VER_OFFSET; static_loader->sram_offset_mask = ~((u32)SRAM_BASE_ADDR); @@ -3884,8 +3889,10 @@ static int gaudi_init_cpu_queues(struct hl_device *hdev, u32 cpu_timeout) } /* update FW application security bits */ - if (prop->fw_security_status_valid) - prop->fw_app_security_map = RREG32(mmCPU_BOOT_DEV_STS0); + if (prop->fw_cpu_boot_dev_sts0_valid) + prop->fw_app_cpu_boot_dev_sts0 = RREG32(mmCPU_BOOT_DEV_STS0); + if (prop->fw_cpu_boot_dev_sts1_valid) + prop->fw_app_cpu_boot_dev_sts1 = RREG32(mmCPU_BOOT_DEV_STS1); gaudi->hw_cap_initialized |= HW_CAP_CPU_Q; return 0; @@ -7409,8 +7416,8 @@ static int gaudi_hbm_read_interrupts(struct hl_device *hdev, int device, u32 base, val, val2, wr_par, rd_par, ca_par, derr, serr, type, ch; int err = 0; - if (hdev->asic_prop.fw_security_status_valid && - (hdev->asic_prop.fw_app_security_map & + if (hdev->asic_prop.fw_cpu_boot_dev_sts0_valid && + (hdev->asic_prop.fw_app_cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_HBM_ECC_EN)) { if (!hbm_ecc_data) { dev_err(hdev->dev, "No FW ECC data"); @@ -7975,7 +7982,9 @@ static int gaudi_cpucp_info_get(struct hl_device *hdev) if (!(gaudi->hw_cap_initialized & HW_CAP_CPU_Q)) return 0; - rc = hl_fw_cpucp_handshake(hdev, mmCPU_BOOT_DEV_STS0, mmCPU_BOOT_ERR0); + rc = hl_fw_cpucp_handshake(hdev, mmCPU_BOOT_DEV_STS0, + mmCPU_BOOT_DEV_STS1, mmCPU_BOOT_ERR0, + mmCPU_BOOT_ERR1); if (rc) return rc; diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c index 3b995e354c50..f1bd8e826304 100644 --- a/drivers/misc/habanalabs/goya/goya.c +++ b/drivers/misc/habanalabs/goya/goya.c @@ -461,7 +461,8 @@ int goya_get_fixed_properties(struct hl_device *hdev) for (i = 0 ; i < HL_MAX_DCORES ; i++) prop->first_available_cq[i] = USHRT_MAX; - prop->fw_security_status_valid = false; + prop->fw_cpu_boot_dev_sts0_valid = false; + prop->fw_cpu_boot_dev_sts1_valid = false; prop->hard_reset_done_by_fw = false; return 0; @@ -641,8 +642,10 @@ pci_init: * version to determine whether we run with a security-enabled firmware */ rc = hl_fw_read_preboot_status(hdev, mmPSOC_GLOBAL_CONF_CPU_BOOT_STATUS, - mmCPU_BOOT_DEV_STS0, mmCPU_BOOT_ERR0, - GOYA_BOOT_FIT_REQ_TIMEOUT_USEC); + mmCPU_BOOT_DEV_STS0, + mmCPU_BOOT_DEV_STS1, mmCPU_BOOT_ERR0, + mmCPU_BOOT_ERR1, + GOYA_BOOT_FIT_REQ_TIMEOUT_USEC); if (rc) { if (hdev->reset_on_preboot_fail) hdev->asic_funcs->hw_fini(hdev, true); @@ -1297,8 +1300,11 @@ int goya_init_cpu_queues(struct hl_device *hdev) } /* update FW application security bits */ - if (prop->fw_security_status_valid) - prop->fw_app_security_map = RREG32(mmCPU_BOOT_DEV_STS0); + if (prop->fw_cpu_boot_dev_sts0_valid) + prop->fw_app_cpu_boot_dev_sts0 = RREG32(mmCPU_BOOT_DEV_STS0); + + if (prop->fw_cpu_boot_dev_sts1_valid) + prop->fw_app_cpu_boot_dev_sts1 = RREG32(mmCPU_BOOT_DEV_STS1); goya->hw_cap_initialized |= HW_CAP_CPU_Q; return 0; @@ -2470,8 +2476,10 @@ static void goya_init_static_firmware_loader(struct hl_device *hdev) static_loader->kmd_msg_to_cpu_reg = mmPSOC_GLOBAL_CONF_KMD_MSG_TO_CPU; static_loader->cpu_cmd_status_to_host_reg = mmCPU_CMD_STATUS_TO_HOST; static_loader->cpu_boot_status_reg = mmPSOC_GLOBAL_CONF_CPU_BOOT_STATUS; - static_loader->cpu_boot_dev_status_reg = mmCPU_BOOT_DEV_STS0; + static_loader->cpu_boot_dev_status0_reg = mmCPU_BOOT_DEV_STS0; + static_loader->cpu_boot_dev_status1_reg = mmCPU_BOOT_DEV_STS1; static_loader->boot_err0_reg = mmCPU_BOOT_ERR0; + static_loader->boot_err1_reg = mmCPU_BOOT_ERR1; static_loader->preboot_version_offset_reg = mmPREBOOT_VER_OFFSET; static_loader->boot_fit_version_offset_reg = mmUBOOT_VER_OFFSET; static_loader->sram_offset_mask = ~((u32)SRAM_BASE_ADDR); @@ -5245,7 +5253,9 @@ int goya_cpucp_info_get(struct hl_device *hdev) if (!(goya->hw_cap_initialized & HW_CAP_CPU_Q)) return 0; - rc = hl_fw_cpucp_handshake(hdev, mmCPU_BOOT_DEV_STS0, mmCPU_BOOT_ERR0); + rc = hl_fw_cpucp_handshake(hdev, mmCPU_BOOT_DEV_STS0, + mmCPU_BOOT_DEV_STS1, mmCPU_BOOT_ERR0, + mmCPU_BOOT_ERR1); if (rc) return rc; -- cgit v1.2.3 From 8121736bbf3d5cbd3dcae1e8a40c31fff5713427 Mon Sep 17 00:00:00 2001 From: Koby Elbaz Date: Mon, 3 May 2021 23:03:15 +0300 Subject: habanalabs/gaudi: use scratchpad regs instead of GIC controller Due to new security restrictions, GIC controller can no longer be accessed from user/kernel. To monitor that, a new status bit will be read from preboot caps, indicating whether direct access to GIC is blocked. In case it is blocked, driver will use scratchpad registers instead of using GIC interface on two main scenarios: The first of which LKD triggers interrupts to F/W through GIC, and the second of when LKD configures all engines/QMANs to write to GIC when they want to report an error. From F/W perspective, it will poll on all SPs, and once IRQ number is retrieved, SP register is cleared, and it will perform the write to the GIC to trigger the IRQ handler. Signed-off-by: Koby Elbaz Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 7 ++ drivers/misc/habanalabs/common/habanalabs.h | 3 + drivers/misc/habanalabs/gaudi/gaudi.c | 116 ++++++++++++++------- drivers/misc/habanalabs/goya/goya.c | 1 + .../misc/habanalabs/include/common/hl_boot_if.h | 7 ++ .../misc/habanalabs/include/gaudi/gaudi_reg_map.h | 6 ++ 6 files changed, 104 insertions(+), 36 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index 3cf177e2ac1e..3969351b5513 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -1075,6 +1075,7 @@ static void hl_fw_preboot_update_state(struct hl_device *hdev) * Preboot: * Check security status bit (CPU_BOOT_DEV_STS0_ENABLED), if it is set * check security enabled bit (CPU_BOOT_DEV_STS0_SECURITY_EN) + * Check GIC privileged bit (CPU_BOOT_DEV_STS0_GIC_PRIVILEGED_EN) */ if (cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_ENABLED) { prop->fw_cpu_boot_dev_sts0_valid = 1; @@ -1087,6 +1088,9 @@ static void hl_fw_preboot_update_state(struct hl_device *hdev) if (cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_FW_HARD_RST_EN) prop->hard_reset_done_by_fw = true; + + if (cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_GIC_PRIVILEGED_EN) + prop->gic_interrupts_enable = false; } else { prop->fw_cpu_boot_dev_sts0_valid = 0; } @@ -1106,6 +1110,9 @@ static void hl_fw_preboot_update_state(struct hl_device *hdev) dev_info(hdev->dev, "firmware-level security is %s\n", prop->fw_security_disabled ? "disabled" : "enabled"); + + dev_info(hdev->dev, "GIC controller is %s\n", + prop->gic_interrupts_enable ? "enabled" : "disabled"); } static int hl_fw_static_read_preboot_status(struct hl_device *hdev) diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index afa3175ddfb7..7e13a198a946 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -463,6 +463,8 @@ struct hl_mmu_properties { * @num_functional_hbms: number of functional HBMs in each DCORE. * @iatu_done_by_fw: true if iATU configuration is being done by FW. * @dynamic_fw_load: is dynamic FW load is supported. + * @gic_interrupts_enable: true if FW is not blocking GIC controller, + * false otherwise. */ struct asic_fixed_properties { struct hw_queue_properties *hw_queues_props; @@ -533,6 +535,7 @@ struct asic_fixed_properties { u8 num_functional_hbms; u8 iatu_done_by_fw; u8 dynamic_fw_load; + u8 gic_interrupts_enable; }; /** diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 26c653375450..9e4bb9d01def 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -549,6 +549,7 @@ static int gaudi_get_fixed_properties(struct hl_device *hdev) prop->fw_cpu_boot_dev_sts0_valid = false; prop->fw_cpu_boot_dev_sts1_valid = false; prop->hard_reset_done_by_fw = false; + prop->gic_interrupts_enable = true; return 0; } @@ -2536,7 +2537,7 @@ static void gaudi_init_pci_dma_qman(struct hl_device *hdev, int dma_id, u32 mtr_base_en_lo, mtr_base_en_hi, mtr_base_ws_lo, mtr_base_ws_hi; u32 so_base_en_lo, so_base_en_hi, so_base_ws_lo, so_base_ws_hi; u32 q_off, dma_qm_offset; - u32 dma_qm_err_cfg; + u32 dma_qm_err_cfg, irq_handler_offset; dma_qm_offset = dma_id * DMA_QMAN_OFFSET; @@ -2585,6 +2586,10 @@ static void gaudi_init_pci_dma_qman(struct hl_device *hdev, int dma_id, /* The following configuration is needed only once per QMAN */ if (qman_id == 0) { + irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ? + mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR : + mmGIC_DMA_QM_IRQ_CTRL_POLL_REG; + /* Configure RAZWI IRQ */ dma_qm_err_cfg = PCI_DMA_QMAN_GLBL_ERR_CFG_MSG_EN_MASK; if (hdev->stop_on_err) { @@ -2593,12 +2598,12 @@ static void gaudi_init_pci_dma_qman(struct hl_device *hdev, int dma_id, } WREG32(mmDMA0_QM_GLBL_ERR_CFG + dma_qm_offset, dma_qm_err_cfg); + WREG32(mmDMA0_QM_GLBL_ERR_ADDR_LO + dma_qm_offset, - lower_32_bits(CFG_BASE + - mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR)); + lower_32_bits(CFG_BASE + irq_handler_offset)); WREG32(mmDMA0_QM_GLBL_ERR_ADDR_HI + dma_qm_offset, - upper_32_bits(CFG_BASE + - mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR)); + upper_32_bits(CFG_BASE + irq_handler_offset)); + WREG32(mmDMA0_QM_GLBL_ERR_WDATA + dma_qm_offset, gaudi_irq_map_table[GAUDI_EVENT_DMA0_QM].cpu_id + dma_id); @@ -2619,8 +2624,9 @@ static void gaudi_init_pci_dma_qman(struct hl_device *hdev, int dma_id, static void gaudi_init_dma_core(struct hl_device *hdev, int dma_id) { - u32 dma_offset = dma_id * DMA_CORE_OFFSET; u32 dma_err_cfg = 1 << DMA0_CORE_ERR_CFG_ERR_MSG_EN_SHIFT; + u32 dma_offset = dma_id * DMA_CORE_OFFSET; + u32 irq_handler_offset; /* Set to maximum possible according to physical size */ WREG32(mmDMA0_CORE_RD_MAX_OUTSTAND + dma_offset, 0); @@ -2634,10 +2640,16 @@ static void gaudi_init_dma_core(struct hl_device *hdev, int dma_id) dma_err_cfg |= 1 << DMA0_CORE_ERR_CFG_STOP_ON_ERR_SHIFT; WREG32(mmDMA0_CORE_ERR_CFG + dma_offset, dma_err_cfg); + + irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ? + mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR : + mmGIC_DMA_CR_IRQ_CTRL_POLL_REG; + WREG32(mmDMA0_CORE_ERRMSG_ADDR_LO + dma_offset, - lower_32_bits(CFG_BASE + mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR)); + lower_32_bits(CFG_BASE + irq_handler_offset)); WREG32(mmDMA0_CORE_ERRMSG_ADDR_HI + dma_offset, - upper_32_bits(CFG_BASE + mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR)); + upper_32_bits(CFG_BASE + irq_handler_offset)); + WREG32(mmDMA0_CORE_ERRMSG_WDATA + dma_offset, gaudi_irq_map_table[GAUDI_EVENT_DMA0_CORE].cpu_id + dma_id); WREG32(mmDMA0_CORE_PROT + dma_offset, @@ -2702,8 +2714,8 @@ static void gaudi_init_hbm_dma_qman(struct hl_device *hdev, int dma_id, { u32 mtr_base_en_lo, mtr_base_en_hi, mtr_base_ws_lo, mtr_base_ws_hi; u32 so_base_en_lo, so_base_en_hi, so_base_ws_lo, so_base_ws_hi; + u32 dma_qm_err_cfg, irq_handler_offset; u32 q_off, dma_qm_offset; - u32 dma_qm_err_cfg; dma_qm_offset = dma_id * DMA_QMAN_OFFSET; @@ -2743,6 +2755,10 @@ static void gaudi_init_hbm_dma_qman(struct hl_device *hdev, int dma_id, WREG32(mmDMA0_QM_CP_LDMA_DST_BASE_LO_OFFSET_0 + q_off, QMAN_CPDMA_DST_OFFSET); } else { + irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ? + mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR : + mmGIC_DMA_QM_IRQ_CTRL_POLL_REG; + WREG32(mmDMA0_QM_CP_LDMA_TSIZE_OFFSET_0 + q_off, QMAN_LDMA_SIZE_OFFSET); WREG32(mmDMA0_QM_CP_LDMA_SRC_BASE_LO_OFFSET_0 + q_off, @@ -2759,11 +2775,10 @@ static void gaudi_init_hbm_dma_qman(struct hl_device *hdev, int dma_id, WREG32(mmDMA0_QM_GLBL_ERR_CFG + dma_qm_offset, dma_qm_err_cfg); WREG32(mmDMA0_QM_GLBL_ERR_ADDR_LO + dma_qm_offset, - lower_32_bits(CFG_BASE + - mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR)); + lower_32_bits(CFG_BASE + irq_handler_offset)); WREG32(mmDMA0_QM_GLBL_ERR_ADDR_HI + dma_qm_offset, - upper_32_bits(CFG_BASE + - mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR)); + upper_32_bits(CFG_BASE + irq_handler_offset)); + WREG32(mmDMA0_QM_GLBL_ERR_WDATA + dma_qm_offset, gaudi_irq_map_table[GAUDI_EVENT_DMA0_QM].cpu_id + dma_id); @@ -2840,6 +2855,7 @@ static void gaudi_init_mme_qman(struct hl_device *hdev, u32 mme_offset, { u32 mtr_base_lo, mtr_base_hi; u32 so_base_lo, so_base_hi; + u32 irq_handler_offset; u32 q_off, mme_id; u32 mme_qm_err_cfg; @@ -2871,6 +2887,10 @@ static void gaudi_init_mme_qman(struct hl_device *hdev, u32 mme_offset, WREG32(mmMME0_QM_CP_LDMA_DST_BASE_LO_OFFSET_0 + q_off, QMAN_CPDMA_DST_OFFSET); } else { + irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ? + mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR : + mmGIC_MME_QM_IRQ_CTRL_POLL_REG; + WREG32(mmMME0_QM_CP_LDMA_TSIZE_OFFSET_0 + q_off, QMAN_LDMA_SIZE_OFFSET); WREG32(mmMME0_QM_CP_LDMA_SRC_BASE_LO_OFFSET_0 + q_off, @@ -2888,12 +2908,12 @@ static void gaudi_init_mme_qman(struct hl_device *hdev, u32 mme_offset, MME_QMAN_GLBL_ERR_CFG_STOP_ON_ERR_EN_MASK; } WREG32(mmMME0_QM_GLBL_ERR_CFG + mme_offset, mme_qm_err_cfg); + WREG32(mmMME0_QM_GLBL_ERR_ADDR_LO + mme_offset, - lower_32_bits(CFG_BASE + - mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR)); + lower_32_bits(CFG_BASE + irq_handler_offset)); WREG32(mmMME0_QM_GLBL_ERR_ADDR_HI + mme_offset, - upper_32_bits(CFG_BASE + - mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR)); + upper_32_bits(CFG_BASE + irq_handler_offset)); + WREG32(mmMME0_QM_GLBL_ERR_WDATA + mme_offset, gaudi_irq_map_table[GAUDI_EVENT_MME0_QM].cpu_id + mme_id); @@ -2960,8 +2980,8 @@ static void gaudi_init_tpc_qman(struct hl_device *hdev, u32 tpc_offset, { u32 mtr_base_en_lo, mtr_base_en_hi, mtr_base_ws_lo, mtr_base_ws_hi; u32 so_base_en_lo, so_base_en_hi, so_base_ws_lo, so_base_ws_hi; + u32 tpc_qm_err_cfg, irq_handler_offset; u32 q_off, tpc_id; - u32 tpc_qm_err_cfg; mtr_base_en_lo = lower_32_bits(CFG_BASE + mmSYNC_MNGR_E_N_SYNC_MNGR_OBJS_MON_PAY_ADDRL_0); @@ -3002,6 +3022,10 @@ static void gaudi_init_tpc_qman(struct hl_device *hdev, u32 tpc_offset, WREG32(mmTPC0_QM_CP_LDMA_DST_BASE_LO_OFFSET_0 + q_off, QMAN_CPDMA_DST_OFFSET); } else { + irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ? + mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR : + mmGIC_TPC_QM_IRQ_CTRL_POLL_REG; + WREG32(mmTPC0_QM_CP_LDMA_TSIZE_OFFSET_0 + q_off, QMAN_LDMA_SIZE_OFFSET); WREG32(mmTPC0_QM_CP_LDMA_SRC_BASE_LO_OFFSET_0 + q_off, @@ -3017,12 +3041,12 @@ static void gaudi_init_tpc_qman(struct hl_device *hdev, u32 tpc_offset, } WREG32(mmTPC0_QM_GLBL_ERR_CFG + tpc_offset, tpc_qm_err_cfg); + WREG32(mmTPC0_QM_GLBL_ERR_ADDR_LO + tpc_offset, - lower_32_bits(CFG_BASE + - mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR)); + lower_32_bits(CFG_BASE + irq_handler_offset)); WREG32(mmTPC0_QM_GLBL_ERR_ADDR_HI + tpc_offset, - upper_32_bits(CFG_BASE + - mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR)); + upper_32_bits(CFG_BASE + irq_handler_offset)); + WREG32(mmTPC0_QM_GLBL_ERR_WDATA + tpc_offset, gaudi_irq_map_table[GAUDI_EVENT_TPC0_QM].cpu_id + tpc_id); @@ -3107,8 +3131,8 @@ static void gaudi_init_nic_qman(struct hl_device *hdev, u32 nic_offset, { u32 mtr_base_en_lo, mtr_base_en_hi, mtr_base_ws_lo, mtr_base_ws_hi; u32 so_base_en_lo, so_base_en_hi, so_base_ws_lo, so_base_ws_hi; + u32 nic_qm_err_cfg, irq_handler_offset; u32 q_off; - u32 nic_qm_err_cfg; mtr_base_en_lo = lower_32_bits(CFG_BASE + mmSYNC_MNGR_E_N_SYNC_MNGR_OBJS_MON_PAY_ADDRL_0); @@ -3155,6 +3179,10 @@ static void gaudi_init_nic_qman(struct hl_device *hdev, u32 nic_offset, WREG32(mmNIC0_QM0_CP_MSG_BASE3_ADDR_HI_0 + q_off, so_base_ws_hi); if (qman_id == 0) { + irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ? + mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR : + mmGIC_NIC_QM_IRQ_CTRL_POLL_REG; + /* Configure RAZWI IRQ */ nic_qm_err_cfg = NIC_QMAN_GLBL_ERR_CFG_MSG_EN_MASK; if (hdev->stop_on_err) { @@ -3163,12 +3191,12 @@ static void gaudi_init_nic_qman(struct hl_device *hdev, u32 nic_offset, } WREG32(mmNIC0_QM0_GLBL_ERR_CFG + nic_offset, nic_qm_err_cfg); + WREG32(mmNIC0_QM0_GLBL_ERR_ADDR_LO + nic_offset, - lower_32_bits(CFG_BASE + - mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR)); + lower_32_bits(CFG_BASE + irq_handler_offset)); WREG32(mmNIC0_QM0_GLBL_ERR_ADDR_HI + nic_offset, - upper_32_bits(CFG_BASE + - mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR)); + upper_32_bits(CFG_BASE + irq_handler_offset)); + WREG32(mmNIC0_QM0_GLBL_ERR_WDATA + nic_offset, gaudi_irq_map_table[GAUDI_EVENT_NIC0_QM0].cpu_id + nic_id); @@ -3830,10 +3858,10 @@ static int gaudi_init_cpu(struct hl_device *hdev) static int gaudi_init_cpu_queues(struct hl_device *hdev, u32 cpu_timeout) { - struct gaudi_device *gaudi = hdev->asic_specific; struct asic_fixed_properties *prop = &hdev->asic_prop; + struct gaudi_device *gaudi = hdev->asic_specific; + u32 status, irq_handler_offset; struct hl_eq *eq; - u32 status; struct hl_hw_queue *cpu_pq = &hdev->kernel_queues[GAUDI_QUEUE_ID_CPU_PQ]; int err; @@ -3872,7 +3900,11 @@ static int gaudi_init_cpu_queues(struct hl_device *hdev, u32 cpu_timeout) WREG32(mmCPU_IF_QUEUE_INIT, PQ_INIT_STATUS_READY_FOR_CP_SINGLE_MSI); - WREG32(mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR, GAUDI_EVENT_PI_UPDATE); + irq_handler_offset = prop->gic_interrupts_enable ? + mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR : + mmGIC_HOST_IRQ_CTRL_POLL_REG; + + WREG32(irq_handler_offset, GAUDI_EVENT_PI_UPDATE); err = hl_poll_timeout( hdev, @@ -4003,7 +4035,7 @@ disable_queues: static void gaudi_hw_fini(struct hl_device *hdev, bool hard_reset) { struct gaudi_device *gaudi = hdev->asic_specific; - u32 status, reset_timeout_ms, cpu_timeout_ms; + u32 status, reset_timeout_ms, cpu_timeout_ms, irq_handler_offset; if (!hard_reset) { dev_err(hdev->dev, "GAUDI doesn't support soft-reset\n"); @@ -4034,7 +4066,11 @@ static void gaudi_hw_fini(struct hl_device *hdev, bool hard_reset) else WREG32(mmPSOC_GLOBAL_CONF_KMD_MSG_TO_CPU, KMD_MSG_GOTO_WFE); - WREG32(mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR, GAUDI_EVENT_HALT_MACHINE); + irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ? + mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR : + mmGIC_HOST_IRQ_CTRL_POLL_REG; + + WREG32(irq_handler_offset, GAUDI_EVENT_HALT_MACHINE); if (hdev->asic_prop.fw_security_disabled && !hdev->asic_prop.hard_reset_done_by_fw) { @@ -4146,8 +4182,8 @@ static int gaudi_cb_mmap(struct hl_device *hdev, struct vm_area_struct *vma, static void gaudi_ring_doorbell(struct hl_device *hdev, u32 hw_queue_id, u32 pi) { + u32 db_reg_offset, db_value, dma_qm_offset, q_off, irq_handler_offset; struct gaudi_device *gaudi = hdev->asic_specific; - u32 db_reg_offset, db_value, dma_qm_offset, q_off; int dma_id; bool invalid_queue = false; @@ -4554,8 +4590,12 @@ static void gaudi_ring_doorbell(struct hl_device *hdev, u32 hw_queue_id, u32 pi) if (hw_queue_id == GAUDI_QUEUE_ID_CPU_PQ) { /* make sure device CPU will read latest data from host */ mb(); - WREG32(mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR, - GAUDI_EVENT_PI_UPDATE); + + irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ? + mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR : + mmGIC_HOST_IRQ_CTRL_POLL_REG; + + WREG32(irq_handler_offset, GAUDI_EVENT_PI_UPDATE); } } @@ -8777,7 +8817,11 @@ static int gaudi_block_mmap(struct hl_device *hdev, static void gaudi_enable_events_from_fw(struct hl_device *hdev) { - WREG32(mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR, GAUDI_EVENT_INTS_REGISTER); + u32 irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ? + mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR : + mmGIC_HOST_IRQ_CTRL_POLL_REG; + + WREG32(irq_handler_offset, GAUDI_EVENT_INTS_REGISTER); } static int gaudi_map_pll_idx_to_fw_idx(u32 pll_idx) diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c index f1bd8e826304..3d7a760cf2ba 100644 --- a/drivers/misc/habanalabs/goya/goya.c +++ b/drivers/misc/habanalabs/goya/goya.c @@ -464,6 +464,7 @@ int goya_get_fixed_properties(struct hl_device *hdev) prop->fw_cpu_boot_dev_sts0_valid = false; prop->fw_cpu_boot_dev_sts1_valid = false; prop->hard_reset_done_by_fw = false; + prop->gic_interrupts_enable = true; return 0; } diff --git a/drivers/misc/habanalabs/include/common/hl_boot_if.h b/drivers/misc/habanalabs/include/common/hl_boot_if.h index 0fd749c92fc2..9baa56acf473 100644 --- a/drivers/misc/habanalabs/include/common/hl_boot_if.h +++ b/drivers/misc/habanalabs/include/common/hl_boot_if.h @@ -191,6 +191,12 @@ * PLLs. * Initialized in: linux * + * CPU_BOOT_DEV_STS0_GIC_PRIVILEGED_EN GIC access permission only from + * previleged entity. FW sets this status + * bit for host. If this bit is set then + * GIC can not be accessed from host. + * Initialized in: preboot + * * CPU_BOOT_DEV_STS0_ENABLED Device status register enabled. * This is a main indication that the * running FW populates the device status @@ -219,6 +225,7 @@ #define CPU_BOOT_DEV_STS0_FW_LD_COM_EN (1 << 16) #define CPU_BOOT_DEV_STS0_FW_IATU_CONF_EN (1 << 17) #define CPU_BOOT_DEV_STS0_DYN_PLL_EN (1 << 19) +#define CPU_BOOT_DEV_STS0_GIC_PRIVILEGED_EN (1 << 20) #define CPU_BOOT_DEV_STS0_ENABLED (1 << 31) #define CPU_BOOT_DEV_STS1_ENABLED (1 << 31) diff --git a/drivers/misc/habanalabs/include/gaudi/gaudi_reg_map.h b/drivers/misc/habanalabs/include/gaudi/gaudi_reg_map.h index 137afedf5f15..cd69d3407631 100644 --- a/drivers/misc/habanalabs/include/gaudi/gaudi_reg_map.h +++ b/drivers/misc/habanalabs/include/gaudi/gaudi_reg_map.h @@ -12,6 +12,12 @@ * PSOC scratch-pad registers */ #define mmHW_STATE mmPSOC_GLOBAL_CONF_SCRATCHPAD_0 +#define mmGIC_HOST_IRQ_CTRL_POLL_REG mmPSOC_GLOBAL_CONF_SCRATCHPAD_1 +#define mmGIC_TPC_QM_IRQ_CTRL_POLL_REG mmPSOC_GLOBAL_CONF_SCRATCHPAD_2 +#define mmGIC_MME_QM_IRQ_CTRL_POLL_REG mmPSOC_GLOBAL_CONF_SCRATCHPAD_3 +#define mmGIC_DMA_QM_IRQ_CTRL_POLL_REG mmPSOC_GLOBAL_CONF_SCRATCHPAD_4 +#define mmGIC_NIC_QM_IRQ_CTRL_POLL_REG mmPSOC_GLOBAL_CONF_SCRATCHPAD_5 +#define mmGIC_DMA_CR_IRQ_CTRL_POLL_REG mmPSOC_GLOBAL_CONF_SCRATCHPAD_6 #define mmCPU_BOOT_DEV_STS0 mmPSOC_GLOBAL_CONF_SCRATCHPAD_20 #define mmCPU_BOOT_DEV_STS1 mmPSOC_GLOBAL_CONF_SCRATCHPAD_21 #define mmFUSE_VER_OFFSET mmPSOC_GLOBAL_CONF_SCRATCHPAD_22 -- cgit v1.2.3 From a782422b20f4b3433099b0e1e4d6a9e5f1a87f5f Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Sun, 9 May 2021 09:49:36 +0300 Subject: habanalabs: notify before f/w loading An information print notifying on starting to load the f/w was removed by mistake when moving to the new dynamic f/w loading mechanism. Restore that print as the F/W loading usually takes between 10 to 20 seconds and this print helps the user know the status of the driver load. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index 3969351b5513..8922d4a43919 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -1951,6 +1951,9 @@ static int hl_fw_dynamic_init_cpu(struct hl_device *hdev, struct cpu_dyn_regs *dyn_regs; int rc; + dev_info(hdev->dev, + "Loading firmware to device, may take some time...\n"); + dyn_regs = &fw_loader->dynamic_loader.comm_desc.cpu_dyn_regs; rc = hl_fw_dynamic_send_protocol_cmd(hdev, fw_loader, COMMS_RST_STATE, -- cgit v1.2.3 From 3e0ca9fab10bc06111e9c13c9c7d29ed3fcab351 Mon Sep 17 00:00:00 2001 From: Koby Elbaz Date: Tue, 4 May 2021 20:10:47 +0300 Subject: habanalabs/gaudi: send hard reset cause to preboot LKD should provide hard reset cause to preboot prior to loading any FW components (in case needed). Current implementation is based on the new FW 'COMMS' protocol In cased 'COMMS' is disabled - reset cause won't be sent. Currently, only 2 reset causes are shared: HEARTBEAT & TDR. Sending the reset cause will provide the missing watchdog info that the firmware needs to provide to the BMC. Signed-off-by: Koby Elbaz Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- .../misc/habanalabs/common/command_submission.c | 2 +- drivers/misc/habanalabs/common/device.c | 18 ++- drivers/misc/habanalabs/common/firmware_if.c | 127 ++++++++++++++++++++- drivers/misc/habanalabs/common/habanalabs.h | 7 ++ drivers/misc/habanalabs/common/habanalabs_drv.c | 2 + .../misc/habanalabs/include/common/hl_boot_if.h | 60 +++++++++- 6 files changed, 208 insertions(+), 8 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/command_submission.c b/drivers/misc/habanalabs/common/command_submission.c index af3c497defb1..ecd96fbe3150 100644 --- a/drivers/misc/habanalabs/common/command_submission.c +++ b/drivers/misc/habanalabs/common/command_submission.c @@ -614,7 +614,7 @@ static void cs_timedout(struct work_struct *work) cs_put(cs); if (hdev->reset_on_lockup) - hl_device_reset(hdev, 0); + hl_device_reset(hdev, HL_RESET_TDR); else hdev->needs_reset = true; } diff --git a/drivers/misc/habanalabs/common/device.c b/drivers/misc/habanalabs/common/device.c index 00e92b678828..bc58a91bf50a 100644 --- a/drivers/misc/habanalabs/common/device.c +++ b/drivers/misc/habanalabs/common/device.c @@ -900,6 +900,19 @@ int hl_device_reset(struct hl_device *hdev, u32 flags) if (rc) return 0; + /* + * 'reset cause' is being updated here, because getting here + * means that it's the 1st time and the last time we're here + * ('in_reset' makes sure of it). This makes sure that + * 'reset_cause' will continue holding its 1st recorded reason! + */ + if (flags & HL_RESET_HEARTBEAT) + hdev->curr_reset_cause = HL_RESET_CAUSE_HEARTBEAT; + else if (flags & HL_RESET_TDR) + hdev->curr_reset_cause = HL_RESET_CAUSE_TDR; + else + hdev->curr_reset_cause = HL_RESET_CAUSE_UNKNOWN; + /* * if reset is due to heartbeat, device CPU is no responsive in * which case no point sending PCI disable message to it @@ -943,9 +956,8 @@ again: hdev->process_kill_trial_cnt = 0; /* - * Because the reset function can't run from interrupt or - * from heartbeat work, we need to call the reset function - * from a dedicated work + * Because the reset function can't run from heartbeat work, + * we need to call the reset function from a dedicated work. */ queue_delayed_work(hdev->device_reset_work.wq, &hdev->device_reset_work.reset_work, 0); diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index 8922d4a43919..2d5a849a377e 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -103,6 +103,41 @@ static int hl_fw_copy_fw_to_device(struct hl_device *hdev, return 0; } +/** + * hl_fw_copy_msg_to_device() - copy message to device + * + * @hdev: pointer to hl_device structure. + * @msg: message + * @dst: IO memory mapped address space to copy firmware to + * @src_offset: offset in src message to copy from + * @size: amount of bytes to copy (0 to copy the whole binary) + * + * actual copy of message data to device. + */ +static int hl_fw_copy_msg_to_device(struct hl_device *hdev, + struct lkd_msg_comms *msg, void __iomem *dst, + u32 src_offset, u32 size) +{ + void *msg_data; + + /* size 0 indicates to copy the whole file */ + if (!size) + size = sizeof(struct lkd_msg_comms); + + if (src_offset + size > sizeof(struct lkd_msg_comms)) { + dev_err(hdev->dev, + "size to copy(%u) and offset(%u) are invalid\n", + size, src_offset); + return -EINVAL; + } + + msg_data = (void *) msg; + + memcpy_toio(dst, msg_data + src_offset, size); + + return 0; +} + /** * hl_fw_load_fw_to_device() - Load F/W code to device's memory. * @@ -1698,6 +1733,36 @@ static int hl_fw_dynamic_copy_image(struct hl_device *hdev, return rc; } +/** + * hl_fw_dynamic_copy_msg - copy msg to memory allocated by the FW + * + * @hdev: pointer to the habanalabs device structure + * @msg: message + * @fw_loader: managing structure for loading device's FW + */ +static int hl_fw_dynamic_copy_msg(struct hl_device *hdev, + struct lkd_msg_comms *msg, struct fw_load_mgr *fw_loader) +{ + struct lkd_fw_comms_desc *fw_desc; + struct pci_mem_region *region; + void __iomem *dest; + u64 addr; + int rc; + + fw_desc = &fw_loader->dynamic_loader.comm_desc; + addr = le64_to_cpu(fw_desc->img_addr); + + /* find memory region to which to copy the image */ + region = fw_loader->dynamic_loader.image_region; + + dest = hdev->pcie_bar[region->bar_id] + region->offset_in_bar + + (addr - region->region_base); + + rc = hl_fw_copy_msg_to_device(hdev, msg, dest, 0, 0); + + return rc; +} + /** * hl_fw_boot_fit_update_state - update internal data structures after boot-fit * is loaded @@ -1771,7 +1836,6 @@ static int hl_fw_dynamic_load_image(struct hl_device *hdev, } else { cur_fwc = FW_COMP_BOOT_FIT; fw_name = fw_loader->linux_img.image_name; - } /* request FW in order to communicate to FW the size to be allocated */ @@ -1927,6 +1991,57 @@ static void hl_fw_linux_update_state(struct hl_device *hdev, dev_info(hdev->dev, "Successfully loaded firmware to device\n"); } +/** + * hl_fw_dynamic_report_reset_cause - send a COMMS message with the cause + * of the newly triggered hard reset + * + * @hdev: pointer to the habanalabs device structure + * @fw_loader: managing structure for loading device's FW + * @reset_cause: enumerated cause for the recent hard reset + * + * @return 0 on success, otherwise non-zero error code + */ +static int hl_fw_dynamic_report_reset_cause(struct hl_device *hdev, + struct fw_load_mgr *fw_loader, + enum comms_reset_cause reset_cause) +{ + struct lkd_msg_comms msg; + int rc; + + memset(&msg, 0, sizeof(msg)); + + /* create message to be sent */ + msg.header.type = HL_COMMS_RESET_CAUSE_TYPE; + msg.header.size = cpu_to_le16(sizeof(struct comms_msg_header)); + msg.header.magic = cpu_to_le32(HL_COMMS_MSG_MAGIC); + + msg.reset_cause = reset_cause; + + rc = hl_fw_dynamic_request_descriptor(hdev, fw_loader, + sizeof(struct lkd_msg_comms)); + if (rc) + return rc; + + /* copy message to space allocated by FW */ + rc = hl_fw_dynamic_copy_msg(hdev, &msg, fw_loader); + if (rc) + return rc; + + rc = hl_fw_dynamic_send_protocol_cmd(hdev, fw_loader, COMMS_DATA_RDY, + 0, true, + fw_loader->cpu_timeout); + if (rc) + return rc; + + rc = hl_fw_dynamic_send_protocol_cmd(hdev, fw_loader, COMMS_EXEC, + 0, true, + fw_loader->cpu_timeout); + if (rc) + return rc; + + return 0; +} + /** * hl_fw_dynamic_init_cpu - initialize the device CPU using dynamic protocol * @@ -1962,6 +2077,16 @@ static int hl_fw_dynamic_init_cpu(struct hl_device *hdev, if (rc) goto protocol_err; + if (hdev->curr_reset_cause) { + rc = hl_fw_dynamic_report_reset_cause(hdev, fw_loader, + hdev->curr_reset_cause); + if (rc) + goto protocol_err; + + /* Clear current reset cause */ + hdev->curr_reset_cause = HL_RESET_CAUSE_UNKNOWN; + } + if (!(hdev->fw_components & FW_TYPE_BOOT_CPU)) { /* update the preboot state */ hl_fw_preboot_update_state(hdev); diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index 7e13a198a946..a046180254c8 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -115,10 +115,14 @@ enum hl_mmu_page_table_location { * * - HL_RESET_HEARTBEAT * Set if reset is due to heartbeat + * + * - HL_RESET_TDR + * Set if reset is due to TDR */ #define HL_RESET_HARD (1 << 0) #define HL_RESET_FROM_RESET_THREAD (1 << 1) #define HL_RESET_HEARTBEAT (1 << 2) +#define HL_RESET_TDR (1 << 3) #define HL_MAX_SOBS_PER_MONITOR 8 @@ -2163,6 +2167,8 @@ struct hl_mmu_funcs { * @device_fini_pending: true if device_fini was called and might be * waiting for the reset thread to finish * @supports_staged_submission: true if staged submissions are supported + * @curr_reset_cause: saves an enumerated reset cause when a hard reset is + * triggered, and cleared after it is shared with preboot. */ struct hl_device { struct pci_dev *pdev; @@ -2273,6 +2279,7 @@ struct hl_device { u8 process_kill_trial_cnt; u8 device_fini_pending; u8 supports_staged_submission; + u8 curr_reset_cause; /* Parameters for bring-up */ u64 nic_ports_mask; diff --git a/drivers/misc/habanalabs/common/habanalabs_drv.c b/drivers/misc/habanalabs/common/habanalabs_drv.c index 64d1530db985..dc92401e7a3f 100644 --- a/drivers/misc/habanalabs/common/habanalabs_drv.c +++ b/drivers/misc/habanalabs/common/habanalabs_drv.c @@ -330,6 +330,8 @@ int create_hdev(struct hl_device **dev, struct pci_dev *pdev, set_driver_behavior_per_device(hdev); + hdev->curr_reset_cause = HL_RESET_CAUSE_UNKNOWN; + if (timeout_locked) hdev->timeout_jiffies = msecs_to_jiffies(timeout_locked * 1000); else diff --git a/drivers/misc/habanalabs/include/common/hl_boot_if.h b/drivers/misc/habanalabs/include/common/hl_boot_if.h index 9baa56acf473..e9d86673109c 100644 --- a/drivers/misc/habanalabs/include/common/hl_boot_if.h +++ b/drivers/misc/habanalabs/include/common/hl_boot_if.h @@ -302,19 +302,43 @@ struct cpu_dyn_regs { __le32 reserved1[32]; /* reserve for future use */ }; +/* TODO: remove the desc magic after the code is updated to use message */ /* HCDM - Habana Communications Descriptor Magic */ #define HL_COMMS_DESC_MAGIC 0x4843444D #define HL_COMMS_DESC_VER 1 +/* HCMv - Habana Communications Message + header version */ +#define HL_COMMS_MSG_MAGIC_VER(ver) (0x48434D00 | ((ver) & 0xff)) +#define HL_COMMS_MSG_MAGIC_V0 HL_COMMS_DESC_MAGIC +#define HL_COMMS_MSG_MAGIC_V1 HL_COMMS_MSG_MAGIC_VER(1) + +#define HL_COMMS_MSG_MAGIC HL_COMMS_MSG_MAGIC_V1 + +enum comms_msg_type { + HL_COMMS_DESC_TYPE = 0, + HL_COMMS_RESET_CAUSE_TYPE = 1, +}; + +/* TODO: remove this struct after the code is updated to use comms_msg_header */ /* this is the comms descriptor header - meta data */ struct comms_desc_header { __le32 magic; /* magic for validation */ __le32 crc32; /* CRC32 of the descriptor w/o header */ __le16 size; /* size of the descriptor w/o header */ - __u8 version; /* descriptor version */ + __u8 version; /* descriptor version */ __u8 reserved[5]; /* pad to 64 bit */ }; +/* this is the comms message header - meta data */ +struct comms_msg_header { + __le32 magic; /* magic for validation */ + __le32 crc32; /* CRC32 of the message w/o header */ + __le16 size; /* size of the message w/o header */ + __u8 version; /* message payload version */ + __u8 type; /* message type */ + __u8 reserved[4]; /* pad to 64 bit */ +}; + /* this is the main FW descriptor - consider ABI when changing */ struct lkd_fw_comms_desc { struct comms_desc_header header; @@ -323,7 +347,37 @@ struct lkd_fw_comms_desc { char cur_fw_ver[VERSION_MAX_LEN]; /* can be used for 1 more version w/o ABI change */ char reserved0[VERSION_MAX_LEN]; - __le64 img_addr; /* address for next FW component load */ + /* address for next FW component load */ + __le64 img_addr; +}; + +enum comms_reset_cause { + HL_RESET_CAUSE_UNKNOWN = 0, + HL_RESET_CAUSE_HEARTBEAT = 1, + HL_RESET_CAUSE_TDR = 2, +}; + +#define RESET_CAUSE_PADDING 7 + +/* this is the comms message descriptor */ +struct lkd_msg_comms { + struct comms_msg_header header; + /* union for future expantions of new messages */ + union { + struct { + struct cpu_dyn_regs cpu_dyn_regs; + char fuse_ver[VERSION_MAX_LEN]; + char cur_fw_ver[VERSION_MAX_LEN]; + /* can be used for 1 more version w/o ABI change */ + char reserved0[VERSION_MAX_LEN]; + /* address for next FW component load */ + __le64 img_addr; + }; + struct { + __u8 reset_cause; + __u8 reserved[RESET_CAUSE_PADDING]; /* 64 bit pad */ + }; + }; }; /* @@ -395,7 +449,7 @@ enum comms_cmd { struct comms_command { union { /* bit fields are only for FW use */ struct { - u32 size :25; /* 32MB max. */ + u32 size :25; /* 32MB max. */ u32 reserved :2; enum comms_cmd cmd :5; /* 32 commands */ }; -- cgit v1.2.3 From 190ec49710a9fe0d5e9e36fe1a2fa864c048484f Mon Sep 17 00:00:00 2001 From: Ohad Sharabi Date: Tue, 11 May 2021 16:02:41 +0300 Subject: habanalabs: check if asic secured with asic type Fix issue in which the input to the function is_asic_secured was device PCI_IDS number instead of the asic_type enumeration. Signed-off-by: Ohad Sharabi Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/habanalabs_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/habanalabs_drv.c b/drivers/misc/habanalabs/common/habanalabs_drv.c index dc92401e7a3f..df1e91f810cc 100644 --- a/drivers/misc/habanalabs/common/habanalabs_drv.c +++ b/drivers/misc/habanalabs/common/habanalabs_drv.c @@ -309,7 +309,7 @@ int create_hdev(struct hl_device **dev, struct pci_dev *pdev, if (pdev) hdev->asic_prop.fw_security_disabled = - !is_asic_secured(pdev->device); + !is_asic_secured(hdev->asic_type); else hdev->asic_prop.fw_security_disabled = true; -- cgit v1.2.3 From e591a49cb585ca76d4f9aad2e9635ec7e6a4fb23 Mon Sep 17 00:00:00 2001 From: Koby Elbaz Date: Wed, 12 May 2021 18:05:46 +0300 Subject: habanalabs/gaudi: read GIC sts after FW is loaded Reading of GIC privileged status will be done after F/W is loaded, because privileged GIC capability is only available with the correct ARMCP version, and after it's loaded. Such versions necessarily support COMMS, so GIC alternatives (SP regs) will be read directly from dynamic regs. As well, initiation of DMA QMANs will occur after F/W is loaded since it depends on GIC configuration. In case F/W isn't loaded there's no problem since either way there won't be any GIC IRQ handling. Signed-off-by: Koby Elbaz Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 16 +++--- drivers/misc/habanalabs/gaudi/gaudi.c | 59 +++++++++++++++------- .../misc/habanalabs/include/common/hl_boot_if.h | 10 +++- 3 files changed, 57 insertions(+), 28 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index 2d5a849a377e..b00f763bcda6 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -1123,9 +1123,6 @@ static void hl_fw_preboot_update_state(struct hl_device *hdev) if (cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_FW_HARD_RST_EN) prop->hard_reset_done_by_fw = true; - - if (cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_GIC_PRIVILEGED_EN) - prop->gic_interrupts_enable = false; } else { prop->fw_cpu_boot_dev_sts0_valid = 0; } @@ -1143,11 +1140,8 @@ static void hl_fw_preboot_update_state(struct hl_device *hdev) dev_dbg(hdev->dev, "Firmware preboot hard-reset is %s\n", prop->hard_reset_done_by_fw ? "enabled" : "disabled"); - dev_info(hdev->dev, "firmware-level security is %s\n", + dev_dbg(hdev->dev, "firmware-level security is %s\n", prop->fw_security_disabled ? "disabled" : "enabled"); - - dev_info(hdev->dev, "GIC controller is %s\n", - prop->gic_interrupts_enable ? "enabled" : "disabled"); } static int hl_fw_static_read_preboot_status(struct hl_device *hdev) @@ -1971,9 +1965,17 @@ static void hl_fw_linux_update_state(struct hl_device *hdev, CPU_BOOT_DEV_STS0_FW_HARD_RST_EN) prop->hard_reset_done_by_fw = true; + if (prop->fw_app_cpu_boot_dev_sts0 & + CPU_BOOT_DEV_STS0_GIC_PRIVILEGED_EN) + prop->gic_interrupts_enable = false; + dev_dbg(hdev->dev, "Firmware application CPU status0 %#x\n", prop->fw_app_cpu_boot_dev_sts0); + + dev_dbg(hdev->dev, "GIC controller is %s\n", + prop->gic_interrupts_enable ? + "enabled" : "disabled"); } if (prop->fw_cpu_boot_dev_sts1_valid) { diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 9e4bb9d01def..6bd9167fc7f1 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -2534,6 +2534,8 @@ static void gaudi_init_golden_registers(struct hl_device *hdev) static void gaudi_init_pci_dma_qman(struct hl_device *hdev, int dma_id, int qman_id, dma_addr_t qman_pq_addr) { + struct cpu_dyn_regs *dyn_regs = + &hdev->fw_loader.dynamic_loader.comm_desc.cpu_dyn_regs; u32 mtr_base_en_lo, mtr_base_en_hi, mtr_base_ws_lo, mtr_base_ws_hi; u32 so_base_en_lo, so_base_en_hi, so_base_ws_lo, so_base_ws_hi; u32 q_off, dma_qm_offset; @@ -2588,7 +2590,7 @@ static void gaudi_init_pci_dma_qman(struct hl_device *hdev, int dma_id, if (qman_id == 0) { irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ? mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR : - mmGIC_DMA_QM_IRQ_CTRL_POLL_REG; + le32_to_cpu(dyn_regs->gic_dma_qm_irq_ctrl); /* Configure RAZWI IRQ */ dma_qm_err_cfg = PCI_DMA_QMAN_GLBL_ERR_CFG_MSG_EN_MASK; @@ -2624,6 +2626,8 @@ static void gaudi_init_pci_dma_qman(struct hl_device *hdev, int dma_id, static void gaudi_init_dma_core(struct hl_device *hdev, int dma_id) { + struct cpu_dyn_regs *dyn_regs = + &hdev->fw_loader.dynamic_loader.comm_desc.cpu_dyn_regs; u32 dma_err_cfg = 1 << DMA0_CORE_ERR_CFG_ERR_MSG_EN_SHIFT; u32 dma_offset = dma_id * DMA_CORE_OFFSET; u32 irq_handler_offset; @@ -2643,7 +2647,7 @@ static void gaudi_init_dma_core(struct hl_device *hdev, int dma_id) irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ? mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR : - mmGIC_DMA_CR_IRQ_CTRL_POLL_REG; + le32_to_cpu(dyn_regs->gic_dma_core_irq_ctrl); WREG32(mmDMA0_CORE_ERRMSG_ADDR_LO + dma_offset, lower_32_bits(CFG_BASE + irq_handler_offset)); @@ -2712,6 +2716,8 @@ static void gaudi_init_pci_dma_qmans(struct hl_device *hdev) static void gaudi_init_hbm_dma_qman(struct hl_device *hdev, int dma_id, int qman_id, u64 qman_base_addr) { + struct cpu_dyn_regs *dyn_regs = + &hdev->fw_loader.dynamic_loader.comm_desc.cpu_dyn_regs; u32 mtr_base_en_lo, mtr_base_en_hi, mtr_base_ws_lo, mtr_base_ws_hi; u32 so_base_en_lo, so_base_en_hi, so_base_ws_lo, so_base_ws_hi; u32 dma_qm_err_cfg, irq_handler_offset; @@ -2756,8 +2762,8 @@ static void gaudi_init_hbm_dma_qman(struct hl_device *hdev, int dma_id, QMAN_CPDMA_DST_OFFSET); } else { irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ? - mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR : - mmGIC_DMA_QM_IRQ_CTRL_POLL_REG; + mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR : + le32_to_cpu(dyn_regs->gic_dma_qm_irq_ctrl); WREG32(mmDMA0_QM_CP_LDMA_TSIZE_OFFSET_0 + q_off, QMAN_LDMA_SIZE_OFFSET); @@ -2853,6 +2859,8 @@ static void gaudi_init_hbm_dma_qmans(struct hl_device *hdev) static void gaudi_init_mme_qman(struct hl_device *hdev, u32 mme_offset, int qman_id, u64 qman_base_addr) { + struct cpu_dyn_regs *dyn_regs = + &hdev->fw_loader.dynamic_loader.comm_desc.cpu_dyn_regs; u32 mtr_base_lo, mtr_base_hi; u32 so_base_lo, so_base_hi; u32 irq_handler_offset; @@ -2888,8 +2896,8 @@ static void gaudi_init_mme_qman(struct hl_device *hdev, u32 mme_offset, QMAN_CPDMA_DST_OFFSET); } else { irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ? - mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR : - mmGIC_MME_QM_IRQ_CTRL_POLL_REG; + mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR : + le32_to_cpu(dyn_regs->gic_mme_qm_irq_ctrl); WREG32(mmMME0_QM_CP_LDMA_TSIZE_OFFSET_0 + q_off, QMAN_LDMA_SIZE_OFFSET); @@ -2978,6 +2986,8 @@ static void gaudi_init_mme_qmans(struct hl_device *hdev) static void gaudi_init_tpc_qman(struct hl_device *hdev, u32 tpc_offset, int qman_id, u64 qman_base_addr) { + struct cpu_dyn_regs *dyn_regs = + &hdev->fw_loader.dynamic_loader.comm_desc.cpu_dyn_regs; u32 mtr_base_en_lo, mtr_base_en_hi, mtr_base_ws_lo, mtr_base_ws_hi; u32 so_base_en_lo, so_base_en_hi, so_base_ws_lo, so_base_ws_hi; u32 tpc_qm_err_cfg, irq_handler_offset; @@ -3023,8 +3033,8 @@ static void gaudi_init_tpc_qman(struct hl_device *hdev, u32 tpc_offset, QMAN_CPDMA_DST_OFFSET); } else { irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ? - mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR : - mmGIC_TPC_QM_IRQ_CTRL_POLL_REG; + mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR : + le32_to_cpu(dyn_regs->gic_tpc_qm_irq_ctrl); WREG32(mmTPC0_QM_CP_LDMA_TSIZE_OFFSET_0 + q_off, QMAN_LDMA_SIZE_OFFSET); @@ -3129,6 +3139,8 @@ static void gaudi_init_tpc_qmans(struct hl_device *hdev) static void gaudi_init_nic_qman(struct hl_device *hdev, u32 nic_offset, int qman_id, u64 qman_base_addr, int nic_id) { + struct cpu_dyn_regs *dyn_regs = + &hdev->fw_loader.dynamic_loader.comm_desc.cpu_dyn_regs; u32 mtr_base_en_lo, mtr_base_en_hi, mtr_base_ws_lo, mtr_base_ws_hi; u32 so_base_en_lo, so_base_en_hi, so_base_ws_lo, so_base_ws_hi; u32 nic_qm_err_cfg, irq_handler_offset; @@ -3180,8 +3192,8 @@ static void gaudi_init_nic_qman(struct hl_device *hdev, u32 nic_offset, if (qman_id == 0) { irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ? - mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR : - mmGIC_NIC_QM_IRQ_CTRL_POLL_REG; + mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR : + le32_to_cpu(dyn_regs->gic_nic_qm_irq_ctrl); /* Configure RAZWI IRQ */ nic_qm_err_cfg = NIC_QMAN_GLBL_ERR_CFG_MSG_EN_MASK; @@ -3858,6 +3870,8 @@ static int gaudi_init_cpu(struct hl_device *hdev) static int gaudi_init_cpu_queues(struct hl_device *hdev, u32 cpu_timeout) { + struct cpu_dyn_regs *dyn_regs = + &hdev->fw_loader.dynamic_loader.comm_desc.cpu_dyn_regs; struct asic_fixed_properties *prop = &hdev->asic_prop; struct gaudi_device *gaudi = hdev->asic_specific; u32 status, irq_handler_offset; @@ -3902,7 +3916,7 @@ static int gaudi_init_cpu_queues(struct hl_device *hdev, u32 cpu_timeout) irq_handler_offset = prop->gic_interrupts_enable ? mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR : - mmGIC_HOST_IRQ_CTRL_POLL_REG; + le32_to_cpu(dyn_regs->gic_host_irq_ctrl); WREG32(irq_handler_offset, GAUDI_EVENT_PI_UPDATE); @@ -3964,9 +3978,6 @@ static int gaudi_hw_init(struct hl_device *hdev) gaudi_pre_hw_init(hdev); - gaudi_init_pci_dma_qmans(hdev); - - gaudi_init_hbm_dma_qmans(hdev); rc = gaudi_init_cpu(hdev); if (rc) { @@ -3995,6 +4006,10 @@ static int gaudi_hw_init(struct hl_device *hdev) gaudi_init_security(hdev); + gaudi_init_pci_dma_qmans(hdev); + + gaudi_init_hbm_dma_qmans(hdev); + gaudi_init_mme_qmans(hdev); gaudi_init_tpc_qmans(hdev); @@ -4034,6 +4049,8 @@ disable_queues: static void gaudi_hw_fini(struct hl_device *hdev, bool hard_reset) { + struct cpu_dyn_regs *dyn_regs = + &hdev->fw_loader.dynamic_loader.comm_desc.cpu_dyn_regs; struct gaudi_device *gaudi = hdev->asic_specific; u32 status, reset_timeout_ms, cpu_timeout_ms, irq_handler_offset; @@ -4067,8 +4084,8 @@ static void gaudi_hw_fini(struct hl_device *hdev, bool hard_reset) WREG32(mmPSOC_GLOBAL_CONF_KMD_MSG_TO_CPU, KMD_MSG_GOTO_WFE); irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ? - mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR : - mmGIC_HOST_IRQ_CTRL_POLL_REG; + mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR : + le32_to_cpu(dyn_regs->gic_host_irq_ctrl); WREG32(irq_handler_offset, GAUDI_EVENT_HALT_MACHINE); @@ -4182,6 +4199,8 @@ static int gaudi_cb_mmap(struct hl_device *hdev, struct vm_area_struct *vma, static void gaudi_ring_doorbell(struct hl_device *hdev, u32 hw_queue_id, u32 pi) { + struct cpu_dyn_regs *dyn_regs = + &hdev->fw_loader.dynamic_loader.comm_desc.cpu_dyn_regs; u32 db_reg_offset, db_value, dma_qm_offset, q_off, irq_handler_offset; struct gaudi_device *gaudi = hdev->asic_specific; int dma_id; @@ -4592,8 +4611,8 @@ static void gaudi_ring_doorbell(struct hl_device *hdev, u32 hw_queue_id, u32 pi) mb(); irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ? - mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR : - mmGIC_HOST_IRQ_CTRL_POLL_REG; + mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR : + le32_to_cpu(dyn_regs->gic_host_irq_ctrl); WREG32(irq_handler_offset, GAUDI_EVENT_PI_UPDATE); } @@ -8817,9 +8836,11 @@ static int gaudi_block_mmap(struct hl_device *hdev, static void gaudi_enable_events_from_fw(struct hl_device *hdev) { + struct cpu_dyn_regs *dyn_regs = + &hdev->fw_loader.dynamic_loader.comm_desc.cpu_dyn_regs; u32 irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ? mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR : - mmGIC_HOST_IRQ_CTRL_POLL_REG; + le32_to_cpu(dyn_regs->gic_host_irq_ctrl); WREG32(irq_handler_offset, GAUDI_EVENT_INTS_REGISTER); } diff --git a/drivers/misc/habanalabs/include/common/hl_boot_if.h b/drivers/misc/habanalabs/include/common/hl_boot_if.h index e9d86673109c..9266c44d8c6c 100644 --- a/drivers/misc/habanalabs/include/common/hl_boot_if.h +++ b/drivers/misc/habanalabs/include/common/hl_boot_if.h @@ -195,7 +195,7 @@ * previleged entity. FW sets this status * bit for host. If this bit is set then * GIC can not be accessed from host. - * Initialized in: preboot + * Initialized in: armcpd * * CPU_BOOT_DEV_STS0_ENABLED Device status register enabled. * This is a main indication that the @@ -299,7 +299,13 @@ struct cpu_dyn_regs { __le32 hw_state; __le32 kmd_msg_to_cpu; __le32 cpu_cmd_status_to_host; - __le32 reserved1[32]; /* reserve for future use */ + __le32 gic_host_irq_ctrl; + __le32 gic_tpc_qm_irq_ctrl; + __le32 gic_mme_qm_irq_ctrl; + __le32 gic_dma_qm_irq_ctrl; + __le32 gic_nic_qm_irq_ctrl; + __le32 gic_dma_core_irq_ctrl; + __le32 reserved1[26]; /* reserve for future use */ }; /* TODO: remove the desc magic after the code is updated to use message */ -- cgit v1.2.3 From 1dae12fe1bf7ae98f31223b47253f4dd6b0a2909 Mon Sep 17 00:00:00 2001 From: Ofir Bitton Date: Wed, 12 May 2021 09:07:39 +0300 Subject: habanalabs/gaudi: do not move HBM bar if iATU done by FW As iATU configuration is done by FW, driver should not try and move HBM bar. Signed-off-by: Ofir Bitton Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/gaudi/gaudi.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 6bd9167fc7f1..1fa12394e3b6 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -580,6 +580,9 @@ static u64 gaudi_set_hbm_bar_base(struct hl_device *hdev, u64 addr) if ((gaudi) && (gaudi->hbm_bar_cur_addr == addr)) return old_addr; + if (hdev->asic_prop.iatu_done_by_fw) + return U64_MAX; + /* Inbound Region 2 - Bar 4 - Point to HBM */ pci_region.mode = PCI_BAR_MATCH_MODE; pci_region.bar = HBM_BAR_ID; @@ -3974,10 +3977,27 @@ static void gaudi_pre_hw_init(struct hl_device *hdev) static int gaudi_hw_init(struct hl_device *hdev) { + struct gaudi_device *gaudi = hdev->asic_specific; int rc; gaudi_pre_hw_init(hdev); + /* If iATU is done by FW, the HBM bar ALWAYS points to DRAM_PHYS_BASE. + * So we set it here and if anyone tries to move it later to + * a different address, there will be an error + */ + if (hdev->asic_prop.iatu_done_by_fw) + gaudi->hbm_bar_cur_addr = DRAM_PHYS_BASE; + + /* + * Before pushing u-boot/linux to device, need to set the hbm bar to + * base address of dram + */ + if (gaudi_set_hbm_bar_base(hdev, DRAM_PHYS_BASE) == U64_MAX) { + dev_err(hdev->dev, + "failed to map HBM bar to DRAM base address\n"); + return -EIO; + } rc = gaudi_init_cpu(hdev); if (rc) { -- cgit v1.2.3 From 7fb2a1f5b7f81dce20587e79aae8fe8a9ac03986 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Wed, 12 May 2021 20:46:12 +0300 Subject: habanalabs: set memory scrubbing to disabled by default Scrubbing memory after every unmap is very costly in terms of performance. If a user wants it he can enable it but the default should prioritize performance. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/habanalabs_drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/habanalabs_drv.c b/drivers/misc/habanalabs/common/habanalabs_drv.c index df1e91f810cc..339a1860c1e7 100644 --- a/drivers/misc/habanalabs/common/habanalabs_drv.c +++ b/drivers/misc/habanalabs/common/habanalabs_drv.c @@ -29,7 +29,7 @@ static DEFINE_MUTEX(hl_devs_idr_lock); static int timeout_locked = 30; static int reset_on_lockup = 1; -static int memory_scrub = 1; +static int memory_scrub; static ulong boot_error_status_mask = ULONG_MAX; module_param(timeout_locked, int, 0444); @@ -42,7 +42,7 @@ MODULE_PARM_DESC(reset_on_lockup, module_param(memory_scrub, int, 0444); MODULE_PARM_DESC(memory_scrub, - "Scrub device memory in various states (0 = no, 1 = yes, default yes)"); + "Scrub device memory in various states (0 = no, 1 = yes, default no)"); module_param(boot_error_status_mask, ulong, 0444); MODULE_PARM_DESC(boot_error_status_mask, -- cgit v1.2.3 From 1242e9f0f45873607f8e6699b4339c81d9f3de73 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Wed, 19 May 2021 14:52:14 +0300 Subject: habanalabs: check running index in eqe control To harden the event queue mechanism, we add a running index to the control header of the entry. The firmware writes the index in each entry and the driver verifies that the index of the current entry is larger by 1 of the index of the previous entry. In case it isn't, the driver will treat the entry as if it wasn't valid (it won't process it but won't skip it). Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 9 +++++++- drivers/misc/habanalabs/common/habanalabs.h | 7 +++++++ drivers/misc/habanalabs/common/irq.c | 24 +++++++++++++++++++--- drivers/misc/habanalabs/include/common/cpucp_if.h | 3 +++ .../misc/habanalabs/include/common/hl_boot_if.h | 11 +++++++++- 5 files changed, 49 insertions(+), 5 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index b00f763bcda6..17173020ff53 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -617,10 +617,17 @@ int hl_fw_cpucp_info_get(struct hl_device *hdev, goto out; } + /* assume EQ code doesn't need to check eqe index */ + hdev->event_queue.check_eqe_index = false; + /* Read FW application security bits again */ - if (hdev->asic_prop.fw_cpu_boot_dev_sts0_valid) + if (hdev->asic_prop.fw_cpu_boot_dev_sts0_valid) { hdev->asic_prop.fw_app_cpu_boot_dev_sts0 = RREG32(sts_boot_dev_sts0_reg); + if (hdev->asic_prop.fw_app_cpu_boot_dev_sts0 & + CPU_BOOT_DEV_STS0_EQ_INDEX_EN) + hdev->event_queue.check_eqe_index = true; + } if (hdev->asic_prop.fw_cpu_boot_dev_sts1_valid) hdev->asic_prop.fw_app_cpu_boot_dev_sts1 = diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index a046180254c8..c3f41f0b609f 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -780,12 +780,19 @@ struct hl_user_pending_interrupt { * @kernel_address: holds the queue's kernel virtual address * @bus_address: holds the queue's DMA address * @ci: ci inside the queue + * @prev_eqe_index: the index of the previous event queue entry. The index of + * the current entry's index must be +1 of the previous one. + * @check_eqe_index: do we need to check the index of the current entry vs. the + * previous one. This is for backward compatibility with older + * firmwares */ struct hl_eq { struct hl_device *hdev; void *kernel_address; dma_addr_t bus_address; u32 ci; + u32 prev_eqe_index; + bool check_eqe_index; }; diff --git a/drivers/misc/habanalabs/common/irq.c b/drivers/misc/habanalabs/common/irq.c index 27129868c711..39b14a933393 100644 --- a/drivers/misc/habanalabs/common/irq.c +++ b/drivers/misc/habanalabs/common/irq.c @@ -207,17 +207,33 @@ irqreturn_t hl_irq_handler_eq(int irq, void *arg) struct hl_eq_entry *eq_entry; struct hl_eq_entry *eq_base; struct hl_eqe_work *handle_eqe_work; + bool entry_ready; + u32 cur_eqe; + u16 cur_eqe_index; eq_base = eq->kernel_address; while (1) { - bool entry_ready = - ((le32_to_cpu(eq_base[eq->ci].hdr.ctl) & - EQ_CTL_READY_MASK) >> EQ_CTL_READY_SHIFT); + cur_eqe = le32_to_cpu(eq_base[eq->ci].hdr.ctl); + entry_ready = !!FIELD_GET(EQ_CTL_READY_MASK, cur_eqe); if (!entry_ready) break; + cur_eqe_index = FIELD_GET(EQ_CTL_INDEX_MASK, cur_eqe); + if ((hdev->event_queue.check_eqe_index) && + (((eq->prev_eqe_index + 1) & EQ_CTL_INDEX_MASK) + != cur_eqe_index)) { + dev_dbg(hdev->dev, + "EQE 0x%x in queue is ready but index does not match %d!=%d", + eq_base[eq->ci].hdr.ctl, + ((eq->prev_eqe_index + 1) & EQ_CTL_INDEX_MASK), + cur_eqe_index); + break; + } + + eq->prev_eqe_index++; + eq_entry = &eq_base[eq->ci]; /* @@ -341,6 +357,7 @@ int hl_eq_init(struct hl_device *hdev, struct hl_eq *q) q->hdev = hdev; q->kernel_address = p; q->ci = 0; + q->prev_eqe_index = 0; return 0; } @@ -365,6 +382,7 @@ void hl_eq_fini(struct hl_device *hdev, struct hl_eq *q) void hl_eq_reset(struct hl_device *hdev, struct hl_eq *q) { q->ci = 0; + q->prev_eqe_index = 0; /* * It's not enough to just reset the PI/CI because the H/W may have diff --git a/drivers/misc/habanalabs/include/common/cpucp_if.h b/drivers/misc/habanalabs/include/common/cpucp_if.h index 4f1123102968..c7da62243619 100644 --- a/drivers/misc/habanalabs/include/common/cpucp_if.h +++ b/drivers/misc/habanalabs/include/common/cpucp_if.h @@ -103,6 +103,9 @@ struct hl_eq_entry { #define EQ_CTL_EVENT_TYPE_SHIFT 16 #define EQ_CTL_EVENT_TYPE_MASK 0x03FF0000 +#define EQ_CTL_INDEX_SHIFT 0 +#define EQ_CTL_INDEX_MASK 0x0000FFFF + enum pq_init_status { PQ_INIT_STATUS_NA = 0, PQ_INIT_STATUS_READY_FOR_CP, diff --git a/drivers/misc/habanalabs/include/common/hl_boot_if.h b/drivers/misc/habanalabs/include/common/hl_boot_if.h index 9266c44d8c6c..6d0c1ddb4304 100644 --- a/drivers/misc/habanalabs/include/common/hl_boot_if.h +++ b/drivers/misc/habanalabs/include/common/hl_boot_if.h @@ -195,7 +195,15 @@ * previleged entity. FW sets this status * bit for host. If this bit is set then * GIC can not be accessed from host. - * Initialized in: armcpd + * Initialized in: linux + * + * CPU_BOOT_DEV_STS0_EQ_INDEX_EN Event Queue (EQ) index is a running + * index for each new event sent to host. + * This is used as a method in host to + * identify that the waiting event in + * queue is actually a new event which + * was not served before. + * Initialized in: linux * * CPU_BOOT_DEV_STS0_ENABLED Device status register enabled. * This is a main indication that the @@ -226,6 +234,7 @@ #define CPU_BOOT_DEV_STS0_FW_IATU_CONF_EN (1 << 17) #define CPU_BOOT_DEV_STS0_DYN_PLL_EN (1 << 19) #define CPU_BOOT_DEV_STS0_GIC_PRIVILEGED_EN (1 << 20) +#define CPU_BOOT_DEV_STS0_EQ_INDEX_EN (1 << 21) #define CPU_BOOT_DEV_STS0_ENABLED (1 << 31) #define CPU_BOOT_DEV_STS1_ENABLED (1 << 31) -- cgit v1.2.3 From 7feffb6815450bbcbed96a870a36a56f20608640 Mon Sep 17 00:00:00 2001 From: Koby Elbaz Date: Tue, 18 May 2021 15:05:35 +0300 Subject: habanalabs: read preboot status bits in an earlier stage On newer releases, host won't be able to trigger an interrupt directly to the ASIC GIC controller. To be able to decide whether GIC can/not be used, we must read device's preboot status bits in a stage that precedes the possible first use of GIC (when device is in dirty state). Signed-off-by: Koby Elbaz Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index 17173020ff53..cdec7212f377 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -1159,8 +1159,6 @@ static int hl_fw_static_read_preboot_status(struct hl_device *hdev) if (rc) return rc; - hl_fw_preboot_update_state(hdev); - return 0; } @@ -1189,6 +1187,8 @@ int hl_fw_read_preboot_status(struct hl_device *hdev, u32 cpu_boot_status_reg, if (rc) return rc; + hl_fw_preboot_update_state(hdev); + /* no need to read preboot status in dynamic load */ if (hdev->asic_prop.dynamic_fw_load) return 0; @@ -1864,9 +1864,6 @@ static int hl_fw_dynamic_load_image(struct hl_device *hdev, hl_fw_boot_fit_update_state(hdev, le32_to_cpu(dyn_regs->cpu_boot_dev_sts0), le32_to_cpu(dyn_regs->cpu_boot_dev_sts1)); - } else { - /* update state during preboot handshake */ - hl_fw_preboot_update_state(hdev); } /* copy boot fit to space allocated by FW */ @@ -2097,9 +2094,6 @@ static int hl_fw_dynamic_init_cpu(struct hl_device *hdev, } if (!(hdev->fw_components & FW_TYPE_BOOT_CPU)) { - /* update the preboot state */ - hl_fw_preboot_update_state(hdev); - rc = hl_fw_dynamic_request_descriptor(hdev, fw_loader, 0); if (rc) goto protocol_err; -- cgit v1.2.3 From 3649eaea2754e0d64a5a6726e46093b490c226d7 Mon Sep 17 00:00:00 2001 From: Koby Elbaz Date: Tue, 18 May 2021 15:43:47 +0300 Subject: habanalabs/gaudi: disable GIC usage if security is enabled Security is set based on PCI ID, and after reading preboot status bits. GIC usage is set in both scenarios since GIC can't be used when security is enabled. Moreover, writing to GIC/SP is enabled only after Linux is fully loaded. Signed-off-by: Koby Elbaz Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 25 ++++++++++++++----------- drivers/misc/habanalabs/common/habanalabs.h | 2 ++ drivers/misc/habanalabs/gaudi/gaudi.c | 17 +++++++++++++---- 3 files changed, 29 insertions(+), 15 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index cdec7212f377..399d64e4f4c2 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -1115,19 +1115,13 @@ static void hl_fw_preboot_update_state(struct hl_device *hdev) * b. Check whether hard reset is done by fw app * * Preboot: - * Check security status bit (CPU_BOOT_DEV_STS0_ENABLED), if it is set + * Check security status bit (CPU_BOOT_DEV_STS0_ENABLED). If set, then- * check security enabled bit (CPU_BOOT_DEV_STS0_SECURITY_EN) - * Check GIC privileged bit (CPU_BOOT_DEV_STS0_GIC_PRIVILEGED_EN) + * If set, then mark GIC controller to be disabled. */ if (cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_ENABLED) { prop->fw_cpu_boot_dev_sts0_valid = 1; - /* FW security should be derived from PCI ID, we keep this - * check for backward compatibility - */ - if (cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_SECURITY_EN) - prop->fw_security_disabled = false; - if (cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_FW_HARD_RST_EN) prop->hard_reset_done_by_fw = true; } else { @@ -1149,6 +1143,9 @@ static void hl_fw_preboot_update_state(struct hl_device *hdev) dev_dbg(hdev->dev, "firmware-level security is %s\n", prop->fw_security_disabled ? "disabled" : "enabled"); + + dev_dbg(hdev->dev, "GIC controller is %s\n", + prop->gic_interrupts_enable ? "enabled" : "disabled"); } static int hl_fw_static_read_preboot_status(struct hl_device *hdev) @@ -1941,9 +1938,13 @@ static int hl_fw_dynamic_wait_for_linux_active(struct hl_device *hdev, } /** - * hl_fw_linux_update_state - update internal data structures after loading - * Linux - * + * hl_fw_linux_update_state - update internal data structures after Linux + * is loaded. + * Note: Linux initialization is comprised mainly + * of two stages - loading kernel (SRAM_AVAIL) + * & loading ARMCP. + * Therefore reading boot device status in any of + * these stages might result in different values. * * @hdev: pointer to the habanalabs device structure * @cpu_boot_dev_sts0_reg: register holding CPU boot dev status 0 @@ -1957,6 +1958,8 @@ static void hl_fw_linux_update_state(struct hl_device *hdev, { struct asic_fixed_properties *prop = &hdev->asic_prop; + hdev->fw_loader.linux_loaded = true; + /* Clear reset status since we need to read again from app */ prop->hard_reset_done_by_fw = false; diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index c3f41f0b609f..433262bfb7e6 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -956,6 +956,7 @@ struct fw_image_props { * @skip_bmc: should BMC be skipped * @sram_bar_id: SRAM bar ID * @dram_bar_id: DRAM bar ID + * @linux_loaded: true if linux was loaded so far */ struct fw_load_mgr { union { @@ -969,6 +970,7 @@ struct fw_load_mgr { u8 skip_bmc; u8 sram_bar_id; u8 dram_bar_id; + u8 linux_loaded; }; /** diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 1fa12394e3b6..4249dffdb7f7 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -689,6 +689,12 @@ static int gaudi_early_init(struct hl_device *hdev) /* If FW security is enabled at this point it means no access to ELBI */ if (!hdev->asic_prop.fw_security_disabled) { hdev->asic_prop.iatu_done_by_fw = true; + + /* + * GIC-security-bit can ONLY be set by CPUCP, so in this stage + * decision can only be taken based on PCI ID security. + */ + hdev->asic_prop.gic_interrupts_enable = false; goto pci_init; } @@ -3829,6 +3835,7 @@ static void gaudi_init_firmware_loader(struct hl_device *hdev) struct fw_load_mgr *fw_loader = &hdev->fw_loader; /* fill common fields */ + fw_loader->linux_loaded = false; fw_loader->boot_fit_img.image_name = GAUDI_BOOT_FIT_FILE; fw_loader->linux_img.image_name = GAUDI_LINUX_FW_FILE; fw_loader->cpu_timeout = GAUDI_CPU_TIMEOUT_USEC; @@ -4103,11 +4110,13 @@ static void gaudi_hw_fini(struct hl_device *hdev, bool hard_reset) else WREG32(mmPSOC_GLOBAL_CONF_KMD_MSG_TO_CPU, KMD_MSG_GOTO_WFE); - irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ? - mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR : - le32_to_cpu(dyn_regs->gic_host_irq_ctrl); + if (hdev->fw_loader.linux_loaded) { + irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ? + mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR : + le32_to_cpu(dyn_regs->gic_host_irq_ctrl); - WREG32(irq_handler_offset, GAUDI_EVENT_HALT_MACHINE); + WREG32(irq_handler_offset, GAUDI_EVENT_HALT_MACHINE); + } if (hdev->asic_prop.fw_security_disabled && !hdev->asic_prop.hard_reset_done_by_fw) { -- cgit v1.2.3 From 4080308e33bd6ebdb10d0ce62545690cb9be23e4 Mon Sep 17 00:00:00 2001 From: Koby Elbaz Date: Thu, 20 May 2021 12:45:58 +0300 Subject: habanalabs/gaudi: use COMMS to reset device / halt CPU This is needed because legacy FW 'communication' protocol will soon become obsolete. Because COMMS is a boot protocol, communicating through it is supported only until Linux is loaded to the device CPU, where in that case we will fallback to the former implementation. Signed-off-by: Koby Elbaz Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 2 +- drivers/misc/habanalabs/common/habanalabs.h | 5 +++- drivers/misc/habanalabs/gaudi/gaudi.c | 36 ++++++++++++++++++++++++++-- 3 files changed, 39 insertions(+), 4 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index 399d64e4f4c2..c19acefdb7e4 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -1390,7 +1390,7 @@ static int hl_fw_dynamic_send_clear_cmd(struct hl_device *hdev, * leftovers between command * NOOP command: necessary to avoid loop on the clear command by the FW */ -static int hl_fw_dynamic_send_protocol_cmd(struct hl_device *hdev, +int hl_fw_dynamic_send_protocol_cmd(struct hl_device *hdev, struct fw_load_mgr *fw_loader, enum comms_cmd cmd, unsigned int size, bool wait_ok, u32 timeout) diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index 433262bfb7e6..f1ff4d503cf2 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -2574,7 +2574,10 @@ int hl_fw_read_preboot_status(struct hl_device *hdev, u32 cpu_boot_status_reg, u32 sts_boot_dev_sts0_reg, u32 sts_boot_dev_sts1_reg, u32 boot_err0_reg, u32 boot_err1_reg, u32 timeout); - +int hl_fw_dynamic_send_protocol_cmd(struct hl_device *hdev, + struct fw_load_mgr *fw_loader, + enum comms_cmd cmd, unsigned int size, + bool wait_ok, u32 timeout); int hl_pci_bars_map(struct hl_device *hdev, const char * const name[3], bool is_wc[3]); int hl_pci_elbi_read(struct hl_device *hdev, u64 addr, u32 *data); diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 4249dffdb7f7..3bdf5ddc6fd5 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -1931,6 +1931,38 @@ static void gaudi_disable_msi(struct hl_device *hdev) gaudi->hw_cap_initialized &= ~HW_CAP_MSI; } +static void gaudi_fw_hard_reset(struct hl_device *hdev) +{ + int rc; + + if (hdev->asic_prop.dynamic_fw_load && !hdev->fw_loader.linux_loaded) { + rc = hl_fw_dynamic_send_protocol_cmd(hdev, &hdev->fw_loader, + COMMS_RST_DEV, 0, false, + hdev->fw_loader.cpu_timeout); + if (rc) + dev_warn(hdev->dev, "Failed sending COMMS_RST_DEV\n"); + } else { + WREG32(mmPSOC_GLOBAL_CONF_KMD_MSG_TO_CPU, KMD_MSG_RST_DEV); + } +} + +static void gaudi_fw_halt_cpu(struct hl_device *hdev) +{ + int rc; + + /* Stop device CPU to make sure nothing bad happens */ + if (hdev->asic_prop.dynamic_fw_load && !hdev->fw_loader.linux_loaded) { + rc = hl_fw_dynamic_send_protocol_cmd(hdev, &hdev->fw_loader, + COMMS_GOTO_WFE, 0, true, + hdev->fw_loader.cpu_timeout); + if (rc) + dev_warn(hdev->dev, "Failed sending COMMS_GOTO_WFE\n"); + } else { + WREG32(mmPSOC_GLOBAL_CONF_KMD_MSG_TO_CPU, KMD_MSG_GOTO_WFE); + msleep(GAUDI_CPU_RESET_WAIT_MSEC); + } +} + static void gaudi_init_scrambler_sram(struct hl_device *hdev) { struct gaudi_device *gaudi = hdev->asic_specific; @@ -4106,9 +4138,9 @@ static void gaudi_hw_fini(struct hl_device *hdev, bool hard_reset) * stopped in any means necessary */ if (hdev->asic_prop.hard_reset_done_by_fw) - WREG32(mmPSOC_GLOBAL_CONF_KMD_MSG_TO_CPU, KMD_MSG_RST_DEV); + gaudi_fw_hard_reset(hdev); else - WREG32(mmPSOC_GLOBAL_CONF_KMD_MSG_TO_CPU, KMD_MSG_GOTO_WFE); + gaudi_fw_halt_cpu(hdev); if (hdev->fw_loader.linux_loaded) { irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ? -- cgit v1.2.3 From 4cb4508c86d700bdf243e013630ba1af93a01892 Mon Sep 17 00:00:00 2001 From: Ohad Sharabi Date: Thu, 20 May 2021 09:09:03 +0300 Subject: habanalabs: track security status using positive logic Using negative logic (i.e. fw_security_disabled) is confusing. Modify the flag to use positive logic (fw_security_enabled). Signed-off-by: Ohad Sharabi Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 2 +- drivers/misc/habanalabs/common/habanalabs.h | 6 ++-- drivers/misc/habanalabs/common/habanalabs_drv.c | 6 ++-- drivers/misc/habanalabs/gaudi/gaudi.c | 48 ++++++++++++------------- drivers/misc/habanalabs/gaudi/gaudi_coresight.c | 2 +- drivers/misc/habanalabs/gaudi/gaudi_security.c | 15 ++++---- drivers/misc/habanalabs/goya/goya.c | 20 +++++------ drivers/misc/habanalabs/goya/goya_coresight.c | 2 +- 8 files changed, 51 insertions(+), 50 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index c19acefdb7e4..4cc6690a3e26 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -1142,7 +1142,7 @@ static void hl_fw_preboot_update_state(struct hl_device *hdev) prop->hard_reset_done_by_fw ? "enabled" : "disabled"); dev_dbg(hdev->dev, "firmware-level security is %s\n", - prop->fw_security_disabled ? "disabled" : "enabled"); + prop->fw_security_enabled ? "enabled" : "disabled"); dev_dbg(hdev->dev, "GIC controller is %s\n", prop->gic_interrupts_enable ? "enabled" : "disabled"); diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index f1ff4d503cf2..e751868b3ed3 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -456,8 +456,8 @@ struct hl_mmu_properties { * @user_interrupt_count: number of user interrupts. * @tpc_enabled_mask: which TPCs are enabled. * @completion_queues_count: number of completion queues. - * @fw_security_disabled: true if security measures are disabled in firmware, - * false otherwise + * @fw_security_enabled: true if security measures are enabled in firmware, + * false otherwise * @fw_cpu_boot_dev_sts0_valid: status bits are valid and can be fetched from * BOOT_DEV_STS0 * @fw_cpu_boot_dev_sts1_valid: status bits are valid and can be fetched from @@ -531,7 +531,7 @@ struct asic_fixed_properties { u16 user_interrupt_count; u8 tpc_enabled_mask; u8 completion_queues_count; - u8 fw_security_disabled; + u8 fw_security_enabled; u8 fw_cpu_boot_dev_sts0_valid; u8 fw_cpu_boot_dev_sts1_valid; u8 dram_supports_virtual_memory; diff --git a/drivers/misc/habanalabs/common/habanalabs_drv.c b/drivers/misc/habanalabs/common/habanalabs_drv.c index 339a1860c1e7..bd67d4ceab56 100644 --- a/drivers/misc/habanalabs/common/habanalabs_drv.c +++ b/drivers/misc/habanalabs/common/habanalabs_drv.c @@ -308,10 +308,10 @@ int create_hdev(struct hl_device **dev, struct pci_dev *pdev, } if (pdev) - hdev->asic_prop.fw_security_disabled = - !is_asic_secured(hdev->asic_type); + hdev->asic_prop.fw_security_enabled = + is_asic_secured(hdev->asic_type); else - hdev->asic_prop.fw_security_disabled = true; + hdev->asic_prop.fw_security_enabled = false; /* Assign status description string */ strncpy(hdev->status[HL_DEVICE_STATUS_MALFUNCTION], diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 3bdf5ddc6fd5..a272dfc6b8a6 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -687,7 +687,7 @@ static int gaudi_early_init(struct hl_device *hdev) prop->dram_pci_bar_size = pci_resource_len(pdev, HBM_BAR_ID); /* If FW security is enabled at this point it means no access to ELBI */ - if (!hdev->asic_prop.fw_security_disabled) { + if (hdev->asic_prop.fw_security_enabled) { hdev->asic_prop.iatu_done_by_fw = true; /* @@ -763,7 +763,14 @@ static int gaudi_fetch_psoc_frequency(struct hl_device *hdev) u16 pll_freq_arr[HL_PLL_NUM_OUTPUTS], freq; int rc; - if (hdev->asic_prop.fw_security_disabled) { + if (hdev->asic_prop.fw_security_enabled) { + rc = hl_fw_cpucp_pll_info_get(hdev, HL_GAUDI_CPU_PLL, pll_freq_arr); + + if (rc) + return rc; + + freq = pll_freq_arr[2]; + } else { /* Backward compatibility */ div_fctr = RREG32(mmPSOC_CPU_PLL_DIV_FACTOR_2); div_sel = RREG32(mmPSOC_CPU_PLL_DIV_SEL_2); @@ -791,13 +798,6 @@ static int gaudi_fetch_psoc_frequency(struct hl_device *hdev) div_sel); freq = 0; } - } else { - rc = hl_fw_cpucp_pll_info_get(hdev, HL_GAUDI_CPU_PLL, pll_freq_arr); - - if (rc) - return rc; - - freq = pll_freq_arr[2]; } prop->psoc_timestamp_frequency = freq; @@ -1525,7 +1525,7 @@ static int gaudi_alloc_cpu_accessible_dma_mem(struct hl_device *hdev) hdev->cpu_pci_msb_addr = GAUDI_CPU_PCI_MSB_ADDR(hdev->cpu_accessible_dma_address); - if (hdev->asic_prop.fw_security_disabled) + if (!hdev->asic_prop.fw_security_enabled) GAUDI_PCI_TO_CPU_ADDR(hdev->cpu_accessible_dma_address); free_dma_mem_arr: @@ -1725,7 +1725,7 @@ static int gaudi_sw_init(struct hl_device *hdev) free_cpu_accessible_dma_pool: gen_pool_destroy(hdev->cpu_accessible_dma_pool); free_cpu_dma_mem: - if (hdev->asic_prop.fw_security_disabled) + if (!hdev->asic_prop.fw_security_enabled) GAUDI_CPU_TO_PCI_ADDR(hdev->cpu_accessible_dma_address, hdev->cpu_pci_msb_addr); hdev->asic_funcs->asic_dma_free_coherent(hdev, @@ -1747,7 +1747,7 @@ static int gaudi_sw_fini(struct hl_device *hdev) gen_pool_destroy(hdev->cpu_accessible_dma_pool); - if (hdev->asic_prop.fw_security_disabled) + if (!hdev->asic_prop.fw_security_enabled) GAUDI_CPU_TO_PCI_ADDR(hdev->cpu_accessible_dma_address, hdev->cpu_pci_msb_addr); @@ -1967,7 +1967,7 @@ static void gaudi_init_scrambler_sram(struct hl_device *hdev) { struct gaudi_device *gaudi = hdev->asic_specific; - if (!hdev->asic_prop.fw_security_disabled) + if (hdev->asic_prop.fw_security_enabled) return; if (hdev->asic_prop.fw_cpu_boot_dev_sts0_valid && @@ -2039,7 +2039,7 @@ static void gaudi_init_scrambler_hbm(struct hl_device *hdev) { struct gaudi_device *gaudi = hdev->asic_specific; - if (!hdev->asic_prop.fw_security_disabled) + if (hdev->asic_prop.fw_security_enabled) return; if (hdev->asic_prop.fw_cpu_boot_dev_sts0_valid && @@ -2109,7 +2109,7 @@ static void gaudi_init_scrambler_hbm(struct hl_device *hdev) static void gaudi_init_e2e(struct hl_device *hdev) { - if (!hdev->asic_prop.fw_security_disabled) + if (hdev->asic_prop.fw_security_enabled) return; if (hdev->asic_prop.fw_cpu_boot_dev_sts0_valid && @@ -2484,7 +2484,7 @@ static void gaudi_init_hbm_cred(struct hl_device *hdev) { uint32_t hbm0_wr, hbm1_wr, hbm0_rd, hbm1_rd; - if (!hdev->asic_prop.fw_security_disabled) + if (hdev->asic_prop.fw_security_enabled) return; if (hdev->asic_prop.fw_cpu_boot_dev_sts0_valid && @@ -3602,7 +3602,7 @@ static void gaudi_set_clock_gating(struct hl_device *hdev) if (hdev->in_debug) return; - if (!hdev->asic_prop.fw_security_disabled) + if (hdev->asic_prop.fw_security_enabled) return; for (i = GAUDI_PCI_DMA_1, qman_offset = 0 ; i < GAUDI_HBM_DMA_1 ; i++) { @@ -3662,7 +3662,7 @@ static void gaudi_disable_clock_gating(struct hl_device *hdev) u32 qman_offset; int i; - if (!hdev->asic_prop.fw_security_disabled) + if (hdev->asic_prop.fw_security_enabled) return; for (i = 0, qman_offset = 0 ; i < DMA_NUMBER_OF_CHANNELS ; i++) { @@ -3897,7 +3897,7 @@ static int gaudi_init_cpu(struct hl_device *hdev) * The device CPU works with 40 bits addresses. * This register sets the extension to 50 bits. */ - if (hdev->asic_prop.fw_security_disabled) + if (!hdev->asic_prop.fw_security_enabled) WREG32(mmCPU_IF_CPU_MSB_ADDR, hdev->cpu_pci_msb_addr); rc = hl_fw_init_cpu(hdev); @@ -3991,7 +3991,7 @@ static void gaudi_pre_hw_init(struct hl_device *hdev) /* Perform read from the device to make sure device is up */ RREG32(mmHW_STATE); - if (hdev->asic_prop.fw_security_disabled) { + if (!hdev->asic_prop.fw_security_enabled) { /* Set the access through PCI bars (Linux driver only) as * secured */ @@ -4129,7 +4129,7 @@ static void gaudi_hw_fini(struct hl_device *hdev, bool hard_reset) /* Set device to handle FLR by H/W as we will put the device CPU to * halt mode */ - if (hdev->asic_prop.fw_security_disabled && + if (!hdev->asic_prop.fw_security_enabled && !hdev->asic_prop.hard_reset_done_by_fw) WREG32(mmPCIE_AUX_FLR_CTRL, (PCIE_AUX_FLR_CTRL_HW_CTRL_MASK | PCIE_AUX_FLR_CTRL_INT_MASK_MASK)); @@ -4150,7 +4150,7 @@ static void gaudi_hw_fini(struct hl_device *hdev, bool hard_reset) WREG32(irq_handler_offset, GAUDI_EVENT_HALT_MACHINE); } - if (hdev->asic_prop.fw_security_disabled && + if (!hdev->asic_prop.fw_security_enabled && !hdev->asic_prop.hard_reset_done_by_fw) { /* Configure the reset registers. Must be done as early as @@ -4185,7 +4185,7 @@ static void gaudi_hw_fini(struct hl_device *hdev, bool hard_reset) WREG32(mmPREBOOT_PCIE_EN, LKD_HARD_RESET_MAGIC); /* Restart BTL/BLR upon hard-reset */ - if (hdev->asic_prop.fw_security_disabled) + if (!hdev->asic_prop.fw_security_enabled) WREG32(mmPSOC_GLOBAL_CONF_BOOT_SEQ_RE_START, 1); WREG32(mmPSOC_GLOBAL_CONF_SW_ALL_RST, @@ -7570,7 +7570,7 @@ static int gaudi_hbm_read_interrupts(struct hl_device *hdev, int device, return 0; } - if (!hdev->asic_prop.fw_security_disabled) { + if (hdev->asic_prop.fw_security_enabled) { dev_info(hdev->dev, "Cannot access MC regs for ECC data while security is enabled\n"); return 0; } diff --git a/drivers/misc/habanalabs/gaudi/gaudi_coresight.c b/drivers/misc/habanalabs/gaudi/gaudi_coresight.c index 6e56fa1c6c69..9e271fd9f0d2 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi_coresight.c +++ b/drivers/misc/habanalabs/gaudi/gaudi_coresight.c @@ -634,7 +634,7 @@ static int gaudi_config_etr(struct hl_device *hdev, WREG32(mmPSOC_ETR_BUFWM, 0x3FFC); WREG32(mmPSOC_ETR_RSZ, input->buffer_size); WREG32(mmPSOC_ETR_MODE, input->sink_mode); - if (hdev->asic_prop.fw_security_disabled) { + if (!hdev->asic_prop.fw_security_enabled) { /* make ETR not privileged */ val = FIELD_PREP( PSOC_ETR_AXICTL_PROTCTRLBIT0_MASK, 0); diff --git a/drivers/misc/habanalabs/gaudi/gaudi_security.c b/drivers/misc/habanalabs/gaudi/gaudi_security.c index 9a706c5980ef..0d3240f1f7d7 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi_security.c +++ b/drivers/misc/habanalabs/gaudi/gaudi_security.c @@ -1448,7 +1448,7 @@ static void gaudi_init_dma_protection_bits(struct hl_device *hdev) u32 pb_addr, mask; u8 word_offset; - if (hdev->asic_prop.fw_security_disabled) { + if (!hdev->asic_prop.fw_security_enabled) { gaudi_pb_set_block(hdev, mmDMA_IF_E_S_BASE); gaudi_pb_set_block(hdev, mmDMA_IF_E_S_DOWN_CH0_BASE); gaudi_pb_set_block(hdev, mmDMA_IF_E_S_DOWN_CH1_BASE); @@ -9135,7 +9135,7 @@ static void gaudi_init_tpc_protection_bits(struct hl_device *hdev) u32 pb_addr, mask; u8 word_offset; - if (hdev->asic_prop.fw_security_disabled) { + if (!hdev->asic_prop.fw_security_enabled) { gaudi_pb_set_block(hdev, mmTPC0_E2E_CRED_BASE); gaudi_pb_set_block(hdev, mmTPC1_E2E_CRED_BASE); gaudi_pb_set_block(hdev, mmTPC2_E2E_CRED_BASE); @@ -12818,7 +12818,7 @@ static void gaudi_init_protection_bits(struct hl_device *hdev) * secured */ - if (hdev->asic_prop.fw_security_disabled) { + if (!hdev->asic_prop.fw_security_enabled) { gaudi_pb_set_block(hdev, mmIF_E_PLL_BASE); gaudi_pb_set_block(hdev, mmMESH_W_PLL_BASE); gaudi_pb_set_block(hdev, mmSRAM_W_PLL_BASE); @@ -13023,7 +13023,7 @@ void gaudi_init_security(struct hl_device *hdev) * property configuration of MME SBAB and ACC to be non-privileged and * non-secured */ - if (hdev->asic_prop.fw_security_disabled) { + if (!hdev->asic_prop.fw_security_enabled) { WREG32(mmMME0_SBAB_PROT, 0x2); WREG32(mmMME0_ACC_PROT, 0x2); WREG32(mmMME1_SBAB_PROT, 0x2); @@ -13032,11 +13032,12 @@ void gaudi_init_security(struct hl_device *hdev) WREG32(mmMME2_ACC_PROT, 0x2); WREG32(mmMME3_SBAB_PROT, 0x2); WREG32(mmMME3_ACC_PROT, 0x2); - } - /* On RAZWI, 0 will be returned from RR and 0xBABA0BAD from PB */ - if (hdev->asic_prop.fw_security_disabled) + /* + * On RAZWI, 0 will be returned from RR and 0xBABA0BAD from PB + */ WREG32(0xC01B28, 0x1); + } gaudi_init_range_registers_lbw(hdev); diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c index 3d7a760cf2ba..bcefc372a689 100644 --- a/drivers/misc/habanalabs/goya/goya.c +++ b/drivers/misc/habanalabs/goya/goya.c @@ -619,7 +619,7 @@ static int goya_early_init(struct hl_device *hdev) prop->dram_pci_bar_size = pci_resource_len(pdev, DDR_BAR_ID); /* If FW security is enabled at this point it means no access to ELBI */ - if (!hdev->asic_prop.fw_security_disabled) { + if (hdev->asic_prop.fw_security_enabled) { hdev->asic_prop.iatu_done_by_fw = true; goto pci_init; } @@ -726,7 +726,15 @@ static void goya_fetch_psoc_frequency(struct hl_device *hdev) u16 pll_freq_arr[HL_PLL_NUM_OUTPUTS], freq; int rc; - if (hdev->asic_prop.fw_security_disabled) { + if (hdev->asic_prop.fw_security_enabled) { + rc = hl_fw_cpucp_pll_info_get(hdev, HL_GOYA_PCI_PLL, + pll_freq_arr); + + if (rc) + return; + + freq = pll_freq_arr[1]; + } else { div_fctr = RREG32(mmPSOC_PCI_PLL_DIV_FACTOR_1); div_sel = RREG32(mmPSOC_PCI_PLL_DIV_SEL_1); nr = RREG32(mmPSOC_PCI_PLL_NR); @@ -753,14 +761,6 @@ static void goya_fetch_psoc_frequency(struct hl_device *hdev) div_sel); freq = 0; } - } else { - rc = hl_fw_cpucp_pll_info_get(hdev, HL_GOYA_PCI_PLL, - pll_freq_arr); - - if (rc) - return; - - freq = pll_freq_arr[1]; } prop->psoc_timestamp_frequency = freq; diff --git a/drivers/misc/habanalabs/goya/goya_coresight.c b/drivers/misc/habanalabs/goya/goya_coresight.c index 6b7445cca580..c55c100fdd24 100644 --- a/drivers/misc/habanalabs/goya/goya_coresight.c +++ b/drivers/misc/habanalabs/goya/goya_coresight.c @@ -434,7 +434,7 @@ static int goya_config_etr(struct hl_device *hdev, WREG32(mmPSOC_ETR_BUFWM, 0x3FFC); WREG32(mmPSOC_ETR_RSZ, input->buffer_size); WREG32(mmPSOC_ETR_MODE, input->sink_mode); - if (hdev->asic_prop.fw_security_disabled) { + if (!hdev->asic_prop.fw_security_enabled) { /* make ETR not privileged */ val = FIELD_PREP(PSOC_ETR_AXICTL_PROTCTRLBIT0_MASK, 0); /* make ETR non-secured (inverted logic) */ -- cgit v1.2.3 From a60d075c81f0730b62b277d9a94842a3737a4a42 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Sun, 23 May 2021 19:00:49 +0300 Subject: habanalabs/gaudi: refactor reset code After all the latest changes to the reset code, there were some redundancy and errors in the flows. If the Linux FIT is loaded to the ASIC CPU, we need to communicate with it only via GIC. If it is not loaded, we need to either use COMMS protocol (for newer f/w) or MSG_TO_CPU register (for older f/w). In addition, if we halted the device CPU then we need to mark that the driver will do the reset, regardless of the capabilities. Also, to prevent false errors, we need to keep track whether the device CPU was already halted. If so, we shouldn't try to halt it again. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/gaudi/gaudi.c | 47 +++++++++++++++++++++------------- drivers/misc/habanalabs/gaudi/gaudiP.h | 5 ++++ 2 files changed, 34 insertions(+), 18 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index a272dfc6b8a6..4d89313f58ea 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -1931,11 +1931,11 @@ static void gaudi_disable_msi(struct hl_device *hdev) gaudi->hw_cap_initialized &= ~HW_CAP_MSI; } -static void gaudi_fw_hard_reset(struct hl_device *hdev) +static void gaudi_ask_hard_reset_without_linux(struct hl_device *hdev) { int rc; - if (hdev->asic_prop.dynamic_fw_load && !hdev->fw_loader.linux_loaded) { + if (hdev->asic_prop.dynamic_fw_load) { rc = hl_fw_dynamic_send_protocol_cmd(hdev, &hdev->fw_loader, COMMS_RST_DEV, 0, false, hdev->fw_loader.cpu_timeout); @@ -1946,12 +1946,16 @@ static void gaudi_fw_hard_reset(struct hl_device *hdev) } } -static void gaudi_fw_halt_cpu(struct hl_device *hdev) +static void gaudi_ask_halt_machine_without_linux(struct hl_device *hdev) { + struct gaudi_device *gaudi = hdev->asic_specific; int rc; + if (gaudi && gaudi->device_cpu_is_halted) + return; + /* Stop device CPU to make sure nothing bad happens */ - if (hdev->asic_prop.dynamic_fw_load && !hdev->fw_loader.linux_loaded) { + if (hdev->asic_prop.dynamic_fw_load) { rc = hl_fw_dynamic_send_protocol_cmd(hdev, &hdev->fw_loader, COMMS_GOTO_WFE, 0, true, hdev->fw_loader.cpu_timeout); @@ -1961,6 +1965,9 @@ static void gaudi_fw_halt_cpu(struct hl_device *hdev) WREG32(mmPSOC_GLOBAL_CONF_KMD_MSG_TO_CPU, KMD_MSG_GOTO_WFE); msleep(GAUDI_CPU_RESET_WAIT_MSEC); } + + if (gaudi) + gaudi->device_cpu_is_halted = true; } static void gaudi_init_scrambler_sram(struct hl_device *hdev) @@ -4110,8 +4117,9 @@ static void gaudi_hw_fini(struct hl_device *hdev, bool hard_reset) { struct cpu_dyn_regs *dyn_regs = &hdev->fw_loader.dynamic_loader.comm_desc.cpu_dyn_regs; - struct gaudi_device *gaudi = hdev->asic_specific; u32 status, reset_timeout_ms, cpu_timeout_ms, irq_handler_offset; + struct gaudi_device *gaudi = hdev->asic_specific; + bool driver_performs_reset; if (!hard_reset) { dev_err(hdev->dev, "GAUDI doesn't support soft-reset\n"); @@ -4126,32 +4134,34 @@ static void gaudi_hw_fini(struct hl_device *hdev, bool hard_reset) cpu_timeout_ms = GAUDI_CPU_RESET_WAIT_MSEC; } + driver_performs_reset = !!(!hdev->asic_prop.fw_security_enabled && + !hdev->asic_prop.hard_reset_done_by_fw); + /* Set device to handle FLR by H/W as we will put the device CPU to * halt mode */ - if (!hdev->asic_prop.fw_security_enabled && - !hdev->asic_prop.hard_reset_done_by_fw) + if (driver_performs_reset) WREG32(mmPCIE_AUX_FLR_CTRL, (PCIE_AUX_FLR_CTRL_HW_CTRL_MASK | PCIE_AUX_FLR_CTRL_INT_MASK_MASK)); - /* I don't know what is the state of the CPU so make sure it is - * stopped in any means necessary + /* If linux is loaded in the device CPU we need to communicate with it + * via the GIC. Otherwise, we need to use COMMS or the MSG_TO_CPU + * registers in case of old F/Ws */ - if (hdev->asic_prop.hard_reset_done_by_fw) - gaudi_fw_hard_reset(hdev); - else - gaudi_fw_halt_cpu(hdev); - if (hdev->fw_loader.linux_loaded) { irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ? mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR : le32_to_cpu(dyn_regs->gic_host_irq_ctrl); WREG32(irq_handler_offset, GAUDI_EVENT_HALT_MACHINE); + } else { + if (hdev->asic_prop.hard_reset_done_by_fw) + gaudi_ask_hard_reset_without_linux(hdev); + else + gaudi_ask_halt_machine_without_linux(hdev); } - if (!hdev->asic_prop.fw_security_enabled && - !hdev->asic_prop.hard_reset_done_by_fw) { + if (driver_performs_reset) { /* Configure the reset registers. Must be done as early as * possible in case we fail during H/W initialization @@ -4185,8 +4195,7 @@ static void gaudi_hw_fini(struct hl_device *hdev, bool hard_reset) WREG32(mmPREBOOT_PCIE_EN, LKD_HARD_RESET_MAGIC); /* Restart BTL/BLR upon hard-reset */ - if (!hdev->asic_prop.fw_security_enabled) - WREG32(mmPSOC_GLOBAL_CONF_BOOT_SEQ_RE_START, 1); + WREG32(mmPSOC_GLOBAL_CONF_BOOT_SEQ_RE_START, 1); WREG32(mmPSOC_GLOBAL_CONF_SW_ALL_RST, 1 << PSOC_GLOBAL_CONF_SW_ALL_RST_IND_SHIFT); @@ -4223,6 +4232,8 @@ static void gaudi_hw_fini(struct hl_device *hdev, bool hard_reset) HW_CAP_CLK_GATE); memset(gaudi->events_stat, 0, sizeof(gaudi->events_stat)); + + gaudi->device_cpu_is_halted = false; } } diff --git a/drivers/misc/habanalabs/gaudi/gaudiP.h b/drivers/misc/habanalabs/gaudi/gaudiP.h index 5929be81ec23..48637a6343bb 100644 --- a/drivers/misc/habanalabs/gaudi/gaudiP.h +++ b/drivers/misc/habanalabs/gaudi/gaudiP.h @@ -314,6 +314,10 @@ struct gaudi_internal_qman_info { * Multi MSI is possible only with IOMMU enabled. * @mmu_cache_inv_pi: PI for MMU cache invalidation flow. The H/W expects an * 8-bit value so use u8. + * @device_cpu_is_halted: Flag to indicate whether the device CPU was already + * halted. We can't halt it again because the COMMS + * protocol will throw an error. Relevant only for + * cases where Linux was not loaded to device CPU */ struct gaudi_device { int (*cpucp_info_get)(struct hl_device *hdev); @@ -335,6 +339,7 @@ struct gaudi_device { u32 hw_cap_initialized; u8 multi_msi_mode; u8 mmu_cache_inv_pi; + u8 device_cpu_is_halted; }; void gaudi_init_security(struct hl_device *hdev); -- cgit v1.2.3 From b92c637c5f5ef7e3e21dbc7bfa7f1999450f3902 Mon Sep 17 00:00:00 2001 From: Koby Elbaz Date: Wed, 19 May 2021 15:16:52 +0300 Subject: habanalabs/gaudi: set the correct cpu_id on MME2_QM failure This fix was applied since there was an incorrect reported CPU ID to GIC such that an error in MME2 QMAN aliased to be an arriving from DMA0_QM. Signed-off-by: Koby Elbaz Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/gaudi/gaudi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 4d89313f58ea..17fb1fde14cb 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -2956,7 +2956,7 @@ static void gaudi_init_mme_qman(struct hl_device *hdev, u32 mme_offset, /* Configure RAZWI IRQ */ mme_id = mme_offset / - (mmMME1_QM_GLBL_CFG0 - mmMME0_QM_GLBL_CFG0); + (mmMME1_QM_GLBL_CFG0 - mmMME0_QM_GLBL_CFG0) / 2; mme_qm_err_cfg = MME_QMAN_GLBL_ERR_CFG_MSG_EN_MASK; if (hdev->stop_on_err) { -- cgit v1.2.3 From 9081021029fd97d09056ed6ab13912339efab571 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Tue, 25 May 2021 21:35:13 +0300 Subject: habanalabs/gaudi: don't use nic_ports_mask in compute nic_ports_mask is used by the networking part of the driver. In the compute part, we use the HW_CAP bits to select what is active and what is not. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/gaudi/gaudi.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 17fb1fde14cb..b022658b67f3 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -6712,7 +6712,7 @@ static void gaudi_mmu_prepare(struct hl_device *hdev, u32 asid) gaudi_mmu_prepare_reg(hdev, mmMME2_ACC_WBC, asid); gaudi_mmu_prepare_reg(hdev, mmMME3_ACC_WBC, asid); - if (hdev->nic_ports_mask & GAUDI_NIC_MASK_NIC0) { + if (gaudi->hw_cap_initialized & HW_CAP_NIC0) { gaudi_mmu_prepare_reg(hdev, mmNIC0_QM0_GLBL_NON_SECURE_PROPS_0, asid); gaudi_mmu_prepare_reg(hdev, mmNIC0_QM0_GLBL_NON_SECURE_PROPS_1, @@ -6725,7 +6725,7 @@ static void gaudi_mmu_prepare(struct hl_device *hdev, u32 asid) asid); } - if (hdev->nic_ports_mask & GAUDI_NIC_MASK_NIC1) { + if (gaudi->hw_cap_initialized & HW_CAP_NIC1) { gaudi_mmu_prepare_reg(hdev, mmNIC0_QM1_GLBL_NON_SECURE_PROPS_0, asid); gaudi_mmu_prepare_reg(hdev, mmNIC0_QM1_GLBL_NON_SECURE_PROPS_1, @@ -6738,7 +6738,7 @@ static void gaudi_mmu_prepare(struct hl_device *hdev, u32 asid) asid); } - if (hdev->nic_ports_mask & GAUDI_NIC_MASK_NIC2) { + if (gaudi->hw_cap_initialized & HW_CAP_NIC2) { gaudi_mmu_prepare_reg(hdev, mmNIC1_QM0_GLBL_NON_SECURE_PROPS_0, asid); gaudi_mmu_prepare_reg(hdev, mmNIC1_QM0_GLBL_NON_SECURE_PROPS_1, @@ -6751,7 +6751,7 @@ static void gaudi_mmu_prepare(struct hl_device *hdev, u32 asid) asid); } - if (hdev->nic_ports_mask & GAUDI_NIC_MASK_NIC3) { + if (gaudi->hw_cap_initialized & HW_CAP_NIC3) { gaudi_mmu_prepare_reg(hdev, mmNIC1_QM1_GLBL_NON_SECURE_PROPS_0, asid); gaudi_mmu_prepare_reg(hdev, mmNIC1_QM1_GLBL_NON_SECURE_PROPS_1, @@ -6764,7 +6764,7 @@ static void gaudi_mmu_prepare(struct hl_device *hdev, u32 asid) asid); } - if (hdev->nic_ports_mask & GAUDI_NIC_MASK_NIC4) { + if (gaudi->hw_cap_initialized & HW_CAP_NIC4) { gaudi_mmu_prepare_reg(hdev, mmNIC2_QM0_GLBL_NON_SECURE_PROPS_0, asid); gaudi_mmu_prepare_reg(hdev, mmNIC2_QM0_GLBL_NON_SECURE_PROPS_1, @@ -6777,7 +6777,7 @@ static void gaudi_mmu_prepare(struct hl_device *hdev, u32 asid) asid); } - if (hdev->nic_ports_mask & GAUDI_NIC_MASK_NIC5) { + if (gaudi->hw_cap_initialized & HW_CAP_NIC5) { gaudi_mmu_prepare_reg(hdev, mmNIC2_QM1_GLBL_NON_SECURE_PROPS_0, asid); gaudi_mmu_prepare_reg(hdev, mmNIC2_QM1_GLBL_NON_SECURE_PROPS_1, @@ -6790,7 +6790,7 @@ static void gaudi_mmu_prepare(struct hl_device *hdev, u32 asid) asid); } - if (hdev->nic_ports_mask & GAUDI_NIC_MASK_NIC6) { + if (gaudi->hw_cap_initialized & HW_CAP_NIC6) { gaudi_mmu_prepare_reg(hdev, mmNIC3_QM0_GLBL_NON_SECURE_PROPS_0, asid); gaudi_mmu_prepare_reg(hdev, mmNIC3_QM0_GLBL_NON_SECURE_PROPS_1, @@ -6803,7 +6803,7 @@ static void gaudi_mmu_prepare(struct hl_device *hdev, u32 asid) asid); } - if (hdev->nic_ports_mask & GAUDI_NIC_MASK_NIC7) { + if (gaudi->hw_cap_initialized & HW_CAP_NIC7) { gaudi_mmu_prepare_reg(hdev, mmNIC3_QM1_GLBL_NON_SECURE_PROPS_0, asid); gaudi_mmu_prepare_reg(hdev, mmNIC3_QM1_GLBL_NON_SECURE_PROPS_1, @@ -6816,7 +6816,7 @@ static void gaudi_mmu_prepare(struct hl_device *hdev, u32 asid) asid); } - if (hdev->nic_ports_mask & GAUDI_NIC_MASK_NIC8) { + if (gaudi->hw_cap_initialized & HW_CAP_NIC8) { gaudi_mmu_prepare_reg(hdev, mmNIC4_QM0_GLBL_NON_SECURE_PROPS_0, asid); gaudi_mmu_prepare_reg(hdev, mmNIC4_QM0_GLBL_NON_SECURE_PROPS_1, @@ -6829,7 +6829,7 @@ static void gaudi_mmu_prepare(struct hl_device *hdev, u32 asid) asid); } - if (hdev->nic_ports_mask & GAUDI_NIC_MASK_NIC9) { + if (gaudi->hw_cap_initialized & HW_CAP_NIC9) { gaudi_mmu_prepare_reg(hdev, mmNIC4_QM1_GLBL_NON_SECURE_PROPS_0, asid); gaudi_mmu_prepare_reg(hdev, mmNIC4_QM1_GLBL_NON_SECURE_PROPS_1, @@ -8236,7 +8236,7 @@ static bool gaudi_is_device_idle(struct hl_device *hdev, u64 *mask_arr, for (i = 0 ; i < (NIC_NUMBER_OF_ENGINES / 2) ; i++) { offset = i * NIC_MACRO_QMAN_OFFSET; port = 2 * i; - if (hdev->nic_ports_mask & BIT(port)) { + if (gaudi->hw_cap_initialized & BIT(HW_CAP_NIC_SHIFT + port)) { qm_glbl_sts0 = RREG32(mmNIC0_QM0_GLBL_STS0 + offset); qm_cgm_sts = RREG32(mmNIC0_QM0_CGM_STS + offset); is_eng_idle = IS_QM_IDLE(qm_glbl_sts0, qm_cgm_sts); @@ -8251,7 +8251,7 @@ static bool gaudi_is_device_idle(struct hl_device *hdev, u64 *mask_arr, } port = 2 * i + 1; - if (hdev->nic_ports_mask & BIT(port)) { + if (gaudi->hw_cap_initialized & BIT(HW_CAP_NIC_SHIFT + port)) { qm_glbl_sts0 = RREG32(mmNIC0_QM1_GLBL_STS0 + offset); qm_cgm_sts = RREG32(mmNIC0_QM1_CGM_STS + offset); is_eng_idle = IS_QM_IDLE(qm_glbl_sts0, qm_cgm_sts); -- cgit v1.2.3 From ae151bcfab04f3580382a81b608a72773d19c25d Mon Sep 17 00:00:00 2001 From: Tomer Tayar Date: Mon, 24 May 2021 22:35:06 +0300 Subject: habanalabs/gaudi: add ARB to QM stop on error masks Update the QM stop on error masks to also stop on ARB errors. Signed-off-by: Tomer Tayar Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/gaudi/gaudi.c | 17 +++++++---------- drivers/misc/habanalabs/include/gaudi/gaudi_masks.h | 15 ++++++++++----- 2 files changed, 17 insertions(+), 15 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index b022658b67f3..e0e3e0f6e9d8 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -2642,10 +2642,9 @@ static void gaudi_init_pci_dma_qman(struct hl_device *hdev, int dma_id, /* Configure RAZWI IRQ */ dma_qm_err_cfg = PCI_DMA_QMAN_GLBL_ERR_CFG_MSG_EN_MASK; - if (hdev->stop_on_err) { + if (hdev->stop_on_err) dma_qm_err_cfg |= PCI_DMA_QMAN_GLBL_ERR_CFG_STOP_ON_ERR_EN_MASK; - } WREG32(mmDMA0_QM_GLBL_ERR_CFG + dma_qm_offset, dma_qm_err_cfg); @@ -2822,10 +2821,10 @@ static void gaudi_init_hbm_dma_qman(struct hl_device *hdev, int dma_id, /* Configure RAZWI IRQ */ dma_qm_err_cfg = HBM_DMA_QMAN_GLBL_ERR_CFG_MSG_EN_MASK; - if (hdev->stop_on_err) { + if (hdev->stop_on_err) dma_qm_err_cfg |= HBM_DMA_QMAN_GLBL_ERR_CFG_STOP_ON_ERR_EN_MASK; - } + WREG32(mmDMA0_QM_GLBL_ERR_CFG + dma_qm_offset, dma_qm_err_cfg); WREG32(mmDMA0_QM_GLBL_ERR_ADDR_LO + dma_qm_offset, @@ -2959,10 +2958,10 @@ static void gaudi_init_mme_qman(struct hl_device *hdev, u32 mme_offset, (mmMME1_QM_GLBL_CFG0 - mmMME0_QM_GLBL_CFG0) / 2; mme_qm_err_cfg = MME_QMAN_GLBL_ERR_CFG_MSG_EN_MASK; - if (hdev->stop_on_err) { + if (hdev->stop_on_err) mme_qm_err_cfg |= MME_QMAN_GLBL_ERR_CFG_STOP_ON_ERR_EN_MASK; - } + WREG32(mmMME0_QM_GLBL_ERR_CFG + mme_offset, mme_qm_err_cfg); WREG32(mmMME0_QM_GLBL_ERR_ADDR_LO + mme_offset, @@ -3093,10 +3092,9 @@ static void gaudi_init_tpc_qman(struct hl_device *hdev, u32 tpc_offset, /* Configure RAZWI IRQ */ tpc_qm_err_cfg = TPC_QMAN_GLBL_ERR_CFG_MSG_EN_MASK; - if (hdev->stop_on_err) { + if (hdev->stop_on_err) tpc_qm_err_cfg |= TPC_QMAN_GLBL_ERR_CFG_STOP_ON_ERR_EN_MASK; - } WREG32(mmTPC0_QM_GLBL_ERR_CFG + tpc_offset, tpc_qm_err_cfg); @@ -3245,10 +3243,9 @@ static void gaudi_init_nic_qman(struct hl_device *hdev, u32 nic_offset, /* Configure RAZWI IRQ */ nic_qm_err_cfg = NIC_QMAN_GLBL_ERR_CFG_MSG_EN_MASK; - if (hdev->stop_on_err) { + if (hdev->stop_on_err) nic_qm_err_cfg |= NIC_QMAN_GLBL_ERR_CFG_STOP_ON_ERR_EN_MASK; - } WREG32(mmNIC0_QM0_GLBL_ERR_CFG + nic_offset, nic_qm_err_cfg); diff --git a/drivers/misc/habanalabs/include/gaudi/gaudi_masks.h b/drivers/misc/habanalabs/include/gaudi/gaudi_masks.h index b53aeda9a982..9aea7e996654 100644 --- a/drivers/misc/habanalabs/include/gaudi/gaudi_masks.h +++ b/drivers/misc/habanalabs/include/gaudi/gaudi_masks.h @@ -66,7 +66,8 @@ #define PCI_DMA_QMAN_GLBL_ERR_CFG_STOP_ON_ERR_EN_MASK (\ (FIELD_PREP(DMA0_QM_GLBL_ERR_CFG_PQF_STOP_ON_ERR_MASK, 0xF)) | \ (FIELD_PREP(DMA0_QM_GLBL_ERR_CFG_CQF_STOP_ON_ERR_MASK, 0xF)) | \ - (FIELD_PREP(DMA0_QM_GLBL_ERR_CFG_CP_STOP_ON_ERR_MASK, 0xF))) + (FIELD_PREP(DMA0_QM_GLBL_ERR_CFG_CP_STOP_ON_ERR_MASK, 0xF)) | \ + (FIELD_PREP(DMA0_QM_GLBL_ERR_CFG_ARB_STOP_ON_ERR_MASK, 0x1))) #define HBM_DMA_QMAN_GLBL_ERR_CFG_MSG_EN_MASK (\ (FIELD_PREP(DMA0_QM_GLBL_ERR_CFG_PQF_ERR_MSG_EN_MASK, 0xF)) | \ @@ -76,7 +77,8 @@ #define HBM_DMA_QMAN_GLBL_ERR_CFG_STOP_ON_ERR_EN_MASK (\ (FIELD_PREP(DMA0_QM_GLBL_ERR_CFG_PQF_STOP_ON_ERR_MASK, 0xF)) | \ (FIELD_PREP(DMA0_QM_GLBL_ERR_CFG_CQF_STOP_ON_ERR_MASK, 0x1F)) | \ - (FIELD_PREP(DMA0_QM_GLBL_ERR_CFG_CP_STOP_ON_ERR_MASK, 0x1F))) + (FIELD_PREP(DMA0_QM_GLBL_ERR_CFG_CP_STOP_ON_ERR_MASK, 0x1F)) | \ + (FIELD_PREP(DMA0_QM_GLBL_ERR_CFG_ARB_STOP_ON_ERR_MASK, 0x1))) #define TPC_QMAN_GLBL_ERR_CFG_MSG_EN_MASK (\ (FIELD_PREP(TPC0_QM_GLBL_ERR_CFG_PQF_ERR_MSG_EN_MASK, 0xF)) | \ @@ -86,7 +88,8 @@ #define TPC_QMAN_GLBL_ERR_CFG_STOP_ON_ERR_EN_MASK (\ (FIELD_PREP(TPC0_QM_GLBL_ERR_CFG_PQF_STOP_ON_ERR_MASK, 0xF)) | \ (FIELD_PREP(TPC0_QM_GLBL_ERR_CFG_CQF_STOP_ON_ERR_MASK, 0x1F)) | \ - (FIELD_PREP(TPC0_QM_GLBL_ERR_CFG_CP_STOP_ON_ERR_MASK, 0x1F))) + (FIELD_PREP(TPC0_QM_GLBL_ERR_CFG_CP_STOP_ON_ERR_MASK, 0x1F)) | \ + (FIELD_PREP(TPC0_QM_GLBL_ERR_CFG_ARB_STOP_ON_ERR_MASK, 0x1))) #define MME_QMAN_GLBL_ERR_CFG_MSG_EN_MASK (\ (FIELD_PREP(MME0_QM_GLBL_ERR_CFG_PQF_ERR_MSG_EN_MASK, 0xF)) | \ @@ -96,7 +99,8 @@ #define MME_QMAN_GLBL_ERR_CFG_STOP_ON_ERR_EN_MASK (\ (FIELD_PREP(MME0_QM_GLBL_ERR_CFG_PQF_STOP_ON_ERR_MASK, 0xF)) | \ (FIELD_PREP(MME0_QM_GLBL_ERR_CFG_CQF_STOP_ON_ERR_MASK, 0x1F)) | \ - (FIELD_PREP(MME0_QM_GLBL_ERR_CFG_CP_STOP_ON_ERR_MASK, 0x1F))) + (FIELD_PREP(MME0_QM_GLBL_ERR_CFG_CP_STOP_ON_ERR_MASK, 0x1F)) | \ + (FIELD_PREP(MME0_QM_GLBL_ERR_CFG_ARB_STOP_ON_ERR_MASK, 0x1))) #define NIC_QMAN_GLBL_ERR_CFG_MSG_EN_MASK (\ (FIELD_PREP(NIC0_QM0_GLBL_ERR_CFG_PQF_ERR_MSG_EN_MASK, 0xF)) | \ @@ -106,7 +110,8 @@ #define NIC_QMAN_GLBL_ERR_CFG_STOP_ON_ERR_EN_MASK (\ (FIELD_PREP(NIC0_QM0_GLBL_ERR_CFG_PQF_STOP_ON_ERR_MASK, 0xF)) | \ (FIELD_PREP(NIC0_QM0_GLBL_ERR_CFG_CQF_STOP_ON_ERR_MASK, 0xF)) | \ - (FIELD_PREP(NIC0_QM0_GLBL_ERR_CFG_CP_STOP_ON_ERR_MASK, 0xF))) + (FIELD_PREP(NIC0_QM0_GLBL_ERR_CFG_CP_STOP_ON_ERR_MASK, 0xF)) | \ + (FIELD_PREP(NIC0_QM0_GLBL_ERR_CFG_ARB_STOP_ON_ERR_MASK, 0x1))) #define QMAN_CGM1_PWR_GATE_EN (FIELD_PREP(DMA0_QM_CGM_CFG1_MASK_TH_MASK, 0xA)) -- cgit v1.2.3 From 135ade0c6afccbe874bdda811201733e5b57c9bc Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Wed, 26 May 2021 11:14:21 +0300 Subject: habanalabs: prefer ASYNC device probing There is no dependency when probing multiple devices so indicate to the kernel that it can probe our devices in ASYNC fashion. This shortens insmod of the driver from ~2 minutes to 20 seconds on a system with 8 devices. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/habanalabs_drv.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/habanalabs_drv.c b/drivers/misc/habanalabs/common/habanalabs_drv.c index bd67d4ceab56..137e7dc63d3b 100644 --- a/drivers/misc/habanalabs/common/habanalabs_drv.c +++ b/drivers/misc/habanalabs/common/habanalabs_drv.c @@ -574,7 +574,11 @@ static struct pci_driver hl_pci_driver = { .probe = hl_pci_probe, .remove = hl_pci_remove, .shutdown = hl_pci_remove, - .driver.pm = &hl_pm_ops, + .driver = { + .name = HL_NAME, + .pm = &hl_pm_ops, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, .err_handler = &hl_pci_err_handler, }; -- cgit v1.2.3 From 5bc691d84966cd763d06c9c70b68c97835793c88 Mon Sep 17 00:00:00 2001 From: Ofir Bitton Date: Tue, 25 May 2021 22:09:13 +0300 Subject: habanalabs/gaudi: split host irq interfaces towards FW Current implementation uses a single interrupt interface towards FW, this interface is causing races between interrupt types. We split this interface to interface per interrupt type. Signed-off-by: Ofir Bitton Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 26 ++++++++++++++++++++-- drivers/misc/habanalabs/gaudi/gaudi.c | 8 +++---- .../misc/habanalabs/include/common/hl_boot_if.h | 14 ++++++++++-- .../misc/habanalabs/include/gaudi/gaudi_reg_map.h | 4 ++++ 4 files changed, 44 insertions(+), 8 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index 4cc6690a3e26..40e91985cb48 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -1782,7 +1782,8 @@ static void hl_fw_boot_fit_update_state(struct hl_device *hdev, /* Read boot_cpu status bits */ if (prop->fw_cpu_boot_dev_sts0_valid) { - prop->fw_bootfit_cpu_boot_dev_sts0 = RREG32(cpu_boot_dev_sts0_reg); + prop->fw_bootfit_cpu_boot_dev_sts0 = + RREG32(cpu_boot_dev_sts0_reg); if (prop->fw_bootfit_cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_FW_HARD_RST_EN) @@ -1793,7 +1794,8 @@ static void hl_fw_boot_fit_update_state(struct hl_device *hdev, } if (prop->fw_cpu_boot_dev_sts1_valid) { - prop->fw_bootfit_cpu_boot_dev_sts1 = RREG32(cpu_boot_dev_sts1_reg); + prop->fw_bootfit_cpu_boot_dev_sts1 = + RREG32(cpu_boot_dev_sts1_reg); dev_dbg(hdev->dev, "Firmware boot CPU status1 %#x\n", prop->fw_bootfit_cpu_boot_dev_sts1); @@ -1803,6 +1805,24 @@ static void hl_fw_boot_fit_update_state(struct hl_device *hdev, prop->hard_reset_done_by_fw ? "enabled" : "disabled"); } +static void hl_fw_dynamic_update_linux_interrupt_if(struct hl_device *hdev) +{ + struct cpu_dyn_regs *dyn_regs = + &hdev->fw_loader.dynamic_loader.comm_desc.cpu_dyn_regs; + + /* Check whether all 3 interrupt interfaces are set, if not use a + * single interface + */ + if (!hdev->asic_prop.gic_interrupts_enable && + !(hdev->asic_prop.fw_app_cpu_boot_dev_sts0 & + CPU_BOOT_DEV_STS0_MULTI_IRQ_POLL_EN)) { + dyn_regs->gic_host_halt_irq = dyn_regs->gic_host_irq_ctrl; + dyn_regs->gic_host_ints_irq = dyn_regs->gic_host_irq_ctrl; + + dev_warn(hdev->dev, + "Using a single interrupt interface towards cpucp"); + } +} /** * hl_fw_dynamic_load_image - load FW image using dynamic protocol * @@ -2150,6 +2170,8 @@ static int hl_fw_dynamic_init_cpu(struct hl_device *hdev, hl_fw_linux_update_state(hdev, le32_to_cpu(dyn_regs->cpu_boot_dev_sts0), le32_to_cpu(dyn_regs->cpu_boot_dev_sts1)); + hl_fw_dynamic_update_linux_interrupt_if(hdev); + return 0; protocol_err: diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index e0e3e0f6e9d8..ee1ab7190e46 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -3962,7 +3962,7 @@ static int gaudi_init_cpu_queues(struct hl_device *hdev, u32 cpu_timeout) irq_handler_offset = prop->gic_interrupts_enable ? mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR : - le32_to_cpu(dyn_regs->gic_host_irq_ctrl); + le32_to_cpu(dyn_regs->gic_host_pi_upd_irq); WREG32(irq_handler_offset, GAUDI_EVENT_PI_UPDATE); @@ -4148,7 +4148,7 @@ static void gaudi_hw_fini(struct hl_device *hdev, bool hard_reset) if (hdev->fw_loader.linux_loaded) { irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ? mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR : - le32_to_cpu(dyn_regs->gic_host_irq_ctrl); + le32_to_cpu(dyn_regs->gic_host_halt_irq); WREG32(irq_handler_offset, GAUDI_EVENT_HALT_MACHINE); } else { @@ -4681,7 +4681,7 @@ static void gaudi_ring_doorbell(struct hl_device *hdev, u32 hw_queue_id, u32 pi) irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ? mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR : - le32_to_cpu(dyn_regs->gic_host_irq_ctrl); + le32_to_cpu(dyn_regs->gic_host_pi_upd_irq); WREG32(irq_handler_offset, GAUDI_EVENT_PI_UPDATE); } @@ -8909,7 +8909,7 @@ static void gaudi_enable_events_from_fw(struct hl_device *hdev) &hdev->fw_loader.dynamic_loader.comm_desc.cpu_dyn_regs; u32 irq_handler_offset = hdev->asic_prop.gic_interrupts_enable ? mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR : - le32_to_cpu(dyn_regs->gic_host_irq_ctrl); + le32_to_cpu(dyn_regs->gic_host_ints_irq); WREG32(irq_handler_offset, GAUDI_EVENT_INTS_REGISTER); } diff --git a/drivers/misc/habanalabs/include/common/hl_boot_if.h b/drivers/misc/habanalabs/include/common/hl_boot_if.h index 6d0c1ddb4304..89ac8020f821 100644 --- a/drivers/misc/habanalabs/include/common/hl_boot_if.h +++ b/drivers/misc/habanalabs/include/common/hl_boot_if.h @@ -205,6 +205,10 @@ * was not served before. * Initialized in: linux * + * CPU_BOOT_DEV_STS0_MULTI_IRQ_POLL_EN Use multiple scratchpad interfaces to + * prevent IRQs overriding each other. + * Initialized in: linux + * * CPU_BOOT_DEV_STS0_ENABLED Device status register enabled. * This is a main indication that the * running FW populates the device status @@ -235,6 +239,7 @@ #define CPU_BOOT_DEV_STS0_DYN_PLL_EN (1 << 19) #define CPU_BOOT_DEV_STS0_GIC_PRIVILEGED_EN (1 << 20) #define CPU_BOOT_DEV_STS0_EQ_INDEX_EN (1 << 21) +#define CPU_BOOT_DEV_STS0_MULTI_IRQ_POLL_EN (1 << 22) #define CPU_BOOT_DEV_STS0_ENABLED (1 << 31) #define CPU_BOOT_DEV_STS1_ENABLED (1 << 31) @@ -308,13 +313,18 @@ struct cpu_dyn_regs { __le32 hw_state; __le32 kmd_msg_to_cpu; __le32 cpu_cmd_status_to_host; - __le32 gic_host_irq_ctrl; + union { + __le32 gic_host_irq_ctrl; + __le32 gic_host_pi_upd_irq; + }; __le32 gic_tpc_qm_irq_ctrl; __le32 gic_mme_qm_irq_ctrl; __le32 gic_dma_qm_irq_ctrl; __le32 gic_nic_qm_irq_ctrl; __le32 gic_dma_core_irq_ctrl; - __le32 reserved1[26]; /* reserve for future use */ + __le32 gic_host_halt_irq; + __le32 gic_host_ints_irq; + __le32 reserved1[24]; /* reserve for future use */ }; /* TODO: remove the desc magic after the code is updated to use message */ diff --git a/drivers/misc/habanalabs/include/gaudi/gaudi_reg_map.h b/drivers/misc/habanalabs/include/gaudi/gaudi_reg_map.h index cd69d3407631..d95d4162ae2c 100644 --- a/drivers/misc/habanalabs/include/gaudi/gaudi_reg_map.h +++ b/drivers/misc/habanalabs/include/gaudi/gaudi_reg_map.h @@ -12,12 +12,16 @@ * PSOC scratch-pad registers */ #define mmHW_STATE mmPSOC_GLOBAL_CONF_SCRATCHPAD_0 +/* TODO: remove mmGIC_HOST_IRQ_CTRL_POLL_REG */ #define mmGIC_HOST_IRQ_CTRL_POLL_REG mmPSOC_GLOBAL_CONF_SCRATCHPAD_1 +#define mmGIC_HOST_PI_UPD_IRQ_POLL_REG mmPSOC_GLOBAL_CONF_SCRATCHPAD_1 #define mmGIC_TPC_QM_IRQ_CTRL_POLL_REG mmPSOC_GLOBAL_CONF_SCRATCHPAD_2 #define mmGIC_MME_QM_IRQ_CTRL_POLL_REG mmPSOC_GLOBAL_CONF_SCRATCHPAD_3 #define mmGIC_DMA_QM_IRQ_CTRL_POLL_REG mmPSOC_GLOBAL_CONF_SCRATCHPAD_4 #define mmGIC_NIC_QM_IRQ_CTRL_POLL_REG mmPSOC_GLOBAL_CONF_SCRATCHPAD_5 #define mmGIC_DMA_CR_IRQ_CTRL_POLL_REG mmPSOC_GLOBAL_CONF_SCRATCHPAD_6 +#define mmGIC_HOST_HALT_IRQ_POLL_REG mmPSOC_GLOBAL_CONF_SCRATCHPAD_7 +#define mmGIC_HOST_INTS_IRQ_POLL_REG mmPSOC_GLOBAL_CONF_SCRATCHPAD_8 #define mmCPU_BOOT_DEV_STS0 mmPSOC_GLOBAL_CONF_SCRATCHPAD_20 #define mmCPU_BOOT_DEV_STS1 mmPSOC_GLOBAL_CONF_SCRATCHPAD_21 #define mmFUSE_VER_OFFSET mmPSOC_GLOBAL_CONF_SCRATCHPAD_22 -- cgit v1.2.3 From 5a967fb3a74113724cf3f5fd9021d43fe2bda32e Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Mon, 31 May 2021 17:01:43 +0300 Subject: habanalabs/gaudi: update to latest f/w specs Update the firmware interface files to their latest version. Signed-off-by: Oded Gabbay --- .../misc/habanalabs/include/common/hl_boot_if.h | 36 ++++++++++++++++------ .../misc/habanalabs/include/gaudi/gaudi_fw_if.h | 7 +++++ 2 files changed, 33 insertions(+), 10 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/include/common/hl_boot_if.h b/drivers/misc/habanalabs/include/common/hl_boot_if.h index 89ac8020f821..fa8a5ad2d438 100644 --- a/drivers/misc/habanalabs/include/common/hl_boot_if.h +++ b/drivers/misc/habanalabs/include/common/hl_boot_if.h @@ -333,24 +333,41 @@ struct cpu_dyn_regs { #define HL_COMMS_DESC_VER 1 /* HCMv - Habana Communications Message + header version */ -#define HL_COMMS_MSG_MAGIC_VER(ver) (0x48434D00 | ((ver) & 0xff)) +#define HL_COMMS_MSG_MAGIC_VALUE 0x48434D00 +#define HL_COMMS_MSG_MAGIC_MASK 0xFFFFFF00 +#define HL_COMMS_MSG_MAGIC_VER_MASK 0xFF + +#define HL_COMMS_MSG_MAGIC_VER(ver) (HL_COMMS_MSG_MAGIC_VALUE | \ + ((ver) & HL_COMMS_MSG_MAGIC_VER_MASK)) #define HL_COMMS_MSG_MAGIC_V0 HL_COMMS_DESC_MAGIC #define HL_COMMS_MSG_MAGIC_V1 HL_COMMS_MSG_MAGIC_VER(1) #define HL_COMMS_MSG_MAGIC HL_COMMS_MSG_MAGIC_V1 +#define HL_COMMS_MSG_MAGIC_VALIDATE_MAGIC(magic) \ + (((magic) & HL_COMMS_MSG_MAGIC_MASK) == \ + HL_COMMS_MSG_MAGIC_VALUE) + +#define HL_COMMS_MSG_MAGIC_VALIDATE_VERSION(magic, ver) \ + (((magic) & HL_COMMS_MSG_MAGIC_VER_MASK) >= \ + ((ver) & HL_COMMS_MSG_MAGIC_VER_MASK)) + +#define HL_COMMS_MSG_MAGIC_VALIDATE(magic, ver) \ + (HL_COMMS_MSG_MAGIC_VALIDATE_MAGIC((magic)) && \ + HL_COMMS_MSG_MAGIC_VALIDATE_VERSION((magic), (ver))) + enum comms_msg_type { HL_COMMS_DESC_TYPE = 0, HL_COMMS_RESET_CAUSE_TYPE = 1, }; -/* TODO: remove this struct after the code is updated to use comms_msg_header */ +/* TODO: remove this struct after the code is updated to use message */ /* this is the comms descriptor header - meta data */ struct comms_desc_header { __le32 magic; /* magic for validation */ __le32 crc32; /* CRC32 of the descriptor w/o header */ __le16 size; /* size of the descriptor w/o header */ - __u8 version; /* descriptor version */ + __u8 version; /* descriptor version */ __u8 reserved[5]; /* pad to 64 bit */ }; @@ -359,7 +376,7 @@ struct comms_msg_header { __le32 magic; /* magic for validation */ __le32 crc32; /* CRC32 of the message w/o header */ __le16 size; /* size of the message w/o header */ - __u8 version; /* message payload version */ + __u8 version; /* message payload version */ __u8 type; /* message type */ __u8 reserved[4]; /* pad to 64 bit */ }; @@ -372,8 +389,7 @@ struct lkd_fw_comms_desc { char cur_fw_ver[VERSION_MAX_LEN]; /* can be used for 1 more version w/o ABI change */ char reserved0[VERSION_MAX_LEN]; - /* address for next FW component load */ - __le64 img_addr; + __le64 img_addr; /* address for next FW component load */ }; enum comms_reset_cause { @@ -382,10 +398,11 @@ enum comms_reset_cause { HL_RESET_CAUSE_TDR = 2, }; -#define RESET_CAUSE_PADDING 7 +/* TODO: remove define after struct name is aligned on all projects */ +#define lkd_msg_comms lkd_fw_comms_msg /* this is the comms message descriptor */ -struct lkd_msg_comms { +struct lkd_fw_comms_msg { struct comms_msg_header header; /* union for future expantions of new messages */ union { @@ -400,7 +417,6 @@ struct lkd_msg_comms { }; struct { __u8 reset_cause; - __u8 reserved[RESET_CAUSE_PADDING]; /* 64 bit pad */ }; }; }; @@ -474,7 +490,7 @@ enum comms_cmd { struct comms_command { union { /* bit fields are only for FW use */ struct { - u32 size :25; /* 32MB max. */ + u32 size :25; /* 32MB max. */ u32 reserved :2; enum comms_cmd cmd :5; /* 32 commands */ }; diff --git a/drivers/misc/habanalabs/include/gaudi/gaudi_fw_if.h b/drivers/misc/habanalabs/include/gaudi/gaudi_fw_if.h index a4afb984d0ae..34ca4fe50d91 100644 --- a/drivers/misc/habanalabs/include/gaudi/gaudi_fw_if.h +++ b/drivers/misc/habanalabs/include/gaudi/gaudi_fw_if.h @@ -20,6 +20,9 @@ #define UBOOT_FW_OFFSET 0x100000 /* 1MB in SRAM */ #define LINUX_FW_OFFSET 0x800000 /* 8MB in HBM */ +/* HBM thermal delta in [Deg] added to composite (CTemp) */ +#define HBM_TEMP_ADJUST_COEFF 6 + enum gaudi_nic_axi_error { RXB, RXE, @@ -56,6 +59,8 @@ struct eq_nic_sei_event { * @pcs_link: has PCS link. * @phy_ready: is PHY ready. * @auto_neg: is Autoneg enabled. + * @timeout_retransmission_cnt: timeout retransmission events + * @high_ber_cnt: high ber events */ struct gaudi_nic_status { __u32 port; @@ -69,6 +74,8 @@ struct gaudi_nic_status { __u8 pcs_link; __u8 phy_ready; __u8 auto_neg; + __u32 timeout_retransmission_cnt; + __u32 high_ber_cnt; }; struct gaudi_flops_2_data { -- cgit v1.2.3 From a39725819c816c87c6b4eeca4c10197a41e2a928 Mon Sep 17 00:00:00 2001 From: Ofir Bitton Date: Mon, 24 May 2021 22:58:44 +0300 Subject: habanalabs/gaudi: don't use disabled ports in collective wait In the collective wait, we put jobs on the QMANs of all the NICs. The code takes into account if a port is disabled only in case of PCI card. When this info arrives from the f/w, the code doesn't take it into account, and it tries to schedule jobs on NICs that aren't enabled and thats a bug. To fix this, after the f/w sends us the list of disabled ports, we update the state of the QMANs according to that list. In addition, we need to update the HW_CAP bits so the collective wait operation will not try to use those QMANs. We also need to update the collective master monitor mask. Moreover, we need to add a protection for such future cases and in case the user will try to submit work to those QMANs. Signed-off-by: Ofir Bitton Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/gaudi/gaudi.c | 219 +++++++++++----------------------- 1 file changed, 71 insertions(+), 148 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index ee1ab7190e46..476dbe6a0bce 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -1000,9 +1000,27 @@ static void gaudi_sob_group_reset_error(struct kref *ref) hw_sob_group->base_sob_id); } +static void gaudi_collective_mstr_sob_mask_set(struct gaudi_device *gaudi) +{ + struct gaudi_collective_properties *prop; + int i; + + prop = &gaudi->collective_props; + + memset(prop->mstr_sob_mask, 0, sizeof(prop->mstr_sob_mask)); + + for (i = 0 ; i < NIC_NUMBER_OF_ENGINES ; i++) + if (gaudi->hw_cap_initialized & BIT(HW_CAP_NIC_SHIFT + i)) + prop->mstr_sob_mask[i / HL_MAX_SOBS_PER_MONITOR] |= + BIT(i % HL_MAX_SOBS_PER_MONITOR); + /* Set collective engine bit */ + prop->mstr_sob_mask[i / HL_MAX_SOBS_PER_MONITOR] |= + BIT(i % HL_MAX_SOBS_PER_MONITOR); +} + static int gaudi_collective_init(struct hl_device *hdev) { - u32 i, master_monitor_sobs, sob_id, reserved_sobs_per_group; + u32 i, sob_id, reserved_sobs_per_group; struct gaudi_collective_properties *prop; struct gaudi_device *gaudi; @@ -1028,22 +1046,7 @@ static int gaudi_collective_init(struct hl_device *hdev) gaudi_collective_map_sobs(hdev, i); } - prop->mstr_sob_mask[0] = 0; - master_monitor_sobs = HL_MAX_SOBS_PER_MONITOR; - for (i = 0 ; i < master_monitor_sobs ; i++) - if (gaudi->hw_cap_initialized & BIT(HW_CAP_NIC_SHIFT + i)) - prop->mstr_sob_mask[0] |= BIT(i); - - prop->mstr_sob_mask[1] = 0; - master_monitor_sobs = - NIC_NUMBER_OF_ENGINES - HL_MAX_SOBS_PER_MONITOR; - for (i = 0 ; i < master_monitor_sobs; i++) { - if (gaudi->hw_cap_initialized & BIT(HW_CAP_NIC_SHIFT + i)) - prop->mstr_sob_mask[1] |= BIT(i); - } - - /* Set collective engine bit */ - prop->mstr_sob_mask[1] |= BIT(i); + gaudi_collective_mstr_sob_mask_set(gaudi); return 0; } @@ -4272,8 +4275,8 @@ static void gaudi_ring_doorbell(struct hl_device *hdev, u32 hw_queue_id, u32 pi) &hdev->fw_loader.dynamic_loader.comm_desc.cpu_dyn_regs; u32 db_reg_offset, db_value, dma_qm_offset, q_off, irq_handler_offset; struct gaudi_device *gaudi = hdev->asic_specific; - int dma_id; bool invalid_queue = false; + int dma_id; switch (hw_queue_id) { case GAUDI_QUEUE_ID_DMA_0_0...GAUDI_QUEUE_ID_DMA_0_3: @@ -4499,164 +4502,84 @@ static void gaudi_ring_doorbell(struct hl_device *hdev, u32 hw_queue_id, u32 pi) db_reg_offset = mmTPC7_QM_PQ_PI_3; break; - case GAUDI_QUEUE_ID_NIC_0_0: - db_reg_offset = mmNIC0_QM0_PQ_PI_0; - break; - - case GAUDI_QUEUE_ID_NIC_0_1: - db_reg_offset = mmNIC0_QM0_PQ_PI_1; - break; - - case GAUDI_QUEUE_ID_NIC_0_2: - db_reg_offset = mmNIC0_QM0_PQ_PI_2; - break; - - case GAUDI_QUEUE_ID_NIC_0_3: - db_reg_offset = mmNIC0_QM0_PQ_PI_3; - break; - - case GAUDI_QUEUE_ID_NIC_1_0: - db_reg_offset = mmNIC0_QM1_PQ_PI_0; - break; - - case GAUDI_QUEUE_ID_NIC_1_1: - db_reg_offset = mmNIC0_QM1_PQ_PI_1; - break; - - case GAUDI_QUEUE_ID_NIC_1_2: - db_reg_offset = mmNIC0_QM1_PQ_PI_2; - break; - - case GAUDI_QUEUE_ID_NIC_1_3: - db_reg_offset = mmNIC0_QM1_PQ_PI_3; - break; - - case GAUDI_QUEUE_ID_NIC_2_0: - db_reg_offset = mmNIC1_QM0_PQ_PI_0; - break; - - case GAUDI_QUEUE_ID_NIC_2_1: - db_reg_offset = mmNIC1_QM0_PQ_PI_1; - break; - - case GAUDI_QUEUE_ID_NIC_2_2: - db_reg_offset = mmNIC1_QM0_PQ_PI_2; - break; - - case GAUDI_QUEUE_ID_NIC_2_3: - db_reg_offset = mmNIC1_QM0_PQ_PI_3; - break; - - case GAUDI_QUEUE_ID_NIC_3_0: - db_reg_offset = mmNIC1_QM1_PQ_PI_0; - break; - - case GAUDI_QUEUE_ID_NIC_3_1: - db_reg_offset = mmNIC1_QM1_PQ_PI_1; - break; - - case GAUDI_QUEUE_ID_NIC_3_2: - db_reg_offset = mmNIC1_QM1_PQ_PI_2; - break; - - case GAUDI_QUEUE_ID_NIC_3_3: - db_reg_offset = mmNIC1_QM1_PQ_PI_3; - break; - - case GAUDI_QUEUE_ID_NIC_4_0: - db_reg_offset = mmNIC2_QM0_PQ_PI_0; - break; - - case GAUDI_QUEUE_ID_NIC_4_1: - db_reg_offset = mmNIC2_QM0_PQ_PI_1; - break; - - case GAUDI_QUEUE_ID_NIC_4_2: - db_reg_offset = mmNIC2_QM0_PQ_PI_2; - break; + case GAUDI_QUEUE_ID_NIC_0_0...GAUDI_QUEUE_ID_NIC_0_3: + if (!(gaudi->hw_cap_initialized & HW_CAP_NIC0)) + invalid_queue = true; - case GAUDI_QUEUE_ID_NIC_4_3: - db_reg_offset = mmNIC2_QM0_PQ_PI_3; + q_off = ((hw_queue_id - 1) & 0x3) * 4; + db_reg_offset = mmNIC0_QM0_PQ_PI_0 + q_off; break; - case GAUDI_QUEUE_ID_NIC_5_0: - db_reg_offset = mmNIC2_QM1_PQ_PI_0; - break; + case GAUDI_QUEUE_ID_NIC_1_0...GAUDI_QUEUE_ID_NIC_1_3: + if (!(gaudi->hw_cap_initialized & HW_CAP_NIC1)) + invalid_queue = true; - case GAUDI_QUEUE_ID_NIC_5_1: - db_reg_offset = mmNIC2_QM1_PQ_PI_1; + q_off = ((hw_queue_id - 1) & 0x3) * 4; + db_reg_offset = mmNIC0_QM1_PQ_PI_0 + q_off; break; - case GAUDI_QUEUE_ID_NIC_5_2: - db_reg_offset = mmNIC2_QM1_PQ_PI_2; - break; + case GAUDI_QUEUE_ID_NIC_2_0...GAUDI_QUEUE_ID_NIC_2_3: + if (!(gaudi->hw_cap_initialized & HW_CAP_NIC2)) + invalid_queue = true; - case GAUDI_QUEUE_ID_NIC_5_3: - db_reg_offset = mmNIC2_QM1_PQ_PI_3; + q_off = ((hw_queue_id - 1) & 0x3) * 4; + db_reg_offset = mmNIC1_QM0_PQ_PI_0 + q_off; break; - case GAUDI_QUEUE_ID_NIC_6_0: - db_reg_offset = mmNIC3_QM0_PQ_PI_0; - break; - - case GAUDI_QUEUE_ID_NIC_6_1: - db_reg_offset = mmNIC3_QM0_PQ_PI_1; - break; + case GAUDI_QUEUE_ID_NIC_3_0...GAUDI_QUEUE_ID_NIC_3_3: + if (!(gaudi->hw_cap_initialized & HW_CAP_NIC3)) + invalid_queue = true; - case GAUDI_QUEUE_ID_NIC_6_2: - db_reg_offset = mmNIC3_QM0_PQ_PI_2; + q_off = ((hw_queue_id - 1) & 0x3) * 4; + db_reg_offset = mmNIC1_QM1_PQ_PI_0 + q_off; break; - case GAUDI_QUEUE_ID_NIC_6_3: - db_reg_offset = mmNIC3_QM0_PQ_PI_3; - break; + case GAUDI_QUEUE_ID_NIC_4_0...GAUDI_QUEUE_ID_NIC_4_3: + if (!(gaudi->hw_cap_initialized & HW_CAP_NIC4)) + invalid_queue = true; - case GAUDI_QUEUE_ID_NIC_7_0: - db_reg_offset = mmNIC3_QM1_PQ_PI_0; + q_off = ((hw_queue_id - 1) & 0x3) * 4; + db_reg_offset = mmNIC2_QM0_PQ_PI_0 + q_off; break; - case GAUDI_QUEUE_ID_NIC_7_1: - db_reg_offset = mmNIC3_QM1_PQ_PI_1; - break; + case GAUDI_QUEUE_ID_NIC_5_0...GAUDI_QUEUE_ID_NIC_5_3: + if (!(gaudi->hw_cap_initialized & HW_CAP_NIC5)) + invalid_queue = true; - case GAUDI_QUEUE_ID_NIC_7_2: - db_reg_offset = mmNIC3_QM1_PQ_PI_2; + q_off = ((hw_queue_id - 1) & 0x3) * 4; + db_reg_offset = mmNIC2_QM1_PQ_PI_0 + q_off; break; - case GAUDI_QUEUE_ID_NIC_7_3: - db_reg_offset = mmNIC3_QM1_PQ_PI_3; - break; - - case GAUDI_QUEUE_ID_NIC_8_0: - db_reg_offset = mmNIC4_QM0_PQ_PI_0; - break; + case GAUDI_QUEUE_ID_NIC_6_0...GAUDI_QUEUE_ID_NIC_6_3: + if (!(gaudi->hw_cap_initialized & HW_CAP_NIC6)) + invalid_queue = true; - case GAUDI_QUEUE_ID_NIC_8_1: - db_reg_offset = mmNIC4_QM0_PQ_PI_1; + q_off = ((hw_queue_id - 1) & 0x3) * 4; + db_reg_offset = mmNIC3_QM0_PQ_PI_0 + q_off; break; - case GAUDI_QUEUE_ID_NIC_8_2: - db_reg_offset = mmNIC4_QM0_PQ_PI_2; - break; + case GAUDI_QUEUE_ID_NIC_7_0...GAUDI_QUEUE_ID_NIC_7_3: + if (!(gaudi->hw_cap_initialized & HW_CAP_NIC7)) + invalid_queue = true; - case GAUDI_QUEUE_ID_NIC_8_3: - db_reg_offset = mmNIC4_QM0_PQ_PI_3; + q_off = ((hw_queue_id - 1) & 0x3) * 4; + db_reg_offset = mmNIC3_QM1_PQ_PI_0 + q_off; break; - case GAUDI_QUEUE_ID_NIC_9_0: - db_reg_offset = mmNIC4_QM1_PQ_PI_0; - break; + case GAUDI_QUEUE_ID_NIC_8_0...GAUDI_QUEUE_ID_NIC_8_3: + if (!(gaudi->hw_cap_initialized & HW_CAP_NIC8)) + invalid_queue = true; - case GAUDI_QUEUE_ID_NIC_9_1: - db_reg_offset = mmNIC4_QM1_PQ_PI_1; + q_off = ((hw_queue_id - 1) & 0x3) * 4; + db_reg_offset = mmNIC4_QM0_PQ_PI_0 + q_off; break; - case GAUDI_QUEUE_ID_NIC_9_2: - db_reg_offset = mmNIC4_QM1_PQ_PI_2; - break; + case GAUDI_QUEUE_ID_NIC_9_0...GAUDI_QUEUE_ID_NIC_9_3: + if (!(gaudi->hw_cap_initialized & HW_CAP_NIC9)) + invalid_queue = true; - case GAUDI_QUEUE_ID_NIC_9_3: - db_reg_offset = mmNIC4_QM1_PQ_PI_3; + q_off = ((hw_queue_id - 1) & 0x3) * 4; + db_reg_offset = mmNIC4_QM1_PQ_PI_0 + q_off; break; default: -- cgit v1.2.3 From 254fac6d1a73aac40aa4d423c993965987728040 Mon Sep 17 00:00:00 2001 From: Ofir Bitton Date: Wed, 2 Jun 2021 11:56:31 +0300 Subject: habanalabs/gaudi: add FW alive event support In order for driver to be aware of process or thread crashes inside GAUDI's CPU, we introduce a new event which contains all relevant information. Upon event reception, driver will dump information and will reset the device. Signed-off-by: Ofir Bitton Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/gaudi/gaudi.c | 15 +++++++++++++++ drivers/misc/habanalabs/include/common/cpucp_if.h | 15 +++++++++++++++ .../misc/habanalabs/include/gaudi/gaudi_async_events.h | 1 + .../include/gaudi/gaudi_async_ids_map_extended.h | 2 +- 4 files changed, 32 insertions(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 476dbe6a0bce..953c5a50c70b 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -7451,6 +7451,16 @@ static void gaudi_print_out_of_sync_info(struct hl_device *hdev, sync_err->pi, sync_err->ci, q->pi, atomic_read(&q->ci)); } +static void gaudi_print_fw_alive_info(struct hl_device *hdev, + struct hl_eq_fw_alive *fw_alive) +{ + dev_err(hdev->dev, + "FW alive report: severity=%s, process_id=%u, thread_id=%u, uptime=%llu seconds\n", + (fw_alive->severity == FW_ALIVE_SEVERITY_MINOR) ? + "Minor" : "Critical", fw_alive->process_id, + fw_alive->thread_id, fw_alive->uptime_seconds); +} + static int gaudi_soft_reset_late_init(struct hl_device *hdev) { struct gaudi_device *gaudi = hdev->asic_specific; @@ -7902,6 +7912,11 @@ static void gaudi_handle_eqe(struct hl_device *hdev, gaudi_print_out_of_sync_info(hdev, &eq_entry->pkt_sync_err); goto reset_device; + case GAUDI_EVENT_FW_ALIVE_S: + gaudi_print_irq_info(hdev, event_type, false); + gaudi_print_fw_alive_info(hdev, &eq_entry->fw_alive); + goto reset_device; + default: dev_err(hdev->dev, "Received invalid H/W interrupt %d\n", event_type); diff --git a/drivers/misc/habanalabs/include/common/cpucp_if.h b/drivers/misc/habanalabs/include/common/cpucp_if.h index c7da62243619..d4dc189a6c92 100644 --- a/drivers/misc/habanalabs/include/common/cpucp_if.h +++ b/drivers/misc/habanalabs/include/common/cpucp_if.h @@ -84,6 +84,20 @@ struct hl_eq_sm_sei_data { __u8 pad[3]; }; +enum hl_fw_alive_severity { + FW_ALIVE_SEVERITY_MINOR, + FW_ALIVE_SEVERITY_CRITICAL +}; + +struct hl_eq_fw_alive { + __le64 uptime_seconds; + __le32 process_id; + __le32 thread_id; + /* enum hl_fw_alive_severity */ + __u8 severity; + __u8 pad[7]; +}; + struct hl_eq_entry { struct hl_eq_header hdr; union { @@ -91,6 +105,7 @@ struct hl_eq_entry { struct hl_eq_hbm_ecc_data hbm_ecc_data; struct hl_eq_sm_sei_data sm_sei_data; struct cpucp_pkt_sync_err pkt_sync_err; + struct hl_eq_fw_alive fw_alive; __le64 data[7]; }; }; diff --git a/drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h b/drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h index e8651abf84f2..f66c759952e4 100644 --- a/drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h +++ b/drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h @@ -303,6 +303,7 @@ enum gaudi_async_event_id { GAUDI_EVENT_NIC3_QP1 = 619, GAUDI_EVENT_NIC4_QP0 = 620, GAUDI_EVENT_NIC4_QP1 = 621, + GAUDI_EVENT_FW_ALIVE_S = 645, GAUDI_EVENT_DEV_RESET_REQ = 646, GAUDI_EVENT_PKT_QUEUE_OUT_SYNC = 647, GAUDI_EVENT_FIX_POWER_ENV_S = 658, diff --git a/drivers/misc/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h b/drivers/misc/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h index 3dc79c131805..e87554ab0102 100644 --- a/drivers/misc/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h +++ b/drivers/misc/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h @@ -669,7 +669,7 @@ static struct gaudi_async_events_ids_map gaudi_irq_map_table[] = { { .fc_id = 642, .cpu_id = 491, .valid = 0, .name = "" }, { .fc_id = 643, .cpu_id = 492, .valid = 0, .name = "" }, { .fc_id = 644, .cpu_id = 493, .valid = 0, .name = "" }, - { .fc_id = 645, .cpu_id = 494, .valid = 0, .name = "" }, + { .fc_id = 645, .cpu_id = 494, .valid = 1, .name = "FW_ALIVE_S" }, { .fc_id = 646, .cpu_id = 495, .valid = 1, .name = "DEV_RESET_REQ" }, { .fc_id = 647, .cpu_id = 496, .valid = 1, .name = "PKT_QUEUE_OUT_SYNC" }, -- cgit v1.2.3 From 8e8125f192288802267157f613c0ca654dfbde8e Mon Sep 17 00:00:00 2001 From: Yuri Nudelman Date: Tue, 25 May 2021 14:49:52 +0300 Subject: habanalabs: add debug flag to prevent failure on timeout Sometimes it is useful to allow the command to continue running despite the timeout occurred, to differentiate between really stuck or just very time consuming commands. This can be achieved by passing a new debug flag alongside the cs, HL_CS_FLAGS_SKIP_RESET_ON_TIMEOUT. Anyway, if the timeout occurred, a warning print shall be issued, however this shall not fail the submission. Signed-off-by: Yuri Nudelman Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- .../misc/habanalabs/common/command_submission.c | 25 +++++++++++++++++----- drivers/misc/habanalabs/common/habanalabs.h | 5 +++++ include/uapi/misc/habanalabs.h | 1 + 3 files changed, 26 insertions(+), 5 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/command_submission.c b/drivers/misc/habanalabs/common/command_submission.c index ecd96fbe3150..6d51f54030c1 100644 --- a/drivers/misc/habanalabs/common/command_submission.c +++ b/drivers/misc/habanalabs/common/command_submission.c @@ -556,6 +556,13 @@ out: else if (!cs->submitted) cs->fence->error = -EBUSY; + if (unlikely(cs->skip_reset_on_timeout)) { + dev_err(hdev->dev, + "Command submission %llu completed after %llu (s)\n", + cs->sequence, + div_u64(jiffies - cs->submission_time_jiffies, HZ)); + } + if (cs->timestamp) cs->fence->timestamp = ktime_get(); complete_all(&cs->fence->completion); @@ -571,6 +578,8 @@ static void cs_timedout(struct work_struct *work) int rc; struct hl_cs *cs = container_of(work, struct hl_cs, work_tdr.work); + bool skip_reset_on_timeout = cs->skip_reset_on_timeout; + rc = cs_get_unless_zero(cs); if (!rc) return; @@ -581,7 +590,8 @@ static void cs_timedout(struct work_struct *work) } /* Mark the CS is timed out so we won't try to cancel its TDR */ - cs->timedout = true; + if (likely(!skip_reset_on_timeout)) + cs->timedout = true; hdev = cs->ctx->hdev; @@ -613,10 +623,12 @@ static void cs_timedout(struct work_struct *work) cs_put(cs); - if (hdev->reset_on_lockup) - hl_device_reset(hdev, HL_RESET_TDR); - else - hdev->needs_reset = true; + if (likely(!skip_reset_on_timeout)) { + if (hdev->reset_on_lockup) + hl_device_reset(hdev, HL_RESET_TDR); + else + hdev->needs_reset = true; + } } static int allocate_cs(struct hl_device *hdev, struct hl_ctx *ctx, @@ -650,6 +662,9 @@ static int allocate_cs(struct hl_device *hdev, struct hl_ctx *ctx, cs->type = cs_type; cs->timestamp = !!(flags & HL_CS_FLAGS_TIMESTAMP); cs->timeout_jiffies = timeout; + cs->skip_reset_on_timeout = + !!(flags & HL_CS_FLAGS_SKIP_RESET_ON_TIMEOUT); + cs->submission_time_jiffies = jiffies; INIT_LIST_HEAD(&cs->job_list); INIT_DELAYED_WORK(&cs->work_tdr, cs_timedout); kref_init(&cs->refcount); diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index e751868b3ed3..56d2f41f8893 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -1421,6 +1421,7 @@ struct hl_userptr { * @staged_sequence: the sequence of the staged submission this CS is part of, * relevant only if staged_cs is set. * @timeout_jiffies: cs timeout in jiffies. + * @submission_time_jiffies: submission time of the cs * @type: CS_TYPE_*. * @submitted: true if CS was submitted to H/W. * @completed: true if CS was completed by device. @@ -1433,6 +1434,8 @@ struct hl_userptr { * @staged_first: true if this is the first staged CS and we need to receive * timeout for this CS. * @staged_cs: true if this CS is part of a staged submission. + * @skip_reset_on_timeout: true if we shall not reset the device in case + * timeout occurs (debug scenario). */ struct hl_cs { u16 *jobs_in_queue_cnt; @@ -1450,6 +1453,7 @@ struct hl_cs { u64 sequence; u64 staged_sequence; u64 timeout_jiffies; + u64 submission_time_jiffies; enum hl_cs_type type; u8 submitted; u8 completed; @@ -1460,6 +1464,7 @@ struct hl_cs { u8 staged_last; u8 staged_first; u8 staged_cs; + u8 skip_reset_on_timeout; }; /** diff --git a/include/uapi/misc/habanalabs.h b/include/uapi/misc/habanalabs.h index 6d2d34c9f375..a47485a8d411 100644 --- a/include/uapi/misc/habanalabs.h +++ b/include/uapi/misc/habanalabs.h @@ -664,6 +664,7 @@ struct hl_cs_chunk { #define HL_CS_FLAGS_STAGED_SUBMISSION_FIRST 0x80 #define HL_CS_FLAGS_STAGED_SUBMISSION_LAST 0x100 #define HL_CS_FLAGS_CUSTOM_TIMEOUT 0x200 +#define HL_CS_FLAGS_SKIP_RESET_ON_TIMEOUT 0x400 #define HL_CS_STATUS_SUCCESS 0 -- cgit v1.2.3 From 84586de496103453c0c8dbf5c233f10381644cf5 Mon Sep 17 00:00:00 2001 From: Ofir Bitton Date: Thu, 20 May 2021 13:30:31 +0300 Subject: habanalabs: reset device upon FD close if not idle If device is not idle after user closes the FD we must reset device as next user that will try to open FD will encounter a non-functional device. Signed-off-by: Ofir Bitton Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/context.c | 9 --------- drivers/misc/habanalabs/common/device.c | 20 +++++++++++++++++--- drivers/misc/habanalabs/common/habanalabs.h | 1 + drivers/misc/habanalabs/common/habanalabs_drv.c | 1 + 4 files changed, 19 insertions(+), 12 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/context.c b/drivers/misc/habanalabs/common/context.c index 62d705889ca8..19b6b045219e 100644 --- a/drivers/misc/habanalabs/common/context.c +++ b/drivers/misc/habanalabs/common/context.c @@ -12,7 +12,6 @@ static void hl_ctx_fini(struct hl_ctx *ctx) { struct hl_device *hdev = ctx->hdev; - u64 idle_mask[HL_BUSY_ENGINES_MASK_EXT_SIZE] = {0}; int i; /* Release all allocated pending cb's, those cb's were never @@ -57,14 +56,6 @@ static void hl_ctx_fini(struct hl_ctx *ctx) /* Scrub both SRAM and DRAM */ hdev->asic_funcs->scrub_device_mem(hdev, 0, 0); - - if ((!hdev->pldm) && (hdev->pdev) && - (!hdev->asic_funcs->is_device_idle(hdev, - idle_mask, - HL_BUSY_ENGINES_MASK_EXT_SIZE, NULL))) - dev_notice(hdev->dev, - "device not idle after user context is closed (0x%llx, 0x%llx)\n", - idle_mask[0], idle_mask[1]); } else { dev_dbg(hdev->dev, "closing kernel context\n"); hdev->asic_funcs->ctx_fini(ctx); diff --git a/drivers/misc/habanalabs/common/device.c b/drivers/misc/habanalabs/common/device.c index bc58a91bf50a..0056282cec94 100644 --- a/drivers/misc/habanalabs/common/device.c +++ b/drivers/misc/habanalabs/common/device.c @@ -51,6 +51,8 @@ bool hl_device_operational(struct hl_device *hdev, static void hpriv_release(struct kref *ref) { + u64 idle_mask[HL_BUSY_ENGINES_MASK_EXT_SIZE] = {0}; + bool device_is_idle = true; struct hl_fpriv *hpriv; struct hl_device *hdev; @@ -71,7 +73,19 @@ static void hpriv_release(struct kref *ref) kfree(hpriv); - if (hdev->reset_upon_device_release) + if ((!hdev->pldm) && (hdev->pdev) && + (!hdev->asic_funcs->is_device_idle(hdev, + idle_mask, + HL_BUSY_ENGINES_MASK_EXT_SIZE, NULL))) { + dev_err(hdev->dev, + "device not idle after user context is closed (0x%llx_%llx)\n", + idle_mask[1], idle_mask[0]); + + device_is_idle = false; + } + + if ((hdev->reset_if_device_not_idle && !device_is_idle) + || hdev->reset_upon_device_release) hl_device_reset(hdev, 0); } @@ -1108,8 +1122,8 @@ kill_processes: if (!hdev->asic_funcs->is_device_idle(hdev, idle_mask, HL_BUSY_ENGINES_MASK_EXT_SIZE, NULL)) { dev_err(hdev->dev, - "device is not idle (mask %#llx %#llx) after reset\n", - idle_mask[0], idle_mask[1]); + "device is not idle (mask 0x%llx_%llx) after reset\n", + idle_mask[1], idle_mask[0]); rc = -EIO; goto out_err; } diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index 56d2f41f8893..bcb5bfdd7f20 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -2311,6 +2311,7 @@ struct hl_device { u8 rl_enable; u8 reset_on_preboot_fail; u8 reset_upon_device_release; + u8 reset_if_device_not_idle; }; diff --git a/drivers/misc/habanalabs/common/habanalabs_drv.c b/drivers/misc/habanalabs/common/habanalabs_drv.c index 137e7dc63d3b..b55dd1c55166 100644 --- a/drivers/misc/habanalabs/common/habanalabs_drv.c +++ b/drivers/misc/habanalabs/common/habanalabs_drv.c @@ -264,6 +264,7 @@ static void set_driver_behavior_per_device(struct hl_device *hdev) hdev->bmc_enable = 1; hdev->hard_reset_on_fw_events = 1; hdev->reset_on_preboot_fail = 1; + hdev->reset_if_device_not_idle = 1; hdev->reset_pcilink = 0; hdev->axi_drain = 0; -- cgit v1.2.3 From 6a785e368a675008dc7a09938480a07ac1aa8956 Mon Sep 17 00:00:00 2001 From: Ohad Sharabi Date: Sat, 29 May 2021 23:26:10 +0300 Subject: habanalabs: skip valid test for boot_dev_sts regs Get rid of the need to check if boot_dev_sts is valid on every access to value read from these registers. This is done by storing the register value in hdev props ONLY if register is enabled. This way if register is NOT enabled all capability bits will not be set. Signed-off-by: Ohad Sharabi Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 56 +++++++++++++++------------- drivers/misc/habanalabs/gaudi/gaudi.c | 25 +++++-------- 2 files changed, 40 insertions(+), 41 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index 40e91985cb48..9412e6707906 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -216,9 +216,7 @@ int hl_fw_send_cpu_message(struct hl_device *hdev, u32 hw_queue_id, u32 *msg, goto out; } - if (prop->fw_cpu_boot_dev_sts0_valid && - (prop->fw_app_cpu_boot_dev_sts0 & - CPU_BOOT_DEV_STS0_PKT_PI_ACK_EN)) + if (prop->fw_app_cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_PKT_PI_ACK_EN) expected_ack_val = queue->pi; else expected_ack_val = CPUCP_PACKET_FENCE_VAL; @@ -838,8 +836,8 @@ int get_used_pll_index(struct hl_device *hdev, u32 input_pll_index, bool dynamic_pll; int fw_pll_idx; - dynamic_pll = prop->fw_cpu_boot_dev_sts0_valid && - (prop->fw_app_cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_DYN_PLL_EN); + dynamic_pll = !!(prop->fw_app_cpu_boot_dev_sts0 & + CPU_BOOT_DEV_STS0_DYN_PLL_EN); if (!dynamic_pll) { /* @@ -988,7 +986,7 @@ static int hl_fw_read_preboot_caps(struct hl_device *hdev, u32 timeout) { struct asic_fixed_properties *prop = &hdev->asic_prop; - u32 status; + u32 status, reg_val; int rc; /* Need to check two possible scenarios: @@ -1026,14 +1024,30 @@ static int hl_fw_read_preboot_caps(struct hl_device *hdev, return -EIO; } - prop->fw_preboot_cpu_boot_dev_sts0 = RREG32(sts_boot_dev_sts0_reg); - prop->fw_preboot_cpu_boot_dev_sts1 = RREG32(sts_boot_dev_sts1_reg); + /* + * the registers DEV_STS* contain FW capabilities/features. + * We can rely on this registers only if bit CPU_BOOT_DEV_STS*_ENABLED + * is set. + * In the first read of this register we store the value of this + * register ONLY if the register is enabled (which will be propagated + * to next stages) and also mark the register as valid. + * In case it is not enabled the stored value will be left 0- all + * caps/features are off + */ + reg_val = RREG32(sts_boot_dev_sts0_reg); + if (reg_val & CPU_BOOT_DEV_STS0_ENABLED) { + prop->fw_cpu_boot_dev_sts0_valid = true; + prop->fw_preboot_cpu_boot_dev_sts0 = reg_val; + } - if (prop->fw_preboot_cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_ENABLED) - prop->dynamic_fw_load = !!(prop->fw_preboot_cpu_boot_dev_sts0 & + reg_val = RREG32(sts_boot_dev_sts1_reg); + if (reg_val & CPU_BOOT_DEV_STS1_ENABLED) { + prop->fw_cpu_boot_dev_sts1_valid = true; + prop->fw_preboot_cpu_boot_dev_sts1 = reg_val; + } + + prop->dynamic_fw_load = !!(prop->fw_preboot_cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_FW_LD_COM_EN); - else - prop->dynamic_fw_load = 0; /* initialize FW loader once we know what load protocol is used */ hdev->asic_funcs->init_firmware_loader(hdev); @@ -1105,7 +1119,7 @@ static void hl_fw_preboot_update_state(struct hl_device *hdev) cpu_boot_dev_sts0 = prop->fw_preboot_cpu_boot_dev_sts0; cpu_boot_dev_sts1 = prop->fw_preboot_cpu_boot_dev_sts1; - /* We read security status multiple times during boot: + /* We read boot_dev_sts registers multiple times during boot: * 1. preboot - a. Check whether the security status bits are valid * b. Check whether fw security is enabled * c. Check whether hard reset is done by preboot @@ -1119,18 +1133,8 @@ static void hl_fw_preboot_update_state(struct hl_device *hdev) * check security enabled bit (CPU_BOOT_DEV_STS0_SECURITY_EN) * If set, then mark GIC controller to be disabled. */ - if (cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_ENABLED) { - prop->fw_cpu_boot_dev_sts0_valid = 1; - - if (cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_FW_HARD_RST_EN) - prop->hard_reset_done_by_fw = true; - } else { - prop->fw_cpu_boot_dev_sts0_valid = 0; - } - - /* place holder for STS1 as no statuses are defined yet */ - prop->fw_cpu_boot_dev_sts1_valid = - !!(cpu_boot_dev_sts1 & CPU_BOOT_DEV_STS1_ENABLED); + prop->hard_reset_done_by_fw = + !!(cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_FW_HARD_RST_EN); dev_dbg(hdev->dev, "Firmware preboot boot device status0 %#x\n", cpu_boot_dev_sts0); @@ -1781,7 +1785,7 @@ static void hl_fw_boot_fit_update_state(struct hl_device *hdev, prop->hard_reset_done_by_fw = false; /* Read boot_cpu status bits */ - if (prop->fw_cpu_boot_dev_sts0_valid) { + if (prop->fw_preboot_cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_ENABLED) { prop->fw_bootfit_cpu_boot_dev_sts0 = RREG32(cpu_boot_dev_sts0_reg); diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 953c5a50c70b..703f41488852 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -1980,9 +1980,8 @@ static void gaudi_init_scrambler_sram(struct hl_device *hdev) if (hdev->asic_prop.fw_security_enabled) return; - if (hdev->asic_prop.fw_cpu_boot_dev_sts0_valid && - (hdev->asic_prop.fw_app_cpu_boot_dev_sts0 & - CPU_BOOT_DEV_STS0_SRAM_SCR_EN)) + if (hdev->asic_prop.fw_app_cpu_boot_dev_sts0 & + CPU_BOOT_DEV_STS0_SRAM_SCR_EN) return; if (gaudi->hw_cap_initialized & HW_CAP_SRAM_SCRAMBLER) @@ -2052,9 +2051,8 @@ static void gaudi_init_scrambler_hbm(struct hl_device *hdev) if (hdev->asic_prop.fw_security_enabled) return; - if (hdev->asic_prop.fw_cpu_boot_dev_sts0_valid && - (hdev->asic_prop.fw_bootfit_cpu_boot_dev_sts0 & - CPU_BOOT_DEV_STS0_DRAM_SCR_EN)) + if (hdev->asic_prop.fw_bootfit_cpu_boot_dev_sts0 & + CPU_BOOT_DEV_STS0_DRAM_SCR_EN) return; if (gaudi->hw_cap_initialized & HW_CAP_HBM_SCRAMBLER) @@ -2122,9 +2120,8 @@ static void gaudi_init_e2e(struct hl_device *hdev) if (hdev->asic_prop.fw_security_enabled) return; - if (hdev->asic_prop.fw_cpu_boot_dev_sts0_valid && - (hdev->asic_prop.fw_bootfit_cpu_boot_dev_sts0 & - CPU_BOOT_DEV_STS0_E2E_CRED_EN)) + if (hdev->asic_prop.fw_bootfit_cpu_boot_dev_sts0 & + CPU_BOOT_DEV_STS0_E2E_CRED_EN) return; WREG32(mmSIF_RTR_CTRL_0_E2E_HBM_WR_SIZE, 247 >> 3); @@ -2497,9 +2494,8 @@ static void gaudi_init_hbm_cred(struct hl_device *hdev) if (hdev->asic_prop.fw_security_enabled) return; - if (hdev->asic_prop.fw_cpu_boot_dev_sts0_valid && - (hdev->asic_prop.fw_bootfit_cpu_boot_dev_sts0 & - CPU_BOOT_DEV_STS0_HBM_CRED_EN)) + if (hdev->asic_prop.fw_bootfit_cpu_boot_dev_sts0 & + CPU_BOOT_DEV_STS0_HBM_CRED_EN) return; hbm0_wr = 0x33333333; @@ -7477,9 +7473,8 @@ static int gaudi_hbm_read_interrupts(struct hl_device *hdev, int device, u32 base, val, val2, wr_par, rd_par, ca_par, derr, serr, type, ch; int err = 0; - if (hdev->asic_prop.fw_cpu_boot_dev_sts0_valid && - (hdev->asic_prop.fw_app_cpu_boot_dev_sts0 & - CPU_BOOT_DEV_STS0_HBM_ECC_EN)) { + if (hdev->asic_prop.fw_app_cpu_boot_dev_sts0 & + CPU_BOOT_DEV_STS0_HBM_ECC_EN) { if (!hbm_ecc_data) { dev_err(hdev->dev, "No FW ECC data"); return 0; -- cgit v1.2.3 From 0f37510ca34848718db1003479bb4671e8f3c112 Mon Sep 17 00:00:00 2001 From: Ohad Sharabi Date: Thu, 3 Jun 2021 00:24:32 +0300 Subject: habanalabs: fix mask to obtain page offset When converting virtual address to physical we need to add correct offset to the physical page. For this we need to use mask that include ALL bits of page offset. Signed-off-by: Ohad Sharabi Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/mmu/mmu.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/mmu/mmu.c b/drivers/misc/habanalabs/common/mmu/mmu.c index b37189956b14..792d25b79ea6 100644 --- a/drivers/misc/habanalabs/common/mmu/mmu.c +++ b/drivers/misc/habanalabs/common/mmu/mmu.c @@ -501,12 +501,20 @@ static void hl_mmu_pa_page_with_offset(struct hl_ctx *ctx, u64 virt_addr, if ((hops->range_type == HL_VA_RANGE_TYPE_DRAM) && !is_power_of_2(prop->dram_page_size)) { - u32 bit; + unsigned long dram_page_size = prop->dram_page_size; u64 page_offset_mask; u64 phys_addr_mask; + u32 bit; - bit = __ffs64((u64)prop->dram_page_size); - page_offset_mask = ((1ull << bit) - 1); + /* + * find last set bit in page_size to cover all bits of page + * offset. note that 1 has to be added to bit index. + * note that the internal ulong variable is used to avoid + * alignment issue. + */ + bit = find_last_bit(&dram_page_size, + sizeof(dram_page_size) * BITS_PER_BYTE) + 1; + page_offset_mask = (BIT_ULL(bit) - 1); phys_addr_mask = ~page_offset_mask; *phys_addr = (tmp_phys_addr & phys_addr_mask) | (virt_addr & page_offset_mask); -- cgit v1.2.3 From f1a29770b2158c2c5a4c92cfd57600a6d6062973 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Sun, 6 Jun 2021 11:38:12 +0300 Subject: habanalabs/gaudi: use standard error codes When there is an ECC error in the HBM, return a standard error code, -EIO in this case, and not a positive value. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/gaudi/gaudi.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 703f41488852..9b4bd38c2986 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -7471,7 +7471,7 @@ static int gaudi_hbm_read_interrupts(struct hl_device *hdev, int device, struct hl_eq_hbm_ecc_data *hbm_ecc_data) { u32 base, val, val2, wr_par, rd_par, ca_par, derr, serr, type, ch; - int err = 0; + int rc = 0; if (hdev->asic_prop.fw_app_cpu_boot_dev_sts0 & CPU_BOOT_DEV_STS0_HBM_ECC_EN) { @@ -7516,7 +7516,7 @@ static int gaudi_hbm_read_interrupts(struct hl_device *hdev, int device, val = RREG32_MASK(base + ch * 0x1000 + 0x06C, 0x0000FFFF); val = (val & 0xFF) | ((val >> 8) & 0xFF); if (val) { - err = 1; + rc = -EIO; dev_err(hdev->dev, "HBM%d pc%d interrupts info: WR_PAR=%d, RD_PAR=%d, CA_PAR=%d, SERR=%d, DERR=%d\n", device, ch * 2, val & 0x1, (val >> 1) & 0x1, @@ -7536,7 +7536,7 @@ static int gaudi_hbm_read_interrupts(struct hl_device *hdev, int device, val = RREG32_MASK(base + ch * 0x1000 + 0x07C, 0x0000FFFF); val = (val & 0xFF) | ((val >> 8) & 0xFF); if (val) { - err = 1; + rc = -EIO; dev_err(hdev->dev, "HBM%d pc%d interrupts info: WR_PAR=%d, RD_PAR=%d, CA_PAR=%d, SERR=%d, DERR=%d\n", device, ch * 2 + 1, val & 0x1, (val >> 1) & 0x1, @@ -7565,7 +7565,7 @@ static int gaudi_hbm_read_interrupts(struct hl_device *hdev, int device, val = RREG32(base + 0x8F30); val2 = RREG32(base + 0x8F34); if (val | val2) { - err = 1; + rc = -EIO; dev_err(hdev->dev, "HBM %d MC SRAM SERR info: Reg 0x8F30=0x%x, Reg 0x8F34=0x%x\n", device, val, val2); @@ -7573,13 +7573,13 @@ static int gaudi_hbm_read_interrupts(struct hl_device *hdev, int device, val = RREG32(base + 0x8F40); val2 = RREG32(base + 0x8F44); if (val | val2) { - err = 1; + rc = -EIO; dev_err(hdev->dev, "HBM %d MC SRAM DERR info: Reg 0x8F40=0x%x, Reg 0x8F44=0x%x\n", device, val, val2); } - return err; + return rc; } static int gaudi_hbm_event_to_dev(u16 hbm_event_type) -- cgit v1.2.3 From 12d133deb30d55076efaf7d2fdbce0a9a0ce8501 Mon Sep 17 00:00:00 2001 From: Koby Elbaz Date: Thu, 3 Jun 2021 13:18:20 +0300 Subject: habanalabs: small code refactoring Use datatype defines instead of hard coded values, and rename set_fixed_properties function. Signed-off-by: Koby Elbaz Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/device.c | 2 +- drivers/misc/habanalabs/gaudi/gaudi.c | 6 +++--- drivers/misc/habanalabs/goya/goya.c | 4 ++-- drivers/misc/habanalabs/goya/goyaP.h | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/device.c b/drivers/misc/habanalabs/common/device.c index 0056282cec94..46fcab1bf873 100644 --- a/drivers/misc/habanalabs/common/device.c +++ b/drivers/misc/habanalabs/common/device.c @@ -1395,7 +1395,7 @@ int hl_device_init(struct hl_device *hdev, struct class *hclass) dev_info(hdev->dev, "Found %s device with %lluGB DRAM\n", hdev->asic_name, - hdev->asic_prop.dram_size / 1024 / 1024 / 1024); + hdev->asic_prop.dram_size / SZ_1G); rc = hl_vm_init(hdev); if (rc) { diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 9b4bd38c2986..f8bf30e48bba 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -410,7 +410,7 @@ static inline void set_default_power_values(struct hl_device *hdev) } } -static int gaudi_get_fixed_properties(struct hl_device *hdev) +static int gaudi_set_fixed_properties(struct hl_device *hdev) { struct asic_fixed_properties *prop = &hdev->asic_prop; u32 num_sync_stream_queues = 0; @@ -655,9 +655,9 @@ static int gaudi_early_init(struct hl_device *hdev) u32 fw_boot_status; int rc; - rc = gaudi_get_fixed_properties(hdev); + rc = gaudi_set_fixed_properties(hdev); if (rc) { - dev_err(hdev->dev, "Failed to get fixed properties\n"); + dev_err(hdev->dev, "Failed setting fixed properties\n"); return rc; } diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c index bcefc372a689..6d63930b7a10 100644 --- a/drivers/misc/habanalabs/goya/goya.c +++ b/drivers/misc/habanalabs/goya/goya.c @@ -355,7 +355,7 @@ static int goya_mmu_set_dram_default_page(struct hl_device *hdev); static int goya_mmu_add_mappings_for_device_cpu(struct hl_device *hdev); static void goya_mmu_prepare(struct hl_device *hdev, u32 asid); -int goya_get_fixed_properties(struct hl_device *hdev) +int goya_set_fixed_properties(struct hl_device *hdev) { struct asic_fixed_properties *prop = &hdev->asic_prop; int i; @@ -587,7 +587,7 @@ static int goya_early_init(struct hl_device *hdev) u32 fw_boot_status, val; int rc; - rc = goya_get_fixed_properties(hdev); + rc = goya_set_fixed_properties(hdev); if (rc) { dev_err(hdev->dev, "Failed to get fixed properties\n"); return rc; diff --git a/drivers/misc/habanalabs/goya/goyaP.h b/drivers/misc/habanalabs/goya/goyaP.h index ef8c6c8b5c8d..0b05da614729 100644 --- a/drivers/misc/habanalabs/goya/goyaP.h +++ b/drivers/misc/habanalabs/goya/goyaP.h @@ -168,7 +168,7 @@ struct goya_device { u8 device_cpu_mmu_mappings_done; }; -int goya_get_fixed_properties(struct hl_device *hdev); +int goya_set_fixed_properties(struct hl_device *hdev); int goya_mmu_init(struct hl_device *hdev); void goya_init_dma_qmans(struct hl_device *hdev); void goya_init_mme_qmans(struct hl_device *hdev); -- cgit v1.2.3 From e1222c2794de72f295aa2992ca5eeebd3614183f Mon Sep 17 00:00:00 2001 From: Ohad Sharabi Date: Sun, 6 Jun 2021 22:38:23 +0300 Subject: habanalabs: report EQ fault during heartbeat In case we have EQ fault we would like to know about it. For this, a status bitmask was added in which EQ_FAULT bit is set by FW in case of EQ fault. Signed-off-by: Ohad Sharabi Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 8 +++++++- drivers/misc/habanalabs/include/common/cpucp_if.h | 20 ++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index 9412e6707906..d5a3c786d4c9 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -362,7 +362,7 @@ void hl_fw_cpu_accessible_dma_pool_free(struct hl_device *hdev, size_t size, int hl_fw_send_heartbeat(struct hl_device *hdev) { - struct cpucp_packet hb_pkt = {}; + struct cpucp_packet hb_pkt = {0}; u64 result; int rc; @@ -374,7 +374,13 @@ int hl_fw_send_heartbeat(struct hl_device *hdev) sizeof(hb_pkt), 0, &result); if ((rc) || (result != CPUCP_PACKET_FENCE_VAL)) + return -EIO; + + if (le32_to_cpu(hb_pkt.status_mask) & + CPUCP_PKT_HB_STATUS_EQ_FAULT_MASK) { + dev_warn(hdev->dev, "FW reported EQ fault during heartbeat\n"); rc = -EIO; + } return rc; } diff --git a/drivers/misc/habanalabs/include/common/cpucp_if.h b/drivers/misc/habanalabs/include/common/cpucp_if.h index d4dc189a6c92..80b1d5a9d9f1 100644 --- a/drivers/misc/habanalabs/include/common/cpucp_if.h +++ b/drivers/misc/habanalabs/include/common/cpucp_if.h @@ -404,6 +404,20 @@ enum cpucp_packet_id { #define CPUCP_PKT_RES_PLL_OUT3_SHIFT 48 #define CPUCP_PKT_RES_PLL_OUT3_MASK 0xFFFF000000000000ull +#define CPUCP_PKT_VAL_PFC_IN1_SHIFT 0 +#define CPUCP_PKT_VAL_PFC_IN1_MASK 0x0000000000000001ull +#define CPUCP_PKT_VAL_PFC_IN2_SHIFT 1 +#define CPUCP_PKT_VAL_PFC_IN2_MASK 0x000000000000001Eull + +#define CPUCP_PKT_VAL_LPBK_IN1_SHIFT 0 +#define CPUCP_PKT_VAL_LPBK_IN1_MASK 0x0000000000000001ull +#define CPUCP_PKT_VAL_LPBK_IN2_SHIFT 1 +#define CPUCP_PKT_VAL_LPBK_IN2_MASK 0x000000000000001Eull + +/* heartbeat status bits */ +#define CPUCP_PKT_HB_STATUS_EQ_FAULT_SHIFT 0 +#define CPUCP_PKT_HB_STATUS_EQ_FAULT_MASK 0x00000001 + struct cpucp_packet { union { __le64 value; /* For SET packets */ @@ -445,6 +459,12 @@ struct cpucp_packet { /* For get CpuCP info/EEPROM data/NIC info */ __le32 data_max_size; + + /* + * For any general status bitmask. Shall be used whenever the + * result cannot be used to hold general purpose data. + */ + __le32 status_mask; }; __le32 reserved; -- cgit v1.2.3 From 358526be824f311e1db0d192cb9e96d85d27ac1d Mon Sep 17 00:00:00 2001 From: Ofir Bitton Date: Thu, 11 Feb 2021 11:09:12 +0200 Subject: habanalabs: enable stop on error for all QMANs and engines If there is an error in the QMAN/engine, there is no point of trying to continue running the workload. It is better to stop to allow the user to debug the program. Signed-off-by: Ofir Bitton Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/habanalabs_drv.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/habanalabs_drv.c b/drivers/misc/habanalabs/common/habanalabs_drv.c index b55dd1c55166..3a4233971f2b 100644 --- a/drivers/misc/habanalabs/common/habanalabs_drv.c +++ b/drivers/misc/habanalabs/common/habanalabs_drv.c @@ -326,6 +326,7 @@ int create_hdev(struct hl_device **dev, struct pci_dev *pdev, hdev->reset_on_lockup = reset_on_lockup; hdev->memory_scrub = memory_scrub; hdev->boot_error_status_mask = boot_error_status_mask; + hdev->stop_on_err = true; hdev->pldm = 0; -- cgit v1.2.3 From 4b09901cf71fdb71f7652b22a4f5e033f7defef9 Mon Sep 17 00:00:00 2001 From: Bharat Jauhari Date: Fri, 28 May 2021 13:14:34 +0300 Subject: habanalabs: enable dram scramble before linux f/w In current code, for dynamic f/w loading flow, DRAM scrambling is enabled post Linux fit image is loaded to the card. This can cause the device CPU to go into reset state. The correct sequence should be: 1. Load boot fit image 2. Enable scrambling 3. Load Linux fit image This commit aligns the DRAM scrambling enabling with the static f/w load flow. Signed-off-by: Bharat Jauhari Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 10 ++++++++++ drivers/misc/habanalabs/common/habanalabs.h | 4 +++- drivers/misc/habanalabs/gaudi/gaudi.c | 4 +--- drivers/misc/habanalabs/goya/goya.c | 8 +++++++- 4 files changed, 21 insertions(+), 5 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index d5a3c786d4c9..2bb2a4145640 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -2149,6 +2149,11 @@ static int hl_fw_dynamic_init_cpu(struct hl_device *hdev, if (rc) goto protocol_err; + /* Enable DRAM scrambling before Linux boot and after successful + * UBoot + */ + hdev->asic_funcs->init_cpu_scrambler_dram(hdev); + if (!(hdev->fw_components & FW_TYPE_LINUX)) { dev_info(hdev->dev, "Skip loading Linux F/W\n"); return 0; @@ -2295,6 +2300,11 @@ static int hl_fw_static_init_cpu(struct hl_device *hdev, goto out; } + /* Enable DRAM scrambling before Linux boot and after successful + * UBoot + */ + hdev->asic_funcs->init_cpu_scrambler_dram(hdev); + if (!(hdev->fw_components & FW_TYPE_LINUX)) { dev_info(hdev->dev, "Skip loading Linux F/W\n"); goto out; diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index bcb5bfdd7f20..bc5a1b45270f 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -1092,7 +1092,8 @@ struct fw_load_mgr { * @get_msi_info: Retrieve asic-specific MSI ID of the f/w async event * @map_pll_idx_to_fw_idx: convert driver specific per asic PLL index to * generic f/w compatible PLL Indexes - *@init_firmware_loader: initialize data for FW loader. + * @init_firmware_loader: initialize data for FW loader. + * @init_cpu_scrambler_dram: Enable CPU specific DRAM scrambling */ struct hl_asic_funcs { int (*early_init)(struct hl_device *hdev); @@ -1217,6 +1218,7 @@ struct hl_asic_funcs { void (*get_msi_info)(__le32 *table); int (*map_pll_idx_to_fw_idx)(u32 pll_idx); void (*init_firmware_loader)(struct hl_device *hdev); + void (*init_cpu_scrambler_dram)(struct hl_device *hdev); }; diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index f8bf30e48bba..ca1a8ca24d4a 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -3804,9 +3804,6 @@ static int gaudi_load_firmware_to_device(struct hl_device *hdev) { void __iomem *dst; - /* HBM scrambler must be initialized before pushing F/W to HBM */ - gaudi_init_scrambler_hbm(hdev); - dst = hdev->pcie_bar[HBM_BAR_ID] + LINUX_FW_OFFSET; return hl_fw_load_fw_to_device(hdev, GAUDI_LINUX_FW_FILE, dst, 0, 0); @@ -8949,6 +8946,7 @@ static const struct hl_asic_funcs gaudi_funcs = { .enable_events_from_fw = gaudi_enable_events_from_fw, .map_pll_idx_to_fw_idx = gaudi_map_pll_idx_to_fw_idx, .init_firmware_loader = gaudi_init_firmware_loader, + .init_cpu_scrambler_dram = gaudi_init_scrambler_hbm }; /** diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c index 6d63930b7a10..2a9b91d5c6ff 100644 --- a/drivers/misc/habanalabs/goya/goya.c +++ b/drivers/misc/habanalabs/goya/goya.c @@ -5402,6 +5402,11 @@ static int goya_get_eeprom_data(struct hl_device *hdev, void *data, return hl_fw_get_eeprom_data(hdev, data, max_size); } +static void goya_cpu_init_scrambler_dram(struct hl_device *hdev) +{ + +} + static int goya_ctx_init(struct hl_ctx *ctx) { if (ctx->asid != HL_KERNEL_ASID_ID) @@ -5601,7 +5606,8 @@ static const struct hl_asic_funcs goya_funcs = { .hw_block_mmap = goya_block_mmap, .enable_events_from_fw = goya_enable_events_from_fw, .map_pll_idx_to_fw_idx = goya_map_pll_idx_to_fw_idx, - .init_firmware_loader = goya_init_firmware_loader + .init_firmware_loader = goya_init_firmware_loader, + .init_cpu_scrambler_dram = goya_cpu_init_scrambler_dram }; /* -- cgit v1.2.3 From 4efb6b2b4662871c7299723e3e26976bfcd3a809 Mon Sep 17 00:00:00 2001 From: Omer Shpigelman Date: Wed, 9 Jun 2021 10:17:49 +0300 Subject: habanalabs: add hard reset timeout for PLDM Hard reset flow on PLDM might take more than 2 minutes. Hence add a dedicated hard reset timeout of 6 minutes for PLDM. Signed-off-by: Omer Shpigelman Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/device.c | 9 +++++++-- drivers/misc/habanalabs/common/habanalabs.h | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/device.c b/drivers/misc/habanalabs/common/device.c index 46fcab1bf873..cbdf75b24cb4 100644 --- a/drivers/misc/habanalabs/common/device.c +++ b/drivers/misc/habanalabs/common/device.c @@ -1501,6 +1501,7 @@ out_disabled: void hl_device_fini(struct hl_device *hdev) { ktime_t timeout; + u64 reset_sec; int i, rc; dev_info(hdev->dev, "Removing device\n"); @@ -1508,6 +1509,11 @@ void hl_device_fini(struct hl_device *hdev) hdev->device_fini_pending = 1; flush_delayed_work(&hdev->device_reset_work.reset_work); + if (hdev->pldm) + reset_sec = HL_PLDM_HARD_RESET_MAX_TIMEOUT; + else + reset_sec = HL_HARD_RESET_MAX_TIMEOUT; + /* * This function is competing with the reset function, so try to * take the reset atomic and if we are already in middle of reset, @@ -1516,8 +1522,7 @@ void hl_device_fini(struct hl_device *hdev) * ports, the hard reset could take between 10-30 seconds */ - timeout = ktime_add_us(ktime_get(), - HL_HARD_RESET_MAX_TIMEOUT * 1000 * 1000); + timeout = ktime_add_us(ktime_get(), reset_sec * 1000 * 1000); rc = atomic_cmpxchg(&hdev->in_reset, 0, 1); while (rc) { usleep_range(50, 200); diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index bc5a1b45270f..244fbf209d34 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -48,6 +48,7 @@ #define HL_PENDING_RESET_LONG_SEC 60 #define HL_HARD_RESET_MAX_TIMEOUT 120 +#define HL_PLDM_HARD_RESET_MAX_TIMEOUT (HL_HARD_RESET_MAX_TIMEOUT * 3) #define HL_DEVICE_TIMEOUT_USEC 1000000 /* 1 s */ -- cgit v1.2.3 From c9d2f5cf27c5712d5d6bc4ba0d10a3b21bd84ad2 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Wed, 9 Jun 2021 10:04:35 +0300 Subject: habanalabs: print firmware versions Firmware in habanalabs devices is composed of several components. During device initialization, we read these versions from the device. Print them during device initialization to allow better visibility in automated systems. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 105 ++++++++++++++++++++++++--- 1 file changed, 95 insertions(+), 10 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index 2bb2a4145640..14e70422af25 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -11,11 +11,41 @@ #include #include #include +#include #define FW_FILE_MAX_SIZE 0x1400000 /* maximum size of 20MB */ #define FW_CPU_STATUS_POLL_INTERVAL_USEC 10000 +static char *extract_fw_ver_from_str(const char *fw_str) +{ + char *str, *fw_ver, *whitespace; + + fw_ver = kmalloc(16, GFP_KERNEL); + if (!fw_ver) + return NULL; + + str = strnstr(fw_str, "fw-", VERSION_MAX_LEN); + if (!str) + goto free_fw_ver; + + /* Skip the fw- part */ + str += 3; + + /* Copy until the next whitespace */ + whitespace = strnstr(str, " ", 15); + if (!whitespace) + goto free_fw_ver; + + strscpy(fw_ver, str, whitespace - str + 1); + + return fw_ver; + +free_fw_ver: + kfree(fw_ver); + return NULL; +} + static int hl_request_fw(struct hl_device *hdev, const struct firmware **firmware_p, const char *fw_name) @@ -573,8 +603,9 @@ int hl_fw_cpucp_info_get(struct hl_device *hdev, { struct asic_fixed_properties *prop = &hdev->asic_prop; struct cpucp_packet pkt = {}; - void *cpucp_info_cpu_addr; dma_addr_t cpucp_info_dma_addr; + void *cpucp_info_cpu_addr; + char *kernel_ver; u64 result; int rc; @@ -621,6 +652,12 @@ int hl_fw_cpucp_info_get(struct hl_device *hdev, goto out; } + kernel_ver = extract_fw_ver_from_str(prop->cpucp_info.kernel_version); + if (kernel_ver) { + dev_info(hdev->dev, "Linux version %s", kernel_ver); + kfree(kernel_ver); + } + /* assume EQ code doesn't need to check eqe index */ hdev->event_queue.check_eqe_index = false; @@ -1066,24 +1103,26 @@ static int hl_fw_read_preboot_caps(struct hl_device *hdev, static int hl_fw_static_read_device_fw_version(struct hl_device *hdev, enum hl_fw_component fwc) { + struct asic_fixed_properties *prop = &hdev->asic_prop; struct fw_load_mgr *fw_loader = &hdev->fw_loader; struct static_fw_load_mgr *static_loader; - const char *name; + char *dest, *boot_ver, *preboot_ver; u32 ver_off, limit; - char *dest; + const char *name; + char btl_ver[32]; static_loader = &hdev->fw_loader.static_loader; switch (fwc) { case FW_COMP_BOOT_FIT: ver_off = RREG32(static_loader->boot_fit_version_offset_reg); - dest = hdev->asic_prop.uboot_ver; + dest = prop->uboot_ver; name = "Boot-fit"; limit = static_loader->boot_fit_version_max_off; break; case FW_COMP_PREBOOT: ver_off = RREG32(static_loader->preboot_version_offset_reg); - dest = hdev->asic_prop.preboot_ver; + dest = prop->preboot_ver; name = "Preboot"; limit = static_loader->preboot_version_max_off; break; @@ -1105,6 +1144,30 @@ static int hl_fw_static_read_device_fw_version(struct hl_device *hdev, return -EIO; } + if (fwc == FW_COMP_BOOT_FIT) { + boot_ver = extract_fw_ver_from_str(prop->uboot_ver); + if (boot_ver) { + dev_info(hdev->dev, "boot-fit version %s\n", boot_ver); + kfree(boot_ver); + } + } else if (fwc == FW_COMP_PREBOOT) { + preboot_ver = strnstr(prop->preboot_ver, "Preboot", + VERSION_MAX_LEN); + if (preboot_ver && preboot_ver != prop->preboot_ver) { + strscpy(btl_ver, prop->preboot_ver, + min((int) (preboot_ver - prop->preboot_ver), + 31)); + dev_info(hdev->dev, "%s\n", btl_ver); + } + + preboot_ver = extract_fw_ver_from_str(prop->preboot_ver); + if (preboot_ver) { + dev_info(hdev->dev, "preboot version %s\n", + preboot_ver); + kfree(preboot_ver); + } + } + return 0; } @@ -1691,21 +1754,43 @@ static void hl_fw_dynamic_read_device_fw_version(struct hl_device *hdev, enum hl_fw_component fwc, const char *fw_version) { - char *dest; + struct asic_fixed_properties *prop = &hdev->asic_prop; + char *preboot_ver, *boot_ver; + char btl_ver[32]; switch (fwc) { case FW_COMP_BOOT_FIT: - dest = hdev->asic_prop.uboot_ver; + strscpy(prop->uboot_ver, fw_version, VERSION_MAX_LEN); + boot_ver = extract_fw_ver_from_str(prop->uboot_ver); + if (boot_ver) { + dev_info(hdev->dev, "boot-fit version %s\n", boot_ver); + kfree(boot_ver); + } + break; case FW_COMP_PREBOOT: - dest = hdev->asic_prop.preboot_ver; + strscpy(prop->preboot_ver, fw_version, VERSION_MAX_LEN); + preboot_ver = strnstr(prop->preboot_ver, "Preboot", + VERSION_MAX_LEN); + if (preboot_ver && preboot_ver != prop->preboot_ver) { + strscpy(btl_ver, prop->preboot_ver, + min((int) (preboot_ver - prop->preboot_ver), + 31)); + dev_info(hdev->dev, "%s\n", btl_ver); + } + + preboot_ver = extract_fw_ver_from_str(prop->preboot_ver); + if (preboot_ver) { + dev_info(hdev->dev, "preboot version %s\n", + preboot_ver); + kfree(preboot_ver); + } + break; default: dev_warn(hdev->dev, "Undefined FW component: %d\n", fwc); return; } - - strscpy(dest, fw_version, VERSION_MAX_LEN); } /** -- cgit v1.2.3 From 3002f467a0b0a70aec01d9f446da4ac8c6fda10b Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 12 Jun 2021 07:39:51 +0200 Subject: habanalabs: Fix an error handling path in 'hl_pci_probe()' If an error occurs after a 'pci_enable_pcie_error_reporting()' call, it must be undone by a corresponding 'pci_disable_pcie_error_reporting()' call, as already done in the remove function. Fixes: 2e5eda4681f9 ("habanalabs: PCIe Advanced Error Reporting support") Signed-off-by: Christophe JAILLET Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/habanalabs_drv.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/habanalabs_drv.c b/drivers/misc/habanalabs/common/habanalabs_drv.c index 3a4233971f2b..4d377a39df13 100644 --- a/drivers/misc/habanalabs/common/habanalabs_drv.c +++ b/drivers/misc/habanalabs/common/habanalabs_drv.c @@ -468,6 +468,7 @@ static int hl_pci_probe(struct pci_dev *pdev, return 0; disable_device: + pci_disable_pcie_error_reporting(pdev); pci_set_drvdata(pdev, NULL); destroy_hdev(hdev); -- cgit v1.2.3 From f5d6e39eb2a933a1734cd8a620c8bcd52c4a0947 Mon Sep 17 00:00:00 2001 From: Tomer Tayar Date: Thu, 10 Jun 2021 20:48:39 +0300 Subject: habanalabs: print more info when failing to pin user memory pin_user_pages_fast() might fail and return a negative number, or pin less pages than requested and return the number of the pages that were pinned. For the latter, it is informative to print also the memory size and the number of requested pages. Signed-off-by: Tomer Tayar Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/memory.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/memory.c b/drivers/misc/habanalabs/common/memory.c index a7a8984e6af2..1cff1887e2e8 100644 --- a/drivers/misc/habanalabs/common/memory.c +++ b/drivers/misc/habanalabs/common/memory.c @@ -1612,8 +1612,8 @@ static int get_user_memory(struct hl_device *hdev, u64 addr, u64 size, if (rc != npages) { dev_err(hdev->dev, - "Failed (%d) to pin host memory with user ptr 0x%llx\n", - rc, addr); + "Failed (%d) to pin host memory with user ptr 0x%llx, size 0x%llx, npages %d\n", + rc, addr, size, npages); if (rc < 0) goto destroy_pages; npages = rc; -- cgit v1.2.3 From b538888c3e49a0d1f1c59ef1b1ed2cd3d6e45db9 Mon Sep 17 00:00:00 2001 From: Koby Elbaz Date: Thu, 10 Jun 2021 15:09:54 +0300 Subject: habanalabs: zero complex structures using memset fix the following sparse warnings: 'warning: Using plain integer as NULL pointer' 'warning: missing braces around initializer' Signed-off-by: Koby Elbaz Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index 14e70422af25..d5d0db7fd6ef 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -392,10 +392,11 @@ void hl_fw_cpu_accessible_dma_pool_free(struct hl_device *hdev, size_t size, int hl_fw_send_heartbeat(struct hl_device *hdev) { - struct cpucp_packet hb_pkt = {0}; + struct cpucp_packet hb_pkt; u64 result; int rc; + memset(&hb_pkt, 0, sizeof(hb_pkt)); hb_pkt.ctl = cpu_to_le32(CPUCP_PACKET_TEST << CPUCP_PKT_CTL_OPCODE_SHIFT); hb_pkt.value = cpu_to_le64(CPUCP_PACKET_FENCE_VAL); -- cgit v1.2.3 From 11d5cb8b95456e2432dfee2ffcebf0623998493a Mon Sep 17 00:00:00 2001 From: Koby Elbaz Date: Thu, 10 Jun 2021 09:01:57 +0300 Subject: habanalabs: set rc as 'valid' in case of intentional func exit fix the following smatch warnings: hl_fw_static_init_cpu() warn: missing error code 'rc' Signed-off-by: Koby Elbaz Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/device.c | 5 +++-- drivers/misc/habanalabs/common/firmware_if.c | 5 ++++- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/device.c b/drivers/misc/habanalabs/common/device.c index cbdf75b24cb4..e56f5170e338 100644 --- a/drivers/misc/habanalabs/common/device.c +++ b/drivers/misc/habanalabs/common/device.c @@ -1360,8 +1360,9 @@ int hl_device_init(struct hl_device *hdev, struct class *hclass) } /* - * From this point, in case of an error, add char devices and create - * sysfs nodes as part of the error flow, to allow debugging. + * From this point, override rc (=0) in case of an error to allow + * debugging (by adding char devices and create sysfs nodes as part of + * the error flow). */ add_cdev_sysfs_on_err = true; diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index d5d0db7fd6ef..ce87053d4fde 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -2393,11 +2393,14 @@ static int hl_fw_static_init_cpu(struct hl_device *hdev, if (!(hdev->fw_components & FW_TYPE_LINUX)) { dev_info(hdev->dev, "Skip loading Linux F/W\n"); + rc = 0; goto out; } - if (status == CPU_BOOT_STATUS_SRAM_AVAIL) + if (status == CPU_BOOT_STATUS_SRAM_AVAIL) { + rc = 0; goto out; + } dev_info(hdev->dev, "Loading firmware to device, may take some time...\n"); -- cgit v1.2.3 From f5eb7bf0c487a212ebda3c1b048fc3ccabacc147 Mon Sep 17 00:00:00 2001 From: Koby Elbaz Date: Wed, 9 Jun 2021 21:43:52 +0300 Subject: habanalabs: remove node from list before freeing the node fix the following smatch warnings: goya_pin_memory_before_cs() warn: '&userptr->job_node' not removed from list gaudi_pin_memory_before_cs() warn: '&userptr->job_node' not removed from list Signed-off-by: Koby Elbaz Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/gaudi/gaudi.c | 1 + drivers/misc/habanalabs/goya/goya.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index ca1a8ca24d4a..a46ec601a635 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -5046,6 +5046,7 @@ already_pinned: return 0; unpin_memory: + list_del(&userptr->job_node); hl_unpin_host_memory(hdev, userptr); free_userptr: kfree(userptr); diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c index 2a9b91d5c6ff..e91b730baebd 100644 --- a/drivers/misc/habanalabs/goya/goya.c +++ b/drivers/misc/habanalabs/goya/goya.c @@ -3326,6 +3326,7 @@ already_pinned: return 0; unpin_memory: + list_del(&userptr->job_node); hl_unpin_host_memory(hdev, userptr); free_userptr: kfree(userptr); -- cgit v1.2.3 From ba662265feac21ef2f47de97e1ab2107d5091a13 Mon Sep 17 00:00:00 2001 From: Tal Albo Date: Thu, 10 Jun 2021 12:18:37 +0300 Subject: habanalabs/gaudi: update coresight configuration Update STMTCSR and STMSYNCR values in order to reduce amount of sync packets Signed-off-by: Tal Albo Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/gaudi/gaudi_coresight.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/gaudi/gaudi_coresight.c b/drivers/misc/habanalabs/gaudi/gaudi_coresight.c index 9e271fd9f0d2..c2a27ed1c4d1 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi_coresight.c +++ b/drivers/misc/habanalabs/gaudi/gaudi_coresight.c @@ -424,7 +424,7 @@ static int gaudi_config_stm(struct hl_device *hdev, if (frequency == 0) frequency = input->frequency; WREG32(base_reg + 0xE8C, frequency); - WREG32(base_reg + 0xE90, 0x7FF); + WREG32(base_reg + 0xE90, 0x1F00); /* SW-2176 - SW WA for HW bug */ if ((CFG_BASE + base_reg) >= mmDMA_CH_0_CS_STM_BASE && @@ -434,7 +434,7 @@ static int gaudi_config_stm(struct hl_device *hdev, WREG32(base_reg + 0xE6C, 0x0); } - WREG32(base_reg + 0xE80, 0x27 | (input->id << 16)); + WREG32(base_reg + 0xE80, 0x23 | (input->id << 16)); } else { WREG32(base_reg + 0xE80, 4); WREG32(base_reg + 0xD64, 0); -- cgit v1.2.3 From 1f7ef4bf41c7c2abad3d21b8c69db11fc3ebc4f5 Mon Sep 17 00:00:00 2001 From: Koby Elbaz Date: Thu, 10 Jun 2021 09:14:43 +0300 Subject: habanalabs/gaudi: set the correct rc in case of err fix the following smatch warnings: gaudi_internal_cb_pool_init() warn: missing error code 'rc' Signed-off-by: Koby Elbaz Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/gaudi/gaudi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index a46ec601a635..e66433d05616 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -8393,8 +8393,10 @@ static int gaudi_internal_cb_pool_init(struct hl_device *hdev, HL_VA_RANGE_TYPE_HOST, HOST_SPACE_INTERNAL_CB_SZ, HL_MMU_VA_ALIGNMENT_NOT_NEEDED); - if (!hdev->internal_cb_va_base) + if (!hdev->internal_cb_va_base) { + rc = -ENOMEM; goto destroy_internal_cb_pool; + } mutex_lock(&ctx->mmu_lock); rc = hl_mmu_map_contiguous(ctx, hdev->internal_cb_va_base, -- cgit v1.2.3 From e307b302be8beb7fb59aa16621d5081b69397076 Mon Sep 17 00:00:00 2001 From: Yuri Nudelman Date: Mon, 24 May 2021 11:25:21 +0300 Subject: habanalabs: added open_stats info ioctl In a system with multiple ASICs, there is a need to provide monitoring tools with information on how long a device was opened and how many times a device was opened. Therefore, we add a new opcode to the INFO ioctl to provide that information. Signed-off-by: Yuri Nudelman Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/device.c | 3 +++ drivers/misc/habanalabs/common/habanalabs.h | 8 ++++++++ drivers/misc/habanalabs/common/habanalabs_drv.c | 3 +++ drivers/misc/habanalabs/common/habanalabs_ioctl.c | 21 +++++++++++++++++++++ include/uapi/misc/habanalabs.h | 12 ++++++++++++ 5 files changed, 47 insertions(+) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/device.c b/drivers/misc/habanalabs/common/device.c index e56f5170e338..37ce38d9a1a7 100644 --- a/drivers/misc/habanalabs/common/device.c +++ b/drivers/misc/habanalabs/common/device.c @@ -132,6 +132,9 @@ static int hl_device_release(struct inode *inode, struct file *filp) dev_warn(hdev->dev, "Device is still in use because there are live CS and/or memory mappings\n"); + hdev->last_open_session_duration_jif = + jiffies - hdev->last_successful_open_jif; + return 0; } diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index 244fbf209d34..6c9a81c2cfe7 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -2137,6 +2137,11 @@ struct hl_mmu_funcs { * the error will be ignored by the driver during * device initialization. Mainly used to debug and * workaround firmware bugs + * @last_successful_open_jif: timestamp (jiffies) of the last successful + * device open. + * @last_open_session_duration_jif: duration (jiffies) of the last device open + * session. + * @open_counter: number of successful device open operations. * @in_reset: is device in reset flow. * @curr_pll_profile: current PLL profile. * @card_type: Various ASICs have several card types. This indicates the card @@ -2259,6 +2264,9 @@ struct hl_device { u64 max_power; u64 clock_gating_mask; u64 boot_error_status_mask; + u64 last_successful_open_jif; + u64 last_open_session_duration_jif; + u64 open_counter; atomic_t in_reset; enum hl_pll_frequency curr_pll_profile; enum cpucp_card_types card_type; diff --git a/drivers/misc/habanalabs/common/habanalabs_drv.c b/drivers/misc/habanalabs/common/habanalabs_drv.c index 4d377a39df13..4194cda2d04c 100644 --- a/drivers/misc/habanalabs/common/habanalabs_drv.c +++ b/drivers/misc/habanalabs/common/habanalabs_drv.c @@ -187,6 +187,9 @@ int hl_device_open(struct inode *inode, struct file *filp) hl_debugfs_add_file(hpriv); + hdev->open_counter++; + hdev->last_successful_open_jif = jiffies; + return 0; out_err: diff --git a/drivers/misc/habanalabs/common/habanalabs_ioctl.c b/drivers/misc/habanalabs/common/habanalabs_ioctl.c index 6604d30246e6..f4dda7b4acdd 100644 --- a/drivers/misc/habanalabs/common/habanalabs_ioctl.c +++ b/drivers/misc/habanalabs/common/habanalabs_ioctl.c @@ -460,6 +460,24 @@ static int power_info(struct hl_fpriv *hpriv, struct hl_info_args *args) min((size_t) max_size, sizeof(power_info))) ? -EFAULT : 0; } +static int open_stats_info(struct hl_fpriv *hpriv, struct hl_info_args *args) +{ + struct hl_device *hdev = hpriv->hdev; + u32 max_size = args->return_size; + struct hl_open_stats_info open_stats_info = {0}; + void __user *out = (void __user *) (uintptr_t) args->return_pointer; + + if ((!max_size) || (!out)) + return -EINVAL; + + open_stats_info.last_open_period_ms = jiffies64_to_msecs( + hdev->last_open_session_duration_jif); + open_stats_info.open_counter = hdev->open_counter; + + return copy_to_user(out, &open_stats_info, + min((size_t) max_size, sizeof(open_stats_info))) ? -EFAULT : 0; +} + static int _hl_info_ioctl(struct hl_fpriv *hpriv, void *data, struct device *dev) { @@ -543,6 +561,9 @@ static int _hl_info_ioctl(struct hl_fpriv *hpriv, void *data, case HL_INFO_POWER: return power_info(hpriv, args); + case HL_INFO_OPEN_STATS: + return open_stats_info(hpriv, args); + default: dev_err(dev, "Invalid request %d\n", args->op); rc = -ENOTTY; diff --git a/include/uapi/misc/habanalabs.h b/include/uapi/misc/habanalabs.h index a47485a8d411..a47a731e4527 100644 --- a/include/uapi/misc/habanalabs.h +++ b/include/uapi/misc/habanalabs.h @@ -313,6 +313,7 @@ enum hl_device_status { * HL_INFO_SYNC_MANAGER - Retrieve sync manager info per dcore * HL_INFO_TOTAL_ENERGY - Retrieve total energy consumption * HL_INFO_PLL_FREQUENCY - Retrieve PLL frequency + * HL_INFO_OPEN_STATS - Retrieve info regarding recent device open calls */ #define HL_INFO_HW_IP_INFO 0 #define HL_INFO_HW_EVENTS 1 @@ -331,6 +332,7 @@ enum hl_device_status { #define HL_INFO_TOTAL_ENERGY 15 #define HL_INFO_PLL_FREQUENCY 16 #define HL_INFO_POWER 17 +#define HL_INFO_OPEN_STATS 18 #define HL_INFO_VERSION_MAX_LEN 128 #define HL_INFO_CARD_NAME_MAX_LEN 16 @@ -444,6 +446,16 @@ struct hl_pll_frequency_info { __u16 output[HL_PLL_NUM_OUTPUTS]; }; +/** + * struct hl_open_stats_info - device open statistics information + * @open_counter: ever growing counter, increased on each successful dev open + * @last_open_period_ms: duration (ms) device was open last time + */ +struct hl_open_stats_info { + __u64 open_counter; + __u64 last_open_period_ms; +}; + /** * struct hl_power_info - power information * @power: power consumption -- cgit v1.2.3 From f18cb6b58e34e0c4e8c11940b906c8c945493973 Mon Sep 17 00:00:00 2001 From: Koby Elbaz Date: Mon, 14 Jun 2021 08:06:15 +0300 Subject: habanalabs/goya: add '__force' attribute to suppress false alarm fix (suppress) the following sparse warnings: 'warning: cast removes address space of expression' Signed-off-by: Koby Elbaz Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/goya/goya.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c index e91b730baebd..5a837c0b4d76 100644 --- a/drivers/misc/habanalabs/goya/goya.c +++ b/drivers/misc/habanalabs/goya/goya.c @@ -2937,7 +2937,7 @@ void *goya_get_int_queue_base(struct hl_device *hdev, u32 queue_id, *dma_handle = hdev->asic_prop.sram_base_address; - base = (void *) hdev->pcie_bar[SRAM_CFG_BAR_ID]; + base = (__force void *) hdev->pcie_bar[SRAM_CFG_BAR_ID]; switch (queue_id) { case GOYA_QUEUE_ID_MME: -- cgit v1.2.3 From 2718e1d32238370404923d0eaa074647f2c788a5 Mon Sep 17 00:00:00 2001 From: Ohad Sharabi Date: Mon, 24 May 2021 09:59:31 +0300 Subject: habanalabs/gaudi: print last QM PQEs on error In case QMAN has an error and stop_on_err is true, print specific information of the "offending" command buffer batch. If the error occurred on one of the higher CPs, the CQ pointer and size will be printed along with (up to) last 8 PQEs of the stream. If the error occurred in the lower CP, the CQ pointer and size will be printed along with (up to) last 8 PQEs of ALL upper CPs as we have no way to know which upper CP sent the job there. This is done so higher SW levels will be able to debug their CS by extracting the raw data of the offending command buffer batch and examine those offline to detect the issue. Signed-off-by: Ohad Sharabi Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/gaudi/gaudi.c | 218 +++++++++++++++++++++++++++------ drivers/misc/habanalabs/gaudi/gaudiP.h | 1 + 2 files changed, 182 insertions(+), 37 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index e66433d05616..a673e404f777 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -7157,14 +7157,158 @@ enable_clk_gate: return rc; } +/* + * gaudi_queue_idx_dec - decrement queue index (pi/ci) and handle wrap + * + * @idx: the current pi/ci value + * @q_len: the queue length (power of 2) + * + * @return the cyclically decremented index + */ +static inline u32 gaudi_queue_idx_dec(u32 idx, u32 q_len) +{ + u32 mask = q_len - 1; + + /* + * modular decrement is equivalent to adding (queue_size -1) + * later we take LSBs to make sure the value is in the + * range [0, queue_len - 1] + */ + return (idx + q_len - 1) & mask; +} + +/** + * gaudi_print_sw_config_stream_data - print SW config stream data + * + * @hdev: pointer to the habanalabs device structure + * @stream: the QMAN's stream + * @qman_base: base address of QMAN registers block + */ +static void gaudi_print_sw_config_stream_data(struct hl_device *hdev, u32 stream, + u64 qman_base) +{ + u64 cq_ptr_lo, cq_ptr_hi, cq_tsize, cq_ptr; + u32 cq_ptr_lo_off, size; + + cq_ptr_lo_off = mmTPC0_QM_CQ_PTR_LO_1 - mmTPC0_QM_CQ_PTR_LO_0; + + cq_ptr_lo = qman_base + (mmTPC0_QM_CQ_PTR_LO_0 - mmTPC0_QM_BASE) + + stream * cq_ptr_lo_off; + cq_ptr_hi = cq_ptr_lo + + (mmTPC0_QM_CQ_PTR_HI_0 - mmTPC0_QM_CQ_PTR_LO_0); + cq_tsize = cq_ptr_lo + + (mmTPC0_QM_CQ_TSIZE_0 - mmTPC0_QM_CQ_PTR_LO_0); + + cq_ptr = (((u64) RREG32(cq_ptr_hi)) << 32) | RREG32(cq_ptr_lo); + size = RREG32(cq_tsize); + dev_info(hdev->dev, "stop on err: stream: %u, addr: %#llx, size: %x\n", + stream, cq_ptr, size); +} + +/** + * gaudi_print_last_pqes_on_err - print last PQEs on error + * + * @hdev: pointer to the habanalabs device structure + * @qid_base: first QID of the QMAN (out of 4 streams) + * @stream: the QMAN's stream + * @qman_base: base address of QMAN registers block + * @pr_sw_conf: if true print the SW config stream data (CQ PTR and SIZE) + */ +static void gaudi_print_last_pqes_on_err(struct hl_device *hdev, u32 qid_base, + u32 stream, u64 qman_base, + bool pr_sw_conf) +{ + u32 ci, qm_ci_stream_off, queue_len; + struct hl_hw_queue *q; + u64 pq_ci; + int i; + + q = &hdev->kernel_queues[qid_base + stream]; + + qm_ci_stream_off = mmTPC0_QM_PQ_CI_1 - mmTPC0_QM_PQ_CI_0; + pq_ci = qman_base + (mmTPC0_QM_PQ_CI_0 - mmTPC0_QM_BASE) + + stream * qm_ci_stream_off; + + queue_len = (q->queue_type == QUEUE_TYPE_INT) ? + q->int_queue_len : HL_QUEUE_LENGTH; + + hdev->asic_funcs->hw_queues_lock(hdev); + + if (pr_sw_conf) + gaudi_print_sw_config_stream_data(hdev, stream, qman_base); + + ci = RREG32(pq_ci); + + /* we should start printing form ci -1 */ + ci = gaudi_queue_idx_dec(ci, queue_len); + + for (i = 0; i < PQ_FETCHER_CACHE_SIZE; i++) { + struct hl_bd *bd; + u64 addr; + u32 len; + + bd = q->kernel_address; + bd += ci; + + len = le32_to_cpu(bd->len); + /* len 0 means uninitialized entry- break */ + if (!len) + break; + + addr = le64_to_cpu(bd->ptr); + + dev_info(hdev->dev, "stop on err PQE(stream %u): ci: %u, addr: %#llx, size: %x\n", + stream, ci, addr, len); + + /* get previous ci, wrap if needed */ + ci = gaudi_queue_idx_dec(ci, queue_len); + } + + hdev->asic_funcs->hw_queues_unlock(hdev); +} + +/** + * print_qman_data_on_err - extract QMAN data on error + * + * @hdev: pointer to the habanalabs device structure + * @qid_base: first QID of the QMAN (out of 4 streams) + * @stream: the QMAN's stream + * @qman_base: base address of QMAN registers block + * + * This function attempt to exatract as much data as possible on QMAN error. + * On upper CP print the SW config stream data and last 8 PQEs. + * On lower CP print SW config data and last PQEs of ALL 4 upper CPs + */ +static void print_qman_data_on_err(struct hl_device *hdev, u32 qid_base, + u32 stream, u64 qman_base) +{ + u32 i; + + if (stream != QMAN_STREAMS) { + gaudi_print_last_pqes_on_err(hdev, qid_base, stream, qman_base, + true); + return; + } + + gaudi_print_sw_config_stream_data(hdev, stream, qman_base); + + for (i = 0; i < QMAN_STREAMS; i++) + gaudi_print_last_pqes_on_err(hdev, qid_base, i, qman_base, + false); +} + static void gaudi_handle_qman_err_generic(struct hl_device *hdev, const char *qm_name, - u64 glbl_sts_addr, - u64 arb_err_addr) + u64 qman_base, + u32 qid_base) { u32 i, j, glbl_sts_val, arb_err_val, glbl_sts_clr_val; + u64 glbl_sts_addr, arb_err_addr; char reg_desc[32]; + glbl_sts_addr = qman_base + (mmTPC0_QM_GLBL_STS1_0 - mmTPC0_QM_BASE); + arb_err_addr = qman_base + (mmTPC0_QM_ARB_ERR_CAUSE - mmTPC0_QM_BASE); + /* Iterate through all stream GLBL_STS1 registers + Lower CP */ for (i = 0 ; i < QMAN_STREAMS + 1 ; i++) { glbl_sts_clr_val = 0; @@ -7191,6 +7335,8 @@ static void gaudi_handle_qman_err_generic(struct hl_device *hdev, /* Write 1 clear errors */ if (!hdev->stop_on_err) WREG32(glbl_sts_addr + 4 * i, glbl_sts_clr_val); + else + print_qman_data_on_err(hdev, qid_base, i, qman_base); } arb_err_val = RREG32(arb_err_addr); @@ -7335,90 +7481,88 @@ static void gaudi_handle_ecc_event(struct hl_device *hdev, u16 event_type, static void gaudi_handle_qman_err(struct hl_device *hdev, u16 event_type) { - u64 glbl_sts_addr, arb_err_addr; - u8 index; + u64 qman_base; char desc[32]; + u32 qid_base; + u8 index; switch (event_type) { case GAUDI_EVENT_TPC0_QM ... GAUDI_EVENT_TPC7_QM: index = event_type - GAUDI_EVENT_TPC0_QM; - glbl_sts_addr = - mmTPC0_QM_GLBL_STS1_0 + index * TPC_QMAN_OFFSET; - arb_err_addr = - mmTPC0_QM_ARB_ERR_CAUSE + index * TPC_QMAN_OFFSET; + qid_base = GAUDI_QUEUE_ID_TPC_0_0 + index * QMAN_STREAMS; + qman_base = mmTPC0_QM_BASE + index * TPC_QMAN_OFFSET; snprintf(desc, ARRAY_SIZE(desc), "%s%d", "TPC_QM", index); break; case GAUDI_EVENT_MME0_QM ... GAUDI_EVENT_MME2_QM: index = event_type - GAUDI_EVENT_MME0_QM; - glbl_sts_addr = - mmMME0_QM_GLBL_STS1_0 + index * MME_QMAN_OFFSET; - arb_err_addr = - mmMME0_QM_ARB_ERR_CAUSE + index * MME_QMAN_OFFSET; + qid_base = GAUDI_QUEUE_ID_MME_0_0 + index * QMAN_STREAMS; + qman_base = mmMME0_QM_BASE + index * MME_QMAN_OFFSET; snprintf(desc, ARRAY_SIZE(desc), "%s%d", "MME_QM", index); break; case GAUDI_EVENT_DMA0_QM ... GAUDI_EVENT_DMA7_QM: index = event_type - GAUDI_EVENT_DMA0_QM; - glbl_sts_addr = - mmDMA0_QM_GLBL_STS1_0 + index * DMA_QMAN_OFFSET; - arb_err_addr = - mmDMA0_QM_ARB_ERR_CAUSE + index * DMA_QMAN_OFFSET; + qid_base = GAUDI_QUEUE_ID_DMA_0_0 + index * QMAN_STREAMS; + /* skip GAUDI_QUEUE_ID_CPU_PQ if necessary */ + if (index > 1) + qid_base++; + qman_base = mmDMA0_QM_BASE + index * DMA_QMAN_OFFSET; snprintf(desc, ARRAY_SIZE(desc), "%s%d", "DMA_QM", index); break; case GAUDI_EVENT_NIC0_QM0: - glbl_sts_addr = mmNIC0_QM0_GLBL_STS1_0; - arb_err_addr = mmNIC0_QM0_ARB_ERR_CAUSE; + qid_base = GAUDI_QUEUE_ID_NIC_0_0; + qman_base = mmNIC0_QM0_BASE; snprintf(desc, ARRAY_SIZE(desc), "NIC0_QM0"); break; case GAUDI_EVENT_NIC0_QM1: - glbl_sts_addr = mmNIC0_QM1_GLBL_STS1_0; - arb_err_addr = mmNIC0_QM1_ARB_ERR_CAUSE; + qid_base = GAUDI_QUEUE_ID_NIC_1_0; + qman_base = mmNIC0_QM1_BASE; snprintf(desc, ARRAY_SIZE(desc), "NIC0_QM1"); break; case GAUDI_EVENT_NIC1_QM0: - glbl_sts_addr = mmNIC1_QM0_GLBL_STS1_0; - arb_err_addr = mmNIC1_QM0_ARB_ERR_CAUSE; + qid_base = GAUDI_QUEUE_ID_NIC_2_0; + qman_base = mmNIC1_QM0_BASE; snprintf(desc, ARRAY_SIZE(desc), "NIC1_QM0"); break; case GAUDI_EVENT_NIC1_QM1: - glbl_sts_addr = mmNIC1_QM1_GLBL_STS1_0; - arb_err_addr = mmNIC1_QM1_ARB_ERR_CAUSE; + qid_base = GAUDI_QUEUE_ID_NIC_3_0; + qman_base = mmNIC1_QM1_BASE; snprintf(desc, ARRAY_SIZE(desc), "NIC1_QM1"); break; case GAUDI_EVENT_NIC2_QM0: - glbl_sts_addr = mmNIC2_QM0_GLBL_STS1_0; - arb_err_addr = mmNIC2_QM0_ARB_ERR_CAUSE; + qid_base = GAUDI_QUEUE_ID_NIC_4_0; + qman_base = mmNIC2_QM0_BASE; snprintf(desc, ARRAY_SIZE(desc), "NIC2_QM0"); break; case GAUDI_EVENT_NIC2_QM1: - glbl_sts_addr = mmNIC2_QM1_GLBL_STS1_0; - arb_err_addr = mmNIC2_QM1_ARB_ERR_CAUSE; + qid_base = GAUDI_QUEUE_ID_NIC_5_0; + qman_base = mmNIC2_QM1_BASE; snprintf(desc, ARRAY_SIZE(desc), "NIC2_QM1"); break; case GAUDI_EVENT_NIC3_QM0: - glbl_sts_addr = mmNIC3_QM0_GLBL_STS1_0; - arb_err_addr = mmNIC3_QM0_ARB_ERR_CAUSE; + qid_base = GAUDI_QUEUE_ID_NIC_6_0; + qman_base = mmNIC3_QM0_BASE; snprintf(desc, ARRAY_SIZE(desc), "NIC3_QM0"); break; case GAUDI_EVENT_NIC3_QM1: - glbl_sts_addr = mmNIC3_QM1_GLBL_STS1_0; - arb_err_addr = mmNIC3_QM1_ARB_ERR_CAUSE; + qid_base = GAUDI_QUEUE_ID_NIC_7_0; + qman_base = mmNIC3_QM1_BASE; snprintf(desc, ARRAY_SIZE(desc), "NIC3_QM1"); break; case GAUDI_EVENT_NIC4_QM0: - glbl_sts_addr = mmNIC4_QM0_GLBL_STS1_0; - arb_err_addr = mmNIC4_QM0_ARB_ERR_CAUSE; + qid_base = GAUDI_QUEUE_ID_NIC_8_0; + qman_base = mmNIC4_QM0_BASE; snprintf(desc, ARRAY_SIZE(desc), "NIC4_QM0"); break; case GAUDI_EVENT_NIC4_QM1: - glbl_sts_addr = mmNIC4_QM1_GLBL_STS1_0; - arb_err_addr = mmNIC4_QM1_ARB_ERR_CAUSE; + qid_base = GAUDI_QUEUE_ID_NIC_9_0; + qman_base = mmNIC4_QM1_BASE; snprintf(desc, ARRAY_SIZE(desc), "NIC4_QM1"); break; default: return; } - gaudi_handle_qman_err_generic(hdev, desc, glbl_sts_addr, arb_err_addr); + gaudi_handle_qman_err_generic(hdev, desc, qman_base, qid_base); } static void gaudi_print_irq_info(struct hl_device *hdev, u16 event_type, diff --git a/drivers/misc/habanalabs/gaudi/gaudiP.h b/drivers/misc/habanalabs/gaudi/gaudiP.h index 48637a6343bb..b23336af191e 100644 --- a/drivers/misc/habanalabs/gaudi/gaudiP.h +++ b/drivers/misc/habanalabs/gaudi/gaudiP.h @@ -82,6 +82,7 @@ QMAN_STREAMS) #define QMAN_STREAMS 4 +#define PQ_FETCHER_CACHE_SIZE 8 #define DMA_QMAN_OFFSET (mmDMA1_QM_BASE - mmDMA0_QM_BASE) #define TPC_QMAN_OFFSET (mmTPC1_QM_BASE - mmTPC0_QM_BASE) -- cgit v1.2.3 From 5bdc657320168900e185f7d84d1ad8915205944d Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Tue, 15 Jun 2021 12:00:38 +0300 Subject: habanalabs: remove a rogue #ifdef There was a rogue #ifdef that crept into the upstream code for backwards compatibility which isn't needed of course. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/memory.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/memory.c b/drivers/misc/habanalabs/common/memory.c index 1cff1887e2e8..af339ce1ab4f 100644 --- a/drivers/misc/habanalabs/common/memory.c +++ b/drivers/misc/habanalabs/common/memory.c @@ -1373,12 +1373,7 @@ int hl_hw_block_mmap(struct hl_fpriv *hpriv, struct vm_area_struct *vma) /* Driver only allows mapping of a complete HW block */ block_size = vma->vm_end - vma->vm_start; -#ifdef _HAS_TYPE_ARG_IN_ACCESS_OK - if (!access_ok(VERIFY_WRITE, - (void __user *) (uintptr_t) vma->vm_start, block_size)) { -#else if (!access_ok((void __user *) (uintptr_t) vma->vm_start, block_size)) { -#endif dev_err(hdev->dev, "user pointer is invalid - 0x%lx\n", vma->vm_start); -- cgit v1.2.3 From 7d5ba005cfbcf8f1f441bbbe72881dc2be54e82c Mon Sep 17 00:00:00 2001 From: Ofir Bitton Date: Mon, 7 Jun 2021 15:22:56 +0300 Subject: habanalabs/gaudi: correct driver events numbering Currently driver sends fc interrupt id to FW instead of using cpu interrupt id. We intend to fix that and keep backward compatibility by using the same interrupt values. Signed-off-by: Ofir Bitton Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/gaudi/gaudi.c | 12 ++++++++---- .../misc/habanalabs/include/gaudi/gaudi_async_events.h | 8 ++++---- .../include/gaudi/gaudi_async_ids_map_extended.h | 16 ++++++++-------- 3 files changed, 20 insertions(+), 16 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index a673e404f777..be830948e051 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -3960,7 +3960,8 @@ static int gaudi_init_cpu_queues(struct hl_device *hdev, u32 cpu_timeout) mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR : le32_to_cpu(dyn_regs->gic_host_pi_upd_irq); - WREG32(irq_handler_offset, GAUDI_EVENT_PI_UPDATE); + WREG32(irq_handler_offset, + gaudi_irq_map_table[GAUDI_EVENT_PI_UPDATE].cpu_id); err = hl_poll_timeout( hdev, @@ -4146,7 +4147,8 @@ static void gaudi_hw_fini(struct hl_device *hdev, bool hard_reset) mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR : le32_to_cpu(dyn_regs->gic_host_halt_irq); - WREG32(irq_handler_offset, GAUDI_EVENT_HALT_MACHINE); + WREG32(irq_handler_offset, + gaudi_irq_map_table[GAUDI_EVENT_HALT_MACHINE].cpu_id); } else { if (hdev->asic_prop.hard_reset_done_by_fw) gaudi_ask_hard_reset_without_linux(hdev); @@ -4599,7 +4601,8 @@ static void gaudi_ring_doorbell(struct hl_device *hdev, u32 hw_queue_id, u32 pi) mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR : le32_to_cpu(dyn_regs->gic_host_pi_upd_irq); - WREG32(irq_handler_offset, GAUDI_EVENT_PI_UPDATE); + WREG32(irq_handler_offset, + gaudi_irq_map_table[GAUDI_EVENT_PI_UPDATE].cpu_id); } } @@ -8988,7 +8991,8 @@ static void gaudi_enable_events_from_fw(struct hl_device *hdev) mmGIC_DISTRIBUTOR__5_GICD_SETSPI_NSR : le32_to_cpu(dyn_regs->gic_host_ints_irq); - WREG32(irq_handler_offset, GAUDI_EVENT_INTS_REGISTER); + WREG32(irq_handler_offset, + gaudi_irq_map_table[GAUDI_EVENT_INTS_REGISTER].cpu_id); } static int gaudi_map_pll_idx_to_fw_idx(u32 pll_idx) diff --git a/drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h b/drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h index f66c759952e4..2aee18e19b5a 100644 --- a/drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h +++ b/drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h @@ -252,10 +252,6 @@ enum gaudi_async_event_id { GAUDI_EVENT_HBM3_SPI_0 = 407, GAUDI_EVENT_HBM3_SPI_1 = 408, GAUDI_EVENT_PSOC_GPIO_U16_0 = 421, - GAUDI_EVENT_PI_UPDATE = 484, - GAUDI_EVENT_HALT_MACHINE = 485, - GAUDI_EVENT_INTS_REGISTER = 486, - GAUDI_EVENT_SOFT_RESET = 487, GAUDI_EVENT_RAZWI_OR_ADC = 548, GAUDI_EVENT_TPC0_QM = 572, GAUDI_EVENT_TPC1_QM = 573, @@ -303,6 +299,10 @@ enum gaudi_async_event_id { GAUDI_EVENT_NIC3_QP1 = 619, GAUDI_EVENT_NIC4_QP0 = 620, GAUDI_EVENT_NIC4_QP1 = 621, + GAUDI_EVENT_PI_UPDATE = 635, + GAUDI_EVENT_HALT_MACHINE = 636, + GAUDI_EVENT_INTS_REGISTER = 637, + GAUDI_EVENT_SOFT_RESET = 638, GAUDI_EVENT_FW_ALIVE_S = 645, GAUDI_EVENT_DEV_RESET_REQ = 646, GAUDI_EVENT_PKT_QUEUE_OUT_SYNC = 647, diff --git a/drivers/misc/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h b/drivers/misc/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h index e87554ab0102..ac4d4b51da7f 100644 --- a/drivers/misc/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h +++ b/drivers/misc/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h @@ -508,10 +508,10 @@ static struct gaudi_async_events_ids_map gaudi_irq_map_table[] = { { .fc_id = 481, .cpu_id = 330, .valid = 0, .name = "" }, { .fc_id = 482, .cpu_id = 331, .valid = 0, .name = "" }, { .fc_id = 483, .cpu_id = 332, .valid = 0, .name = "" }, - { .fc_id = 484, .cpu_id = 333, .valid = 1, .name = "PI_UPDATE" }, - { .fc_id = 485, .cpu_id = 334, .valid = 1, .name = "HALT_MACHINE" }, - { .fc_id = 486, .cpu_id = 335, .valid = 1, .name = "INTS_REGISTER" }, - { .fc_id = 487, .cpu_id = 336, .valid = 1, .name = "SOFT_RESET" }, + { .fc_id = 484, .cpu_id = 333, .valid = 0, .name = "" }, + { .fc_id = 485, .cpu_id = 334, .valid = 0, .name = "" }, + { .fc_id = 486, .cpu_id = 335, .valid = 0, .name = "" }, + { .fc_id = 487, .cpu_id = 336, .valid = 0, .name = "" }, { .fc_id = 488, .cpu_id = 337, .valid = 0, .name = "" }, { .fc_id = 489, .cpu_id = 338, .valid = 0, .name = "" }, { .fc_id = 490, .cpu_id = 339, .valid = 0, .name = "" }, @@ -659,10 +659,10 @@ static struct gaudi_async_events_ids_map gaudi_irq_map_table[] = { { .fc_id = 632, .cpu_id = 481, .valid = 0, .name = "" }, { .fc_id = 633, .cpu_id = 482, .valid = 0, .name = "" }, { .fc_id = 634, .cpu_id = 483, .valid = 0, .name = "" }, - { .fc_id = 635, .cpu_id = 484, .valid = 0, .name = "" }, - { .fc_id = 636, .cpu_id = 485, .valid = 0, .name = "" }, - { .fc_id = 637, .cpu_id = 486, .valid = 0, .name = "" }, - { .fc_id = 638, .cpu_id = 487, .valid = 0, .name = "" }, + { .fc_id = 635, .cpu_id = 484, .valid = 1, .name = "PI_UPDATE" }, + { .fc_id = 636, .cpu_id = 485, .valid = 1, .name = "HALT_MACHINE" }, + { .fc_id = 637, .cpu_id = 486, .valid = 1, .name = "INTS_REGISTER" }, + { .fc_id = 638, .cpu_id = 487, .valid = 1, .name = "SOFT_RESET" }, { .fc_id = 639, .cpu_id = 488, .valid = 0, .name = "" }, { .fc_id = 640, .cpu_id = 489, .valid = 0, .name = "" }, { .fc_id = 641, .cpu_id = 490, .valid = 0, .name = "" }, -- cgit v1.2.3 From 38e19d0b87ebc380341d5c026abed9e8060b2d37 Mon Sep 17 00:00:00 2001 From: Zvika Yehudai Date: Tue, 15 Jun 2021 14:12:20 +0300 Subject: habanalabs: fix typo fix a spelling error in comment Signed-off-by: Zvika Yehudai Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/habanalabs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index 6c9a81c2cfe7..b4413c398142 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -2089,7 +2089,7 @@ struct hl_mmu_funcs { * @kernel_queues: array of hl_hw_queue. * @cs_mirror_list: CS mirror list for TDR. * @cs_mirror_lock: protects cs_mirror_list. - * @kernel_cb_mgr: command buffer manager for creating/destroying/handling CGs. + * @kernel_cb_mgr: command buffer manager for creating/destroying/handling CBs. * @event_queue: event queue for IRQ from CPU-CP. * @dma_pool: DMA pool for small allocations. * @cpu_accessible_dma_mem: Host <-> CPU-CP shared memory CPU address. -- cgit v1.2.3 From 4d041216c83dd9933c7c72b40511bb3585fa1724 Mon Sep 17 00:00:00 2001 From: Yuri Nudelman Date: Sun, 13 Jun 2021 09:22:20 +0300 Subject: debugfs: add skip_reset_on_timeout option To be able to debug long-running CS better, without changing the userspace code, we are adding a new option through debugfs interface to skip the reset of the device in case of CS timeout. Signed-off-by: Yuri Nudelman Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- Documentation/ABI/testing/debugfs-driver-habanalabs | 8 ++++++++ drivers/misc/habanalabs/common/command_submission.c | 1 + drivers/misc/habanalabs/common/debugfs.c | 5 +++++ drivers/misc/habanalabs/common/habanalabs.h | 3 +++ 4 files changed, 17 insertions(+) (limited to 'drivers/misc') diff --git a/Documentation/ABI/testing/debugfs-driver-habanalabs b/Documentation/ABI/testing/debugfs-driver-habanalabs index c78fc9282876..e78ceb1f70b3 100644 --- a/Documentation/ABI/testing/debugfs-driver-habanalabs +++ b/Documentation/ABI/testing/debugfs-driver-habanalabs @@ -207,6 +207,14 @@ Contact: ogabbay@kernel.org Description: Sets the PCI power state. Valid values are "1" for D0 and "2" for D3Hot +What: /sys/kernel/debug/habanalabs/hl/skip_reset_on_timeout +Date: Jun 2021 +KernelVersion: 5.13 +Contact: ynudelman@habana.ai +Description: Sets the skip reset on timeout option for the device. Value of + "0" means device will be reset in case some CS has timed out, + otherwise it will not be reset. + What: /sys/kernel/debug/habanalabs/hl/stop_on_err Date: Mar 2020 KernelVersion: 5.6 diff --git a/drivers/misc/habanalabs/common/command_submission.c b/drivers/misc/habanalabs/common/command_submission.c index 6d51f54030c1..adedb288d452 100644 --- a/drivers/misc/habanalabs/common/command_submission.c +++ b/drivers/misc/habanalabs/common/command_submission.c @@ -663,6 +663,7 @@ static int allocate_cs(struct hl_device *hdev, struct hl_ctx *ctx, cs->timestamp = !!(flags & HL_CS_FLAGS_TIMESTAMP); cs->timeout_jiffies = timeout; cs->skip_reset_on_timeout = + hdev->skip_reset_on_timeout || !!(flags & HL_CS_FLAGS_SKIP_RESET_ON_TIMEOUT); cs->submission_time_jiffies = jiffies; INIT_LIST_HEAD(&cs->job_list); diff --git a/drivers/misc/habanalabs/common/debugfs.c b/drivers/misc/habanalabs/common/debugfs.c index 8381155578a0..703d79fb6f3f 100644 --- a/drivers/misc/habanalabs/common/debugfs.c +++ b/drivers/misc/habanalabs/common/debugfs.c @@ -1278,6 +1278,11 @@ void hl_debugfs_add_device(struct hl_device *hdev) dev_entry->root, &dev_entry->blob_desc); + debugfs_create_x8("skip_reset_on_timeout", + 0644, + dev_entry->root, + &hdev->skip_reset_on_timeout); + for (i = 0, entry = dev_entry->entry_arr ; i < count ; i++, entry++) { debugfs_create_file(hl_debugfs_list[i].name, 0444, diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index b4413c398142..09b89fdeba0b 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -2191,6 +2191,8 @@ struct hl_mmu_funcs { * @supports_staged_submission: true if staged submissions are supported * @curr_reset_cause: saves an enumerated reset cause when a hard reset is * triggered, and cleared after it is shared with preboot. + * @skip_reset_on_timeout: Skip device reset if CS has timed out, wait for it to + * complete instead. */ struct hl_device { struct pci_dev *pdev; @@ -2305,6 +2307,7 @@ struct hl_device { u8 device_fini_pending; u8 supports_staged_submission; u8 curr_reset_cause; + u8 skip_reset_on_timeout; /* Parameters for bring-up */ u64 nic_ports_mask; -- cgit v1.2.3 From 23bace677a3d928b388b6204d64c08b8c6fd468c Mon Sep 17 00:00:00 2001 From: Ofir Bitton Date: Tue, 8 Jun 2021 17:24:52 +0300 Subject: habanalabs: allow reset upon device release We introduce a new type of reset which is reset upon device release. This reset is very similar to soft reset except the fact it is performed only upon device release and not upon user sysfs request nor TDR. The purpose of this reset is to make sure the device is returned to IDLE state after the current user has finished working with the device. Signed-off-by: Ofir Bitton Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/device.c | 25 +++++++++++++++++++++---- drivers/misc/habanalabs/common/habanalabs.h | 7 +++++++ drivers/misc/habanalabs/common/sysfs.c | 2 +- drivers/misc/habanalabs/goya/goya.c | 1 + 4 files changed, 30 insertions(+), 5 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/device.c b/drivers/misc/habanalabs/common/device.c index 37ce38d9a1a7..ff4cbde289c0 100644 --- a/drivers/misc/habanalabs/common/device.c +++ b/drivers/misc/habanalabs/common/device.c @@ -86,7 +86,7 @@ static void hpriv_release(struct kref *ref) if ((hdev->reset_if_device_not_idle && !device_is_idle) || hdev->reset_upon_device_release) - hl_device_reset(hdev, 0); + hl_device_reset(hdev, HL_RESET_DEVICE_RELEASE); } void hl_hpriv_get(struct hl_fpriv *hpriv) @@ -885,7 +885,7 @@ static void device_disable_open_processes(struct hl_device *hdev) int hl_device_reset(struct hl_device *hdev, u32 flags) { u64 idle_mask[HL_BUSY_ENGINES_MASK_EXT_SIZE] = {0}; - bool hard_reset, from_hard_reset_thread; + bool hard_reset, from_hard_reset_thread, hard_instead_soft = false; int i, rc; if (!hdev->init_done) { @@ -897,11 +897,28 @@ int hl_device_reset(struct hl_device *hdev, u32 flags) hard_reset = (flags & HL_RESET_HARD) != 0; from_hard_reset_thread = (flags & HL_RESET_FROM_RESET_THREAD) != 0; - if ((!hard_reset) && (!hdev->supports_soft_reset)) { - dev_dbg(hdev->dev, "Doing hard-reset instead of soft-reset\n"); + if (!hard_reset && !hdev->supports_soft_reset) { + hard_instead_soft = true; hard_reset = true; } + if (hdev->reset_upon_device_release && + (flags & HL_RESET_DEVICE_RELEASE)) { + dev_dbg(hdev->dev, + "Perform %s-reset upon device release\n", + hard_reset ? "hard" : "soft"); + goto do_reset; + } + + if (!hard_reset && !hdev->allow_external_soft_reset) { + hard_instead_soft = true; + hard_reset = true; + } + + if (hard_instead_soft) + dev_dbg(hdev->dev, "Doing hard-reset instead of soft-reset\n"); + +do_reset: /* Re-entry of reset thread */ if (from_hard_reset_thread && hdev->process_kill_trial_cnt) goto kill_processes; diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index 09b89fdeba0b..fad112a01009 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -119,11 +119,15 @@ enum hl_mmu_page_table_location { * * - HL_RESET_TDR * Set if reset is due to TDR + * + * - HL_RESET_DEVICE_RELEASE + * Set if reset is due to device release */ #define HL_RESET_HARD (1 << 0) #define HL_RESET_FROM_RESET_THREAD (1 << 1) #define HL_RESET_HEARTBEAT (1 << 2) #define HL_RESET_TDR (1 << 3) +#define HL_RESET_DEVICE_RELEASE (1 << 4) #define HL_MAX_SOBS_PER_MONITOR 8 @@ -2181,6 +2185,8 @@ struct hl_mmu_funcs { * @collective_mon_idx: helper index for collective initialization * @supports_coresight: is CoreSight supported. * @supports_soft_reset: is soft reset supported. + * @allow_external_soft_reset: true if soft reset initiated by user or TDR is + * allowed. * @supports_cb_mapping: is mapping a CB to the device's MMU supported. * @needs_reset: true if reset_on_lockup is false and device should be reset * due to lockup. @@ -2301,6 +2307,7 @@ struct hl_device { u8 collective_mon_idx; u8 supports_coresight; u8 supports_soft_reset; + u8 allow_external_soft_reset; u8 supports_cb_mapping; u8 needs_reset; u8 process_kill_trial_cnt; diff --git a/drivers/misc/habanalabs/common/sysfs.c b/drivers/misc/habanalabs/common/sysfs.c index c9f649b31e3a..db72df282ef8 100644 --- a/drivers/misc/habanalabs/common/sysfs.c +++ b/drivers/misc/habanalabs/common/sysfs.c @@ -208,7 +208,7 @@ static ssize_t soft_reset_store(struct device *dev, goto out; } - if (!hdev->supports_soft_reset) { + if (!hdev->allow_external_soft_reset) { dev_err(hdev->dev, "Device does not support soft-reset\n"); goto out; } diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c index 5a837c0b4d76..06f5f1439e69 100644 --- a/drivers/misc/habanalabs/goya/goya.c +++ b/drivers/misc/habanalabs/goya/goya.c @@ -954,6 +954,7 @@ static int goya_sw_init(struct hl_device *hdev) spin_lock_init(&goya->hw_queues_lock); hdev->supports_coresight = true; hdev->supports_soft_reset = true; + hdev->allow_external_soft_reset = true; goya_set_pci_memory_regions(hdev); -- cgit v1.2.3 From 69dbbbadad4f579048d441c5472482601a306935 Mon Sep 17 00:00:00 2001 From: Koby Elbaz Date: Thu, 17 Jun 2021 17:04:16 +0300 Subject: habanalabs: get lower/upper 32 bits via masking fix multiple similar occurrences of the following sparse warning: 'warning: cast truncates bits from constant value (7ffc113000 becomes fc113000)' Signed-off-by: Koby Elbaz Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/gaudi/gaudi.c | 2 +- drivers/misc/habanalabs/goya/goya.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index be830948e051..4a75df240cfc 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -3858,7 +3858,7 @@ static void gaudi_init_static_firmware_loader(struct hl_device *hdev) static_loader->boot_err1_reg = mmCPU_BOOT_ERR1; static_loader->preboot_version_offset_reg = mmPREBOOT_VER_OFFSET; static_loader->boot_fit_version_offset_reg = mmUBOOT_VER_OFFSET; - static_loader->sram_offset_mask = ~((u32)SRAM_BASE_ADDR); + static_loader->sram_offset_mask = ~(lower_32_bits(SRAM_BASE_ADDR)); } static void gaudi_init_firmware_loader(struct hl_device *hdev) diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c index 06f5f1439e69..755e08cf2ecc 100644 --- a/drivers/misc/habanalabs/goya/goya.c +++ b/drivers/misc/habanalabs/goya/goya.c @@ -2484,7 +2484,7 @@ static void goya_init_static_firmware_loader(struct hl_device *hdev) static_loader->boot_err1_reg = mmCPU_BOOT_ERR1; static_loader->preboot_version_offset_reg = mmPREBOOT_VER_OFFSET; static_loader->boot_fit_version_offset_reg = mmUBOOT_VER_OFFSET; - static_loader->sram_offset_mask = ~((u32)SRAM_BASE_ADDR); + static_loader->sram_offset_mask = ~(lower_32_bits(SRAM_BASE_ADDR)); } static void goya_init_firmware_loader(struct hl_device *hdev) -- cgit v1.2.3 From 3817b352aad3b43f897c3034b16886cdb949b720 Mon Sep 17 00:00:00 2001 From: farah kassabri Date: Tue, 1 Jun 2021 16:44:28 +0300 Subject: habanalabs: add validity check for signal cs In preparation for a new feature that allows the user to reserve signals ahead of submissions, we need to change a current assumption in the code. Currently, the driver uses 2 SOBs to support signal CS. When the first SOB reaches max value, the driver switches to the other one and assumes that when it will need to switch back to the first one, all of the signals have already been handled. This assumption won't hold when the new feature will be added, because using signal reservation, the driver can reach the max SOB value very fast. The change is to add a validity check when submitting a signal CS, to make sure the previous SOB is available (all the signals attached to it indeed finished). Signed-off-by: farah kassabri Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- .../misc/habanalabs/common/command_submission.c | 55 ++++++++++++++++++++++ drivers/misc/habanalabs/common/habanalabs.h | 2 + drivers/misc/habanalabs/common/hw_queue.c | 42 +++++++---------- 3 files changed, 75 insertions(+), 24 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/command_submission.c b/drivers/misc/habanalabs/common/command_submission.c index adedb288d452..80c60fb41bbc 100644 --- a/drivers/misc/habanalabs/common/command_submission.c +++ b/drivers/misc/habanalabs/common/command_submission.c @@ -1497,6 +1497,61 @@ out: return rc; } +/* + * hl_cs_signal_sob_wraparound_handler: handle SOB value wrapaound case. + * if the SOB value reaches the max value move to the other SOB reserved + * to the queue. + * Note that this function must be called while hw_queues_lock is taken. + */ +int hl_cs_signal_sob_wraparound_handler(struct hl_device *hdev, u32 q_idx, + struct hl_hw_sob **hw_sob, u32 count) +{ + struct hl_sync_stream_properties *prop; + struct hl_hw_sob *sob = *hw_sob, *other_sob; + u8 other_sob_offset; + + prop = &hdev->kernel_queues[q_idx].sync_stream_prop; + + kref_get(&sob->kref); + + /* check for wraparound */ + if (prop->next_sob_val + count >= HL_MAX_SOB_VAL) { + /* + * Decrement as we reached the max value. + * The release function won't be called here as we've + * just incremented the refcount right before calling this + * function. + */ + kref_put(&sob->kref, hl_sob_reset_error); + + /* + * check the other sob value, if it still in use then fail + * otherwise make the switch + */ + other_sob_offset = (prop->curr_sob_offset + 1) % HL_RSVD_SOBS; + other_sob = &prop->hw_sob[other_sob_offset]; + + if (kref_read(&other_sob->kref) != 1) { + dev_err(hdev->dev, "error: Cannot switch SOBs q_idx: %d\n", + q_idx); + return -EINVAL; + } + + prop->next_sob_val = 1; + + /* only two SOBs are currently in use */ + prop->curr_sob_offset = other_sob_offset; + *hw_sob = other_sob; + + dev_dbg(hdev->dev, "switched to SOB %d, q_idx: %d\n", + prop->curr_sob_offset, q_idx); + } else { + prop->next_sob_val += count; + } + + return 0; +} + static int cs_ioctl_extract_signal_seq(struct hl_device *hdev, struct hl_cs_chunk *chunk, u64 *signal_seq, struct hl_ctx *ctx) { diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index fad112a01009..98aa8524a6a6 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -2642,6 +2642,8 @@ int hl_set_voltage(struct hl_device *hdev, int hl_set_current(struct hl_device *hdev, int sensor_index, u32 attr, long value); void hl_release_pending_user_interrupts(struct hl_device *hdev); +int hl_cs_signal_sob_wraparound_handler(struct hl_device *hdev, u32 q_idx, + struct hl_hw_sob **hw_sob, u32 count); #ifdef CONFIG_DEBUG_FS diff --git a/drivers/misc/habanalabs/common/hw_queue.c b/drivers/misc/habanalabs/common/hw_queue.c index 173438461835..bcabfdbf1e01 100644 --- a/drivers/misc/habanalabs/common/hw_queue.c +++ b/drivers/misc/habanalabs/common/hw_queue.c @@ -410,19 +410,20 @@ static void hw_queue_schedule_job(struct hl_cs_job *job) ext_and_hw_queue_submit_bd(hdev, q, ctl, len, ptr); } -static void init_signal_cs(struct hl_device *hdev, +static int init_signal_cs(struct hl_device *hdev, struct hl_cs_job *job, struct hl_cs_compl *cs_cmpl) { struct hl_sync_stream_properties *prop; struct hl_hw_sob *hw_sob; u32 q_idx; + int rc = 0; q_idx = job->hw_queue_id; prop = &hdev->kernel_queues[q_idx].sync_stream_prop; hw_sob = &prop->hw_sob[prop->curr_sob_offset]; cs_cmpl->hw_sob = hw_sob; - cs_cmpl->sob_val = prop->next_sob_val++; + cs_cmpl->sob_val = prop->next_sob_val; dev_dbg(hdev->dev, "generate signal CB, sob_id: %d, sob val: 0x%x, q_idx: %d\n", @@ -434,24 +435,9 @@ static void init_signal_cs(struct hl_device *hdev, hdev->asic_funcs->gen_signal_cb(hdev, job->patched_cb, cs_cmpl->hw_sob->sob_id, 0, true); - kref_get(&hw_sob->kref); + rc = hl_cs_signal_sob_wraparound_handler(hdev, q_idx, &hw_sob, 1); - /* check for wraparound */ - if (prop->next_sob_val == HL_MAX_SOB_VAL) { - /* - * Decrement as we reached the max value. - * The release function won't be called here as we've - * just incremented the refcount. - */ - kref_put(&hw_sob->kref, hl_sob_reset_error); - prop->next_sob_val = 1; - /* only two SOBs are currently in use */ - prop->curr_sob_offset = - (prop->curr_sob_offset + 1) % HL_RSVD_SOBS; - - dev_dbg(hdev->dev, "switched to SOB %d, q_idx: %d\n", - prop->curr_sob_offset, q_idx); - } + return rc; } static void init_wait_cs(struct hl_device *hdev, struct hl_cs *cs, @@ -504,22 +490,25 @@ static void init_wait_cs(struct hl_device *hdev, struct hl_cs *cs, * * H/W queues spinlock should be taken before calling this function */ -static void init_signal_wait_cs(struct hl_cs *cs) +static int init_signal_wait_cs(struct hl_cs *cs) { struct hl_ctx *ctx = cs->ctx; struct hl_device *hdev = ctx->hdev; struct hl_cs_job *job; struct hl_cs_compl *cs_cmpl = container_of(cs->fence, struct hl_cs_compl, base_fence); + int rc = 0; /* There is only one job in a signal/wait CS */ job = list_first_entry(&cs->job_list, struct hl_cs_job, cs_node); if (cs->type & CS_TYPE_SIGNAL) - init_signal_cs(hdev, job, cs_cmpl); + rc = init_signal_cs(hdev, job, cs_cmpl); else if (cs->type & CS_TYPE_WAIT) init_wait_cs(hdev, cs, job, cs_cmpl); + + return rc; } /* @@ -590,11 +579,16 @@ int hl_hw_queue_schedule_cs(struct hl_cs *cs) } } - if ((cs->type == CS_TYPE_SIGNAL) || (cs->type == CS_TYPE_WAIT)) - init_signal_wait_cs(cs); - else if (cs->type == CS_TYPE_COLLECTIVE_WAIT) + if ((cs->type == CS_TYPE_SIGNAL) || (cs->type == CS_TYPE_WAIT)) { + rc = init_signal_wait_cs(cs); + if (rc) { + dev_err(hdev->dev, "Failed to submit signal cs\n"); + goto unroll_cq_resv; + } + } else if (cs->type == CS_TYPE_COLLECTIVE_WAIT) hdev->asic_funcs->collective_wait_init_cs(cs); + spin_lock(&hdev->cs_mirror_lock); /* Verify staged CS exists and add to the staged list */ -- cgit v1.2.3 From 6c31f494d8a9cf7e6081f94717a46ce789da6bc6 Mon Sep 17 00:00:00 2001 From: Ofir Bitton Date: Thu, 17 Jun 2021 09:52:55 +0300 Subject: habanalabs/gaudi: add support for NIC DERR We add support for NIC DERR ECC error events, in case this error is received a device reset will be performed. Signed-off-by: Ofir Bitton Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/gaudi/gaudi.c | 1 + .../misc/habanalabs/include/gaudi/gaudi_async_events.h | 5 +++++ .../include/gaudi/gaudi_async_ids_map_extended.h | 15 ++++++++++----- 3 files changed, 16 insertions(+), 5 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 4a75df240cfc..82d5613f291b 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -7870,6 +7870,7 @@ static void gaudi_handle_eqe(struct hl_device *hdev, case GAUDI_EVENT_DMA_IF0_DERR ... GAUDI_EVENT_DMA_IF3_DERR: case GAUDI_EVENT_HBM_0_DERR ... GAUDI_EVENT_HBM_3_DERR: case GAUDI_EVENT_MMU_DERR: + case GAUDI_EVENT_NIC0_CS_DBG_DERR ... GAUDI_EVENT_NIC4_CS_DBG_DERR: gaudi_print_irq_info(hdev, event_type, true); gaudi_handle_ecc_event(hdev, event_type, &eq_entry->ecc_data); goto reset_device; diff --git a/drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h b/drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h index 2aee18e19b5a..d966bd4dfea6 100644 --- a/drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h +++ b/drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h @@ -252,6 +252,11 @@ enum gaudi_async_event_id { GAUDI_EVENT_HBM3_SPI_0 = 407, GAUDI_EVENT_HBM3_SPI_1 = 408, GAUDI_EVENT_PSOC_GPIO_U16_0 = 421, + GAUDI_EVENT_NIC0_CS_DBG_DERR = 483, + GAUDI_EVENT_NIC1_CS_DBG_DERR = 487, + GAUDI_EVENT_NIC2_CS_DBG_DERR = 491, + GAUDI_EVENT_NIC3_CS_DBG_DERR = 495, + GAUDI_EVENT_NIC4_CS_DBG_DERR = 499, GAUDI_EVENT_RAZWI_OR_ADC = 548, GAUDI_EVENT_TPC0_QM = 572, GAUDI_EVENT_TPC1_QM = 573, diff --git a/drivers/misc/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h b/drivers/misc/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h index ac4d4b51da7f..479b6b038254 100644 --- a/drivers/misc/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h +++ b/drivers/misc/habanalabs/include/gaudi/gaudi_async_ids_map_extended.h @@ -507,23 +507,28 @@ static struct gaudi_async_events_ids_map gaudi_irq_map_table[] = { { .fc_id = 480, .cpu_id = 329, .valid = 0, .name = "" }, { .fc_id = 481, .cpu_id = 330, .valid = 0, .name = "" }, { .fc_id = 482, .cpu_id = 331, .valid = 0, .name = "" }, - { .fc_id = 483, .cpu_id = 332, .valid = 0, .name = "" }, + { .fc_id = 483, .cpu_id = 332, .valid = 1, + .name = "NIC0_CS_DBG_DERR" }, { .fc_id = 484, .cpu_id = 333, .valid = 0, .name = "" }, { .fc_id = 485, .cpu_id = 334, .valid = 0, .name = "" }, { .fc_id = 486, .cpu_id = 335, .valid = 0, .name = "" }, - { .fc_id = 487, .cpu_id = 336, .valid = 0, .name = "" }, + { .fc_id = 487, .cpu_id = 336, .valid = 1, + .name = "NIC1_CS_DBG_DERR" }, { .fc_id = 488, .cpu_id = 337, .valid = 0, .name = "" }, { .fc_id = 489, .cpu_id = 338, .valid = 0, .name = "" }, { .fc_id = 490, .cpu_id = 339, .valid = 0, .name = "" }, - { .fc_id = 491, .cpu_id = 340, .valid = 0, .name = "" }, + { .fc_id = 491, .cpu_id = 340, .valid = 1, + .name = "NIC2_CS_DBG_DERR" }, { .fc_id = 492, .cpu_id = 341, .valid = 0, .name = "" }, { .fc_id = 493, .cpu_id = 342, .valid = 0, .name = "" }, { .fc_id = 494, .cpu_id = 343, .valid = 0, .name = "" }, - { .fc_id = 495, .cpu_id = 344, .valid = 0, .name = "" }, + { .fc_id = 495, .cpu_id = 344, .valid = 1, + .name = "NIC3_CS_DBG_DERR" }, { .fc_id = 496, .cpu_id = 345, .valid = 0, .name = "" }, { .fc_id = 497, .cpu_id = 346, .valid = 0, .name = "" }, { .fc_id = 498, .cpu_id = 347, .valid = 0, .name = "" }, - { .fc_id = 499, .cpu_id = 348, .valid = 0, .name = "" }, + { .fc_id = 499, .cpu_id = 348, .valid = 1, + .name = "NIC4_CS_DBG_DERR" }, { .fc_id = 500, .cpu_id = 349, .valid = 0, .name = "" }, { .fc_id = 501, .cpu_id = 350, .valid = 0, .name = "" }, { .fc_id = 502, .cpu_id = 351, .valid = 0, .name = "" }, -- cgit v1.2.3 From b7a71fddc0ddfdd66cdefcf5bf1f59a0f0bdea57 Mon Sep 17 00:00:00 2001 From: Koby Elbaz Date: Tue, 15 Jun 2021 17:07:02 +0300 Subject: habanalabs/gaudi: refactor hard-reset related code There is code related to hard-reset, which is done in gaudi specific code. However, this code can be used by future ASICs and therefore it is better to move it to the common code section. Signed-off-by: Koby Elbaz Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 41 ++++++++++++++++++++++++ drivers/misc/habanalabs/common/habanalabs.h | 9 ++++++ drivers/misc/habanalabs/gaudi/gaudi.c | 48 ++++------------------------ drivers/misc/habanalabs/gaudi/gaudiP.h | 5 --- 4 files changed, 56 insertions(+), 47 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index ce87053d4fde..2e4d04ec6b53 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -972,6 +972,47 @@ int hl_fw_cpucp_power_get(struct hl_device *hdev, u64 *power) return rc; } +void hl_fw_ask_hard_reset_without_linux(struct hl_device *hdev) +{ + struct static_fw_load_mgr *static_loader = + &hdev->fw_loader.static_loader; + int rc; + + if (hdev->asic_prop.dynamic_fw_load) { + rc = hl_fw_dynamic_send_protocol_cmd(hdev, &hdev->fw_loader, + COMMS_RST_DEV, 0, false, + hdev->fw_loader.cpu_timeout); + if (rc) + dev_warn(hdev->dev, "Failed sending COMMS_RST_DEV\n"); + } else { + WREG32(static_loader->kmd_msg_to_cpu_reg, KMD_MSG_RST_DEV); + } +} + +void hl_fw_ask_halt_machine_without_linux(struct hl_device *hdev) +{ + struct static_fw_load_mgr *static_loader = + &hdev->fw_loader.static_loader; + int rc; + + if (hdev->device_cpu_is_halted) + return; + + /* Stop device CPU to make sure nothing bad happens */ + if (hdev->asic_prop.dynamic_fw_load) { + rc = hl_fw_dynamic_send_protocol_cmd(hdev, &hdev->fw_loader, + COMMS_GOTO_WFE, 0, true, + hdev->fw_loader.cpu_timeout); + if (rc) + dev_warn(hdev->dev, "Failed sending COMMS_GOTO_WFE\n"); + } else { + WREG32(static_loader->kmd_msg_to_cpu_reg, KMD_MSG_GOTO_WFE); + msleep(static_loader->cpu_reset_wait_msec); + } + + hdev->device_cpu_is_halted = true; +} + static void detect_cpu_boot_status(struct hl_device *hdev, u32 status) { /* Some of the status codes below are deprecated in newer f/w diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index 98aa8524a6a6..6b3cdd7e068a 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -894,6 +894,7 @@ struct pci_mem_region { * @preboot_version_offset_reg: SRAM offset to preboot version register * @boot_fit_version_offset_reg: SRAM offset to boot fit version register * @sram_offset_mask: mask for getting offset into the SRAM + * @cpu_reset_wait_msec: used when setting WFE via kmd_msg_to_cpu_reg */ struct static_fw_load_mgr { u64 preboot_version_max_off; @@ -908,6 +909,7 @@ struct static_fw_load_mgr { u32 preboot_version_offset_reg; u32 boot_fit_version_offset_reg; u32 sram_offset_mask; + u32 cpu_reset_wait_msec; }; /** @@ -2199,6 +2201,10 @@ struct hl_mmu_funcs { * triggered, and cleared after it is shared with preboot. * @skip_reset_on_timeout: Skip device reset if CS has timed out, wait for it to * complete instead. + * @device_cpu_is_halted: Flag to indicate whether the device CPU was already + * halted. We can't halt it again because the COMMS + * protocol will throw an error. Relevant only for + * cases where Linux was not loaded to device CPU */ struct hl_device { struct pci_dev *pdev; @@ -2315,6 +2321,7 @@ struct hl_device { u8 supports_staged_submission; u8 curr_reset_cause; u8 skip_reset_on_timeout; + u8 device_cpu_is_halted; /* Parameters for bring-up */ u64 nic_ports_mask; @@ -2596,6 +2603,8 @@ int get_used_pll_index(struct hl_device *hdev, u32 input_pll_index, int hl_fw_cpucp_pll_info_get(struct hl_device *hdev, u32 pll_index, u16 *pll_freq_arr); int hl_fw_cpucp_power_get(struct hl_device *hdev, u64 *power); +void hl_fw_ask_hard_reset_without_linux(struct hl_device *hdev); +void hl_fw_ask_halt_machine_without_linux(struct hl_device *hdev); int hl_fw_init_cpu(struct hl_device *hdev); int hl_fw_read_preboot_status(struct hl_device *hdev, u32 cpu_boot_status_reg, u32 sts_boot_dev_sts0_reg, diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 82d5613f291b..aa8a0ca5aca2 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -1934,45 +1934,6 @@ static void gaudi_disable_msi(struct hl_device *hdev) gaudi->hw_cap_initialized &= ~HW_CAP_MSI; } -static void gaudi_ask_hard_reset_without_linux(struct hl_device *hdev) -{ - int rc; - - if (hdev->asic_prop.dynamic_fw_load) { - rc = hl_fw_dynamic_send_protocol_cmd(hdev, &hdev->fw_loader, - COMMS_RST_DEV, 0, false, - hdev->fw_loader.cpu_timeout); - if (rc) - dev_warn(hdev->dev, "Failed sending COMMS_RST_DEV\n"); - } else { - WREG32(mmPSOC_GLOBAL_CONF_KMD_MSG_TO_CPU, KMD_MSG_RST_DEV); - } -} - -static void gaudi_ask_halt_machine_without_linux(struct hl_device *hdev) -{ - struct gaudi_device *gaudi = hdev->asic_specific; - int rc; - - if (gaudi && gaudi->device_cpu_is_halted) - return; - - /* Stop device CPU to make sure nothing bad happens */ - if (hdev->asic_prop.dynamic_fw_load) { - rc = hl_fw_dynamic_send_protocol_cmd(hdev, &hdev->fw_loader, - COMMS_GOTO_WFE, 0, true, - hdev->fw_loader.cpu_timeout); - if (rc) - dev_warn(hdev->dev, "Failed sending COMMS_GOTO_WFE\n"); - } else { - WREG32(mmPSOC_GLOBAL_CONF_KMD_MSG_TO_CPU, KMD_MSG_GOTO_WFE); - msleep(GAUDI_CPU_RESET_WAIT_MSEC); - } - - if (gaudi) - gaudi->device_cpu_is_halted = true; -} - static void gaudi_init_scrambler_sram(struct hl_device *hdev) { struct gaudi_device *gaudi = hdev->asic_specific; @@ -3859,6 +3820,9 @@ static void gaudi_init_static_firmware_loader(struct hl_device *hdev) static_loader->preboot_version_offset_reg = mmPREBOOT_VER_OFFSET; static_loader->boot_fit_version_offset_reg = mmUBOOT_VER_OFFSET; static_loader->sram_offset_mask = ~(lower_32_bits(SRAM_BASE_ADDR)); + static_loader->cpu_reset_wait_msec = hdev->pldm ? + GAUDI_PLDM_RESET_WAIT_MSEC : + GAUDI_CPU_RESET_WAIT_MSEC; } static void gaudi_init_firmware_loader(struct hl_device *hdev) @@ -4151,9 +4115,9 @@ static void gaudi_hw_fini(struct hl_device *hdev, bool hard_reset) gaudi_irq_map_table[GAUDI_EVENT_HALT_MACHINE].cpu_id); } else { if (hdev->asic_prop.hard_reset_done_by_fw) - gaudi_ask_hard_reset_without_linux(hdev); + hl_fw_ask_hard_reset_without_linux(hdev); else - gaudi_ask_halt_machine_without_linux(hdev); + hl_fw_ask_halt_machine_without_linux(hdev); } if (driver_performs_reset) { @@ -4228,7 +4192,7 @@ static void gaudi_hw_fini(struct hl_device *hdev, bool hard_reset) memset(gaudi->events_stat, 0, sizeof(gaudi->events_stat)); - gaudi->device_cpu_is_halted = false; + hdev->device_cpu_is_halted = false; } } diff --git a/drivers/misc/habanalabs/gaudi/gaudiP.h b/drivers/misc/habanalabs/gaudi/gaudiP.h index b23336af191e..957bf3720f70 100644 --- a/drivers/misc/habanalabs/gaudi/gaudiP.h +++ b/drivers/misc/habanalabs/gaudi/gaudiP.h @@ -315,10 +315,6 @@ struct gaudi_internal_qman_info { * Multi MSI is possible only with IOMMU enabled. * @mmu_cache_inv_pi: PI for MMU cache invalidation flow. The H/W expects an * 8-bit value so use u8. - * @device_cpu_is_halted: Flag to indicate whether the device CPU was already - * halted. We can't halt it again because the COMMS - * protocol will throw an error. Relevant only for - * cases where Linux was not loaded to device CPU */ struct gaudi_device { int (*cpucp_info_get)(struct hl_device *hdev); @@ -340,7 +336,6 @@ struct gaudi_device { u32 hw_cap_initialized; u8 multi_msi_mode; u8 mmu_cache_inv_pi; - u8 device_cpu_is_halted; }; void gaudi_init_security(struct hl_device *hdev); -- cgit v1.2.3 From 09f8c33a4cad3623874766033544abf34e3e365d Mon Sep 17 00:00:00 2001 From: Tamar Mashiah Date: Mon, 21 Jun 2021 22:37:55 +0300 Subject: mei: fix kdoc in the driver Over time the functions were renamed, but this was not always reflected in kdoc, fix that. Signed-off-by: Tamar Mashiah Signed-off-by: Tomas Winkler Link: https://lore.kernel.org/r/20210621193756.134027-1-tomas.winkler@intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/bus-fixup.c | 2 +- drivers/misc/mei/client.c | 6 +++--- drivers/misc/mei/hbm.c | 2 +- drivers/misc/mei/hw-me.c | 4 ++-- drivers/misc/mei/hw.h | 2 +- drivers/misc/mei/main.c | 2 +- drivers/misc/mei/pci-txe.c | 2 +- drivers/watchdog/mei_wdt.c | 4 ++-- 8 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/mei/bus-fixup.c b/drivers/misc/mei/bus-fixup.c index d8e760b11ae3..67844089db21 100644 --- a/drivers/misc/mei/bus-fixup.c +++ b/drivers/misc/mei/bus-fixup.c @@ -498,7 +498,7 @@ static struct mei_fixup { }; /** - * mei_cldev_fixup - run fixup handlers + * mei_cl_bus_dev_fixup - run fixup handlers * * @cldev: me client device */ diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index 2cc370adb238..18e49479d8b0 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -326,7 +326,7 @@ void mei_io_cb_free(struct mei_cl_cb *cb) } /** - * mei_tx_cb_queue - queue tx callback + * mei_tx_cb_enqueue - queue tx callback * * Locking: called under "dev->device_lock" lock * @@ -2250,7 +2250,7 @@ static void mei_cl_dma_free(struct mei_cl *cl) } /** - * mei_cl_alloc_and_map - send client dma map request + * mei_cl_dma_alloc_and_map - send client dma map request * * @cl: host client * @fp: pointer to file structure @@ -2349,7 +2349,7 @@ out: } /** - * mei_cl_unmap_and_free - send client dma unmap request + * mei_cl_dma_unmap - send client dma unmap request * * @cl: host client * @fp: pointer to file structure diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c index d0277c7fed10..99b5c1ecc444 100644 --- a/drivers/misc/mei/hbm.c +++ b/drivers/misc/mei/hbm.c @@ -853,7 +853,7 @@ out: } /** - * mei_hbm_cl_flow_control_res - flow control response from me + * mei_hbm_cl_tx_flow_ctrl_creds_res - flow control response from me * * @dev: the device structure * @fctrl: flow control response bus message diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c index cda0829ac589..d3a6c0728645 100644 --- a/drivers/misc/mei/hw-me.c +++ b/drivers/misc/mei/hw-me.c @@ -1380,7 +1380,7 @@ static bool mei_me_fw_type_nm(const struct pci_dev *pdev) .quirk_probe = mei_me_fw_type_nm /** - * mei_me_fw_sku_sps_4() - check for sps 4.0 sku + * mei_me_fw_type_sps_4() - check for sps 4.0 sku * * Read ME FW Status register to check for SPS Firmware. * The SPS FW is only signaled in the PCI function 0. @@ -1405,7 +1405,7 @@ static bool mei_me_fw_type_sps_4(const struct pci_dev *pdev) .quirk_probe = mei_me_fw_type_sps_4 /** - * mei_me_fw_sku_sps() - check for sps sku + * mei_me_fw_type_sps() - check for sps sku * * Read ME FW Status register to check for SPS Firmware. * The SPS FW is only signaled in pci function 0 diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h index b10606550613..47ef2429a4bc 100644 --- a/drivers/misc/mei/hw.h +++ b/drivers/misc/mei/hw.h @@ -284,7 +284,7 @@ static inline bool mei_ext_last(struct mei_ext_meta_hdr *meta, } /** - *mei_ext_next - following extended header on the TLV list + * mei_ext_next - following extended header on the TLV list * * @ext: current extend header * diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 9001c45f6fc4..786f7c8f7f61 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -1102,7 +1102,7 @@ static ssize_t dev_state_show(struct device *device, static DEVICE_ATTR_RO(dev_state); /** - * dev_set_devstate: set to new device state and notify sysfs file. + * mei_set_devstate: set to new device state and notify sysfs file. * * @dev: mei_device * @state: new device state diff --git a/drivers/misc/mei/pci-txe.c b/drivers/misc/mei/pci-txe.c index 4bf26ce61044..aec0483b8e72 100644 --- a/drivers/misc/mei/pci-txe.c +++ b/drivers/misc/mei/pci-txe.c @@ -156,7 +156,7 @@ end: } /** - * mei_txe_remove - Device Shutdown Routine + * mei_txe_shutdown- Device Shutdown Routine * * @pdev: PCI device structure * diff --git a/drivers/watchdog/mei_wdt.c b/drivers/watchdog/mei_wdt.c index e023d7d90d66..c8ac36135e28 100644 --- a/drivers/watchdog/mei_wdt.c +++ b/drivers/watchdog/mei_wdt.c @@ -121,7 +121,7 @@ struct mei_mc_hdr { }; /** - * struct mei_wdt_start_request watchdog start/ping + * struct mei_wdt_start_request - watchdog start/ping * * @hdr: Management Control Command Header * @timeout: timeout value @@ -134,7 +134,7 @@ struct mei_wdt_start_request { } __packed; /** - * struct mei_wdt_start_response watchdog start/ping response + * struct mei_wdt_start_response - watchdog start/ping response * * @hdr: Management Control Command Header * @status: operation status -- cgit v1.2.3 From 40292383640a2a4f73632e08a553681d0d88c80a Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Mon, 21 Jun 2021 22:37:56 +0300 Subject: mei: revamp mei extension header structure layout. The mei extension header was build as array of flexible structures which will not work if actually more headers are added. (Currently only vtag header was used). Sparse reports: drivers/misc/mei/hw.h:253:32: warning: array of flexible structures Use basic type u8 for the variable sized extension. Define explicitly mei_ext_hdr_vtag structure. And also fix mei_ext_next() function to point correctly to the end of the header. Note: the headers are part of firmware interface and need to be __packed. Signed-off-by: Tomas Winkler Link: https://lore.kernel.org/r/20210621193756.134027-2-tomas.winkler@intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/client.c | 16 +++++++++------- drivers/misc/mei/hw.h | 26 +++++++++++++++++++------- drivers/misc/mei/interrupt.c | 23 ++++++++++------------- 3 files changed, 38 insertions(+), 27 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index 18e49479d8b0..96f4e59c32a5 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -1726,12 +1726,15 @@ nortpm: return rets; } -static inline u8 mei_ext_hdr_set_vtag(struct mei_ext_hdr *ext, u8 vtag) +static inline u8 mei_ext_hdr_set_vtag(void *ext, u8 vtag) { - ext->type = MEI_EXT_HDR_VTAG; - ext->ext_payload[0] = vtag; - ext->length = mei_data2slots(sizeof(*ext)); - return ext->length; + struct mei_ext_hdr_vtag *vtag_hdr = ext; + + vtag_hdr->hdr.type = MEI_EXT_HDR_VTAG; + vtag_hdr->hdr.length = mei_data2slots(sizeof(*vtag_hdr)); + vtag_hdr->vtag = vtag; + vtag_hdr->reserved = 0; + return vtag_hdr->hdr.length; } /** @@ -1745,7 +1748,6 @@ static struct mei_msg_hdr *mei_msg_hdr_init(const struct mei_cl_cb *cb) { size_t hdr_len; struct mei_ext_meta_hdr *meta; - struct mei_ext_hdr *ext; struct mei_msg_hdr *mei_hdr; bool is_ext, is_vtag; @@ -1764,7 +1766,7 @@ static struct mei_msg_hdr *mei_msg_hdr_init(const struct mei_cl_cb *cb) hdr_len += sizeof(*meta); if (is_vtag) - hdr_len += sizeof(*ext); + hdr_len += sizeof(struct mei_ext_hdr_vtag); setup_hdr: mei_hdr = kzalloc(hdr_len, GFP_KERNEL); diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h index 47ef2429a4bc..dfd60c916da0 100644 --- a/drivers/misc/mei/hw.h +++ b/drivers/misc/mei/hw.h @@ -235,9 +235,8 @@ enum mei_ext_hdr_type { struct mei_ext_hdr { u8 type; u8 length; - u8 ext_payload[2]; - u8 hdr[]; -}; + u8 data[]; +} __packed; /** * struct mei_ext_meta_hdr - extend header meta data @@ -250,8 +249,21 @@ struct mei_ext_meta_hdr { u8 count; u8 size; u8 reserved[2]; - struct mei_ext_hdr hdrs[]; -}; + u8 hdrs[]; +} __packed; + +/** + * struct mei_ext_hdr_vtag - extend header for vtag + * + * @hdr: standard extend header + * @vtag: virtual tag + * @reserved: reserved + */ +struct mei_ext_hdr_vtag { + struct mei_ext_hdr hdr; + u8 vtag; + u8 reserved; +} __packed; /* * Extended header iterator functions @@ -266,7 +278,7 @@ struct mei_ext_meta_hdr { */ static inline struct mei_ext_hdr *mei_ext_begin(struct mei_ext_meta_hdr *meta) { - return meta->hdrs; + return (struct mei_ext_hdr *)meta->hdrs; } /** @@ -295,7 +307,7 @@ static inline bool mei_ext_last(struct mei_ext_meta_hdr *meta, */ static inline struct mei_ext_hdr *mei_ext_next(struct mei_ext_hdr *ext) { - return (struct mei_ext_hdr *)(ext->hdr + (ext->length * 4)); + return (struct mei_ext_hdr *)((u8 *)ext + (ext->length * 4)); } /** diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index aab3ebfa9fc4..a67f4f2d33a9 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -123,13 +123,13 @@ static int mei_cl_irq_read_msg(struct mei_cl *cl, if (mei_hdr->extended) { struct mei_ext_hdr *ext; - struct mei_ext_hdr *vtag = NULL; + struct mei_ext_hdr_vtag *vtag_hdr = NULL; ext = mei_ext_begin(meta); do { switch (ext->type) { case MEI_EXT_HDR_VTAG: - vtag = ext; + vtag_hdr = (struct mei_ext_hdr_vtag *)ext; break; case MEI_EXT_HDR_NONE: fallthrough; @@ -141,20 +141,20 @@ static int mei_cl_irq_read_msg(struct mei_cl *cl, ext = mei_ext_next(ext); } while (!mei_ext_last(meta, ext)); - if (!vtag) { + if (!vtag_hdr) { cl_dbg(dev, cl, "vtag not found in extended header.\n"); cb->status = -EPROTO; goto discard; } - cl_dbg(dev, cl, "vtag: %d\n", vtag->ext_payload[0]); - if (cb->vtag && cb->vtag != vtag->ext_payload[0]) { + cl_dbg(dev, cl, "vtag: %d\n", vtag_hdr->vtag); + if (cb->vtag && cb->vtag != vtag_hdr->vtag) { cl_err(dev, cl, "mismatched tag: %d != %d\n", - cb->vtag, vtag->ext_payload[0]); + cb->vtag, vtag_hdr->vtag); cb->status = -EPROTO; goto discard; } - cb->vtag = vtag->ext_payload[0]; + cb->vtag = vtag_hdr->vtag; } if (!mei_cl_is_connected(cl)) { @@ -331,7 +331,6 @@ int mei_irq_read_handler(struct mei_device *dev, struct mei_ext_meta_hdr *meta_hdr = NULL; struct mei_cl *cl; int ret; - u32 ext_meta_hdr_u32; u32 hdr_size_left; u32 hdr_size_ext; int i; @@ -367,14 +366,12 @@ int mei_irq_read_handler(struct mei_device *dev, if (mei_hdr->extended) { if (!dev->rd_msg_hdr[1]) { - ext_meta_hdr_u32 = mei_read_hdr(dev); - dev->rd_msg_hdr[1] = ext_meta_hdr_u32; + dev->rd_msg_hdr[1] = mei_read_hdr(dev); dev->rd_msg_hdr_count++; (*slots)--; - dev_dbg(dev->dev, "extended header is %08x\n", - ext_meta_hdr_u32); + dev_dbg(dev->dev, "extended header is %08x\n", dev->rd_msg_hdr[1]); } - meta_hdr = ((struct mei_ext_meta_hdr *)dev->rd_msg_hdr + 1); + meta_hdr = ((struct mei_ext_meta_hdr *)&dev->rd_msg_hdr[1]); if (check_add_overflow((u32)sizeof(*meta_hdr), mei_slots2data(meta_hdr->size), &hdr_size_ext)) { -- cgit v1.2.3 From a15676ac8f24a9ac5fd881cf17be4be13fa0910a Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 23 Jun 2021 13:39:31 -0700 Subject: lkdtm/bugs: XFAIL UNALIGNED_LOAD_STORE_WRITE When built under CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS, this test is expected to fail (i.e. not trip an exception). Fixes: 46d1a0f03d66 ("selftests/lkdtm: Add tests for LKDTM targets") Cc: stable@vger.kernel.org Signed-off-by: Kees Cook Link: https://lore.kernel.org/r/20210623203936.3151093-5-keescook@chromium.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/lkdtm/bugs.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/misc') diff --git a/drivers/misc/lkdtm/bugs.c b/drivers/misc/lkdtm/bugs.c index 0e8254d0cf0b..9ff02bdf3153 100644 --- a/drivers/misc/lkdtm/bugs.c +++ b/drivers/misc/lkdtm/bugs.c @@ -161,6 +161,9 @@ void lkdtm_UNALIGNED_LOAD_STORE_WRITE(void) if (*p == 0) val = 0x87654321; *p = val; + + if (IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)) + pr_err("XFAIL: arch has CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS\n"); } void lkdtm_SOFTLOCKUP(void) -- cgit v1.2.3 From 9c4f6ebc3665b33f15ee97ba1eb2c9bed341b8e6 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 23 Jun 2021 13:39:32 -0700 Subject: lkdtm/heap: Add vmalloc linear overflow test Similar to the existing slab overflow and stack exhaustion tests, add VMALLOC_LINEAR_OVERFLOW (and rename the slab test SLAB_LINEAR_OVERFLOW). Additionally unmarks the test as destructive. (It should be safe in the face of misbehavior.) Signed-off-by: Kees Cook Link: https://lore.kernel.org/r/20210623203936.3151093-6-keescook@chromium.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/lkdtm/core.c | 3 ++- drivers/misc/lkdtm/heap.c | 22 +++++++++++++++++++++- drivers/misc/lkdtm/lkdtm.h | 3 ++- tools/testing/selftests/lkdtm/tests.txt | 3 ++- 4 files changed, 27 insertions(+), 4 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/lkdtm/core.c b/drivers/misc/lkdtm/core.c index 8024b6a5cc7f..645b31e98c77 100644 --- a/drivers/misc/lkdtm/core.c +++ b/drivers/misc/lkdtm/core.c @@ -120,7 +120,8 @@ static const struct crashtype crashtypes[] = { CRASHTYPE(UNALIGNED_LOAD_STORE_WRITE), CRASHTYPE(FORTIFY_OBJECT), CRASHTYPE(FORTIFY_SUBOBJECT), - CRASHTYPE(OVERWRITE_ALLOCATION), + CRASHTYPE(SLAB_LINEAR_OVERFLOW), + CRASHTYPE(VMALLOC_LINEAR_OVERFLOW), CRASHTYPE(WRITE_AFTER_FREE), CRASHTYPE(READ_AFTER_FREE), CRASHTYPE(WRITE_BUDDY_AFTER_FREE), diff --git a/drivers/misc/lkdtm/heap.c b/drivers/misc/lkdtm/heap.c index 1323bc16f113..36be5e353cd0 100644 --- a/drivers/misc/lkdtm/heap.c +++ b/drivers/misc/lkdtm/heap.c @@ -5,24 +5,44 @@ */ #include "lkdtm.h" #include +#include #include static struct kmem_cache *double_free_cache; static struct kmem_cache *a_cache; static struct kmem_cache *b_cache; +/* + * If there aren't guard pages, it's likely that a consecutive allocation will + * let us overflow into the second allocation without overwriting something real. + */ +void lkdtm_VMALLOC_LINEAR_OVERFLOW(void) +{ + char *one, *two; + + one = vzalloc(PAGE_SIZE); + two = vzalloc(PAGE_SIZE); + + pr_info("Attempting vmalloc linear overflow ...\n"); + memset(one, 0xAA, PAGE_SIZE + 1); + + vfree(two); + vfree(one); +} + /* * This tries to stay within the next largest power-of-2 kmalloc cache * to avoid actually overwriting anything important if it's not detected * correctly. */ -void lkdtm_OVERWRITE_ALLOCATION(void) +void lkdtm_SLAB_LINEAR_OVERFLOW(void) { size_t len = 1020; u32 *data = kmalloc(len, GFP_KERNEL); if (!data) return; + pr_info("Attempting slab linear overflow ...\n"); data[1024 / sizeof(u32)] = 0x12345678; kfree(data); } diff --git a/drivers/misc/lkdtm/lkdtm.h b/drivers/misc/lkdtm/lkdtm.h index 99f90d3e5e9c..c6baf4f1e1db 100644 --- a/drivers/misc/lkdtm/lkdtm.h +++ b/drivers/misc/lkdtm/lkdtm.h @@ -39,7 +39,8 @@ void lkdtm_FORTIFY_SUBOBJECT(void); /* heap.c */ void __init lkdtm_heap_init(void); void __exit lkdtm_heap_exit(void); -void lkdtm_OVERWRITE_ALLOCATION(void); +void lkdtm_VMALLOC_LINEAR_OVERFLOW(void); +void lkdtm_SLAB_LINEAR_OVERFLOW(void); void lkdtm_WRITE_AFTER_FREE(void); void lkdtm_READ_AFTER_FREE(void); void lkdtm_WRITE_BUDDY_AFTER_FREE(void); diff --git a/tools/testing/selftests/lkdtm/tests.txt b/tools/testing/selftests/lkdtm/tests.txt index a94d4d8eeb5c..30080cc15623 100644 --- a/tools/testing/selftests/lkdtm/tests.txt +++ b/tools/testing/selftests/lkdtm/tests.txt @@ -15,7 +15,8 @@ UNSET_SMEP pinned CR4 bits changed: DOUBLE_FAULT CORRUPT_PAC UNALIGNED_LOAD_STORE_WRITE -#OVERWRITE_ALLOCATION Corrupts memory on failure +SLAB_LINEAR_OVERFLOW +VMALLOC_LINEAR_OVERFLOW #WRITE_AFTER_FREE Corrupts memory on failure READ_AFTER_FREE call trace:|Memory correctly poisoned #WRITE_BUDDY_AFTER_FREE Corrupts memory on failure -- cgit v1.2.3 From f123c42bbeff26bfe8bdb08a01307e92d51eec39 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 23 Jun 2021 13:39:33 -0700 Subject: lkdtm: Enable DOUBLE_FAULT on all architectures Where feasible, I prefer to have all tests visible on all architectures, but to have them wired to XFAIL. DOUBLE_FAIL was set up to XFAIL, but wasn't actually being added to the test list. Fixes: cea23efb4de2 ("lkdtm/bugs: Make double-fault test always available") Cc: stable@vger.kernel.org Signed-off-by: Kees Cook Link: https://lore.kernel.org/r/20210623203936.3151093-7-keescook@chromium.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/lkdtm/core.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/lkdtm/core.c b/drivers/misc/lkdtm/core.c index 645b31e98c77..2c89fc18669f 100644 --- a/drivers/misc/lkdtm/core.c +++ b/drivers/misc/lkdtm/core.c @@ -178,9 +178,7 @@ static const struct crashtype crashtypes[] = { CRASHTYPE(STACKLEAK_ERASING), CRASHTYPE(CFI_FORWARD_PROTO), CRASHTYPE(FORTIFIED_STRSCPY), -#ifdef CONFIG_X86_32 CRASHTYPE(DOUBLE_FAULT), -#endif #ifdef CONFIG_PPC_BOOK3S_64 CRASHTYPE(PPC_SLB_MULTIHIT), #endif -- cgit v1.2.3 From 5b777131bd8005acaf7e9d6e7690214155f42890 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 23 Jun 2021 13:39:34 -0700 Subject: lkdtm: Add CONFIG hints in errors where possible For various failure conditions, try to include some details about where to look for reasons about the failure. Signed-off-by: Kees Cook Link: https://lore.kernel.org/r/20210623203936.3151093-8-keescook@chromium.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/lkdtm/bugs.c | 8 +++- drivers/misc/lkdtm/cfi.c | 3 +- drivers/misc/lkdtm/core.c | 51 ++++++++++++++++++++++++++ drivers/misc/lkdtm/fortify.c | 3 +- drivers/misc/lkdtm/heap.c | 10 +++-- drivers/misc/lkdtm/lkdtm.h | 41 +++++++++++++++++++++ drivers/misc/lkdtm/stackleak.c | 4 +- drivers/misc/lkdtm/usercopy.c | 7 +++- tools/testing/selftests/lkdtm/stack-entropy.sh | 1 + 9 files changed, 117 insertions(+), 11 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/lkdtm/bugs.c b/drivers/misc/lkdtm/bugs.c index 9ff02bdf3153..7c7335506c45 100644 --- a/drivers/misc/lkdtm/bugs.c +++ b/drivers/misc/lkdtm/bugs.c @@ -303,8 +303,10 @@ void lkdtm_CORRUPT_LIST_ADD(void) if (target[0] == NULL && target[1] == NULL) pr_err("Overwrite did not happen, but no BUG?!\n"); - else + else { pr_err("list_add() corruption not detected!\n"); + pr_expected_config(CONFIG_DEBUG_LIST); + } } void lkdtm_CORRUPT_LIST_DEL(void) @@ -328,8 +330,10 @@ void lkdtm_CORRUPT_LIST_DEL(void) if (target[0] == NULL && target[1] == NULL) pr_err("Overwrite did not happen, but no BUG?!\n"); - else + else { pr_err("list_del() corruption not detected!\n"); + pr_expected_config(CONFIG_DEBUG_LIST); + } } /* Test that VMAP_STACK is actually allocating with a leading guard page */ diff --git a/drivers/misc/lkdtm/cfi.c b/drivers/misc/lkdtm/cfi.c index e73ebdbfa806..c9aeddef1044 100644 --- a/drivers/misc/lkdtm/cfi.c +++ b/drivers/misc/lkdtm/cfi.c @@ -38,5 +38,6 @@ void lkdtm_CFI_FORWARD_PROTO(void) func = (void *)lkdtm_increment_int; func(&called_count); - pr_info("Fail: survived mismatched prototype function call!\n"); + pr_err("FAIL: survived mismatched prototype function call!\n"); + pr_expected_config(CONFIG_CFI_CLANG); } diff --git a/drivers/misc/lkdtm/core.c b/drivers/misc/lkdtm/core.c index 2c89fc18669f..c185ae4719c3 100644 --- a/drivers/misc/lkdtm/core.c +++ b/drivers/misc/lkdtm/core.c @@ -26,6 +26,7 @@ #include #include #include +#include #define DEFAULT_COUNT 10 @@ -398,6 +399,56 @@ static ssize_t direct_entry(struct file *f, const char __user *user_buf, return count; } +#ifndef MODULE +/* + * To avoid needing to export parse_args(), just don't use this code + * when LKDTM is built as a module. + */ +struct check_cmdline_args { + const char *param; + int value; +}; + +static int lkdtm_parse_one(char *param, char *val, + const char *unused, void *arg) +{ + struct check_cmdline_args *args = arg; + + /* short circuit if we already found a value. */ + if (args->value != -ESRCH) + return 0; + if (strncmp(param, args->param, strlen(args->param)) == 0) { + bool bool_result; + int ret; + + ret = kstrtobool(val, &bool_result); + if (ret == 0) + args->value = bool_result; + } + return 0; +} + +int lkdtm_check_bool_cmdline(const char *param) +{ + char *command_line; + struct check_cmdline_args args = { + .param = param, + .value = -ESRCH, + }; + + command_line = kstrdup(saved_command_line, GFP_KERNEL); + if (!command_line) + return -ENOMEM; + + parse_args("Setting sysctl args", command_line, + NULL, 0, -1, -1, &args, lkdtm_parse_one); + + kfree(command_line); + + return args.value; +} +#endif + static struct dentry *lkdtm_debugfs_root; static int __init lkdtm_module_init(void) diff --git a/drivers/misc/lkdtm/fortify.c b/drivers/misc/lkdtm/fortify.c index faf29cf04baa..0f51d31b57ca 100644 --- a/drivers/misc/lkdtm/fortify.c +++ b/drivers/misc/lkdtm/fortify.c @@ -76,7 +76,8 @@ void lkdtm_FORTIFIED_STRSCPY(void) */ strscpy(dst, src, strlen(src)); - pr_warn("FAIL: No overflow in above strscpy()\n"); + pr_err("FAIL: strscpy() overflow not detected!\n"); + pr_expected_config(CONFIG_FORTIFY_SOURCE); kfree(src); } diff --git a/drivers/misc/lkdtm/heap.c b/drivers/misc/lkdtm/heap.c index 36be5e353cd0..a3bb0577ed8b 100644 --- a/drivers/misc/lkdtm/heap.c +++ b/drivers/misc/lkdtm/heap.c @@ -109,9 +109,10 @@ void lkdtm_READ_AFTER_FREE(void) if (saw != *val) { /* Good! Poisoning happened, so declare a win. */ pr_info("Memory correctly poisoned (%x)\n", saw); - BUG(); + } else { + pr_err("FAIL: Memory was not poisoned!\n"); + pr_expected_config_param(CONFIG_INIT_ON_FREE_DEFAULT_ON, "init_on_free"); } - pr_info("Memory was not poisoned\n"); kfree(val); } @@ -165,9 +166,10 @@ void lkdtm_READ_BUDDY_AFTER_FREE(void) if (saw != *val) { /* Good! Poisoning happened, so declare a win. */ pr_info("Memory correctly poisoned (%x)\n", saw); - BUG(); + } else { + pr_err("FAIL: Buddy page was not poisoned!\n"); + pr_expected_config_param(CONFIG_INIT_ON_FREE_DEFAULT_ON, "init_on_free"); } - pr_info("Buddy page was not poisoned\n"); kfree(val); } diff --git a/drivers/misc/lkdtm/lkdtm.h b/drivers/misc/lkdtm/lkdtm.h index c6baf4f1e1db..e491bc571808 100644 --- a/drivers/misc/lkdtm/lkdtm.h +++ b/drivers/misc/lkdtm/lkdtm.h @@ -6,6 +6,47 @@ #include +#define pr_expected_config(kconfig) \ +{ \ + if (IS_ENABLED(kconfig)) \ + pr_err("Unexpected! This kernel was built with " #kconfig "=y\n"); \ + else \ + pr_warn("This is probably expected, since this kernel was built *without* " #kconfig "=y\n"); \ +} + +#ifndef MODULE +int lkdtm_check_bool_cmdline(const char *param); +#define pr_expected_config_param(kconfig, param) \ +{ \ + if (IS_ENABLED(kconfig)) { \ + switch (lkdtm_check_bool_cmdline(param)) { \ + case 0: \ + pr_warn("This is probably expected, since this kernel was built with " #kconfig "=y but booted with '" param "=N'\n"); \ + break; \ + case 1: \ + pr_err("Unexpected! This kernel was built with " #kconfig "=y and booted with '" param "=Y'\n"); \ + break; \ + default: \ + pr_err("Unexpected! This kernel was built with " #kconfig "=y (and booted without '" param "' specified)\n"); \ + } \ + } else { \ + switch (lkdtm_check_bool_cmdline(param)) { \ + case 0: \ + pr_warn("This is probably expected, as kernel was built *without* " #kconfig "=y and booted with '" param "=N'\n"); \ + break; \ + case 1: \ + pr_err("Unexpected! This kernel was built *without* " #kconfig "=y but booted with '" param "=Y'\n"); \ + break; \ + default: \ + pr_err("This is probably expected, since this kernel was built *without* " #kconfig "=y (and booted without '" param "' specified)\n"); \ + break; \ + } \ + } \ +} +#else +#define pr_expected_config_param(kconfig, param) pr_expected_config(kconfig) +#endif + /* bugs.c */ void __init lkdtm_bugs_init(int *recur_param); void lkdtm_PANIC(void); diff --git a/drivers/misc/lkdtm/stackleak.c b/drivers/misc/lkdtm/stackleak.c index d1a5c0705be3..00db21ff115e 100644 --- a/drivers/misc/lkdtm/stackleak.c +++ b/drivers/misc/lkdtm/stackleak.c @@ -74,8 +74,8 @@ void lkdtm_STACKLEAK_ERASING(void) end: if (test_failed) { - pr_err("FAIL: the thread stack is NOT properly erased\n"); - dump_stack(); + pr_err("FAIL: the thread stack is NOT properly erased!\n"); + pr_expected_config(CONFIG_GCC_PLUGIN_STACKLEAK); } else { pr_info("OK: the rest of the thread stack is properly erased\n"); } diff --git a/drivers/misc/lkdtm/usercopy.c b/drivers/misc/lkdtm/usercopy.c index 15d220ef35a5..9161ce7ed47a 100644 --- a/drivers/misc/lkdtm/usercopy.c +++ b/drivers/misc/lkdtm/usercopy.c @@ -173,6 +173,8 @@ static void do_usercopy_heap_size(bool to_user) goto free_user; } } + pr_err("FAIL: bad usercopy not detected!\n"); + pr_expected_config_param(CONFIG_HARDENED_USERCOPY, "hardened_usercopy"); free_user: vm_munmap(user_addr, PAGE_SIZE); @@ -248,6 +250,8 @@ static void do_usercopy_heap_whitelist(bool to_user) goto free_user; } } + pr_err("FAIL: bad usercopy not detected!\n"); + pr_expected_config_param(CONFIG_HARDENED_USERCOPY, "hardened_usercopy"); free_user: vm_munmap(user_alloc, PAGE_SIZE); @@ -319,7 +323,8 @@ void lkdtm_USERCOPY_KERNEL(void) pr_warn("copy_to_user failed, but lacked Oops\n"); goto free_user; } - pr_err("FAIL: survived bad copy_to_user()\n"); + pr_err("FAIL: bad copy_to_user() not detected!\n"); + pr_expected_config_param(CONFIG_HARDENED_USERCOPY, "hardened_usercopy"); free_user: vm_munmap(user_addr, PAGE_SIZE); diff --git a/tools/testing/selftests/lkdtm/stack-entropy.sh b/tools/testing/selftests/lkdtm/stack-entropy.sh index b1b8a5097cbb..1b4d95d575f8 100755 --- a/tools/testing/selftests/lkdtm/stack-entropy.sh +++ b/tools/testing/selftests/lkdtm/stack-entropy.sh @@ -30,6 +30,7 @@ rm -f "$log" # We would expect any functional stack randomization to be at least 5 bits. if [ "$bits" -lt 5 ]; then + echo "Stack entropy is low! Booted without 'randomize_kstack_offset=y'?" exit 1 else exit 0 -- cgit v1.2.3 From 37a0ca7f3e60cb1fc076444b964b45fdaf930a52 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 23 Jun 2021 13:39:36 -0700 Subject: lkdtm/heap: Add init_on_alloc tests Add SLAB and page allocator tests for init_on_alloc. Testing for init_on_free was already happening via the poisoning tests. Signed-off-by: Kees Cook Link: https://lore.kernel.org/r/20210623203936.3151093-10-keescook@chromium.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/lkdtm/core.c | 2 + drivers/misc/lkdtm/heap.c | 65 +++++++++++++++++++++++++++++++++ drivers/misc/lkdtm/lkdtm.h | 2 + tools/testing/selftests/lkdtm/config | 1 + tools/testing/selftests/lkdtm/tests.txt | 2 + 5 files changed, 72 insertions(+) (limited to 'drivers/misc') diff --git a/drivers/misc/lkdtm/core.c b/drivers/misc/lkdtm/core.c index c185ae4719c3..9dda87c6b54a 100644 --- a/drivers/misc/lkdtm/core.c +++ b/drivers/misc/lkdtm/core.c @@ -127,6 +127,8 @@ static const struct crashtype crashtypes[] = { CRASHTYPE(READ_AFTER_FREE), CRASHTYPE(WRITE_BUDDY_AFTER_FREE), CRASHTYPE(READ_BUDDY_AFTER_FREE), + CRASHTYPE(SLAB_INIT_ON_ALLOC), + CRASHTYPE(BUDDY_INIT_ON_ALLOC), CRASHTYPE(SLAB_FREE_DOUBLE), CRASHTYPE(SLAB_FREE_CROSS), CRASHTYPE(SLAB_FREE_PAGE), diff --git a/drivers/misc/lkdtm/heap.c b/drivers/misc/lkdtm/heap.c index a3bb0577ed8b..3d9aae5821a0 100644 --- a/drivers/misc/lkdtm/heap.c +++ b/drivers/misc/lkdtm/heap.c @@ -174,6 +174,71 @@ void lkdtm_READ_BUDDY_AFTER_FREE(void) kfree(val); } +void lkdtm_SLAB_INIT_ON_ALLOC(void) +{ + u8 *first; + u8 *val; + + first = kmalloc(512, GFP_KERNEL); + if (!first) { + pr_info("Unable to allocate 512 bytes the first time.\n"); + return; + } + + memset(first, 0xAB, 512); + kfree(first); + + val = kmalloc(512, GFP_KERNEL); + if (!val) { + pr_info("Unable to allocate 512 bytes the second time.\n"); + return; + } + if (val != first) { + pr_warn("Reallocation missed clobbered memory.\n"); + } + + if (memchr(val, 0xAB, 512) == NULL) { + pr_info("Memory appears initialized (%x, no earlier values)\n", *val); + } else { + pr_err("FAIL: Slab was not initialized\n"); + pr_expected_config_param(CONFIG_INIT_ON_ALLOC_DEFAULT_ON, "init_on_alloc"); + } + kfree(val); +} + +void lkdtm_BUDDY_INIT_ON_ALLOC(void) +{ + u8 *first; + u8 *val; + + first = (u8 *)__get_free_page(GFP_KERNEL); + if (!first) { + pr_info("Unable to allocate first free page\n"); + return; + } + + memset(first, 0xAB, PAGE_SIZE); + free_page((unsigned long)first); + + val = (u8 *)__get_free_page(GFP_KERNEL); + if (!val) { + pr_info("Unable to allocate second free page\n"); + return; + } + + if (val != first) { + pr_warn("Reallocation missed clobbered memory.\n"); + } + + if (memchr(val, 0xAB, PAGE_SIZE) == NULL) { + pr_info("Memory appears initialized (%x, no earlier values)\n", *val); + } else { + pr_err("FAIL: Slab was not initialized\n"); + pr_expected_config_param(CONFIG_INIT_ON_ALLOC_DEFAULT_ON, "init_on_alloc"); + } + free_page((unsigned long)val); +} + void lkdtm_SLAB_FREE_DOUBLE(void) { int *val; diff --git a/drivers/misc/lkdtm/lkdtm.h b/drivers/misc/lkdtm/lkdtm.h index e491bc571808..6a30b60519f3 100644 --- a/drivers/misc/lkdtm/lkdtm.h +++ b/drivers/misc/lkdtm/lkdtm.h @@ -86,6 +86,8 @@ void lkdtm_WRITE_AFTER_FREE(void); void lkdtm_READ_AFTER_FREE(void); void lkdtm_WRITE_BUDDY_AFTER_FREE(void); void lkdtm_READ_BUDDY_AFTER_FREE(void); +void lkdtm_SLAB_INIT_ON_ALLOC(void); +void lkdtm_BUDDY_INIT_ON_ALLOC(void); void lkdtm_SLAB_FREE_DOUBLE(void); void lkdtm_SLAB_FREE_CROSS(void); void lkdtm_SLAB_FREE_PAGE(void); diff --git a/tools/testing/selftests/lkdtm/config b/tools/testing/selftests/lkdtm/config index 849799bcfa95..013446e87f1f 100644 --- a/tools/testing/selftests/lkdtm/config +++ b/tools/testing/selftests/lkdtm/config @@ -5,3 +5,4 @@ CONFIG_FORTIFY_SOURCE=y CONFIG_HARDENED_USERCOPY=y # CONFIG_HARDENED_USERCOPY_FALLBACK is not set CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT=y +CONFIG_INIT_ON_ALLOC_DEFAULT_ON=y diff --git a/tools/testing/selftests/lkdtm/tests.txt b/tools/testing/selftests/lkdtm/tests.txt index 30080cc15623..846cfd508d3c 100644 --- a/tools/testing/selftests/lkdtm/tests.txt +++ b/tools/testing/selftests/lkdtm/tests.txt @@ -21,6 +21,8 @@ VMALLOC_LINEAR_OVERFLOW READ_AFTER_FREE call trace:|Memory correctly poisoned #WRITE_BUDDY_AFTER_FREE Corrupts memory on failure READ_BUDDY_AFTER_FREE call trace:|Memory correctly poisoned +SLAB_INIT_ON_ALLOC Memory appears initialized +BUDDY_INIT_ON_ALLOC Memory appears initialized SLAB_FREE_DOUBLE SLAB_FREE_CROSS SLAB_FREE_PAGE -- cgit v1.2.3 From 7487257cea875a2ee0aab088ee1dd92cd77698d4 Mon Sep 17 00:00:00 2001 From: Junlin Yang Date: Sat, 19 Jun 2021 19:28:54 +0800 Subject: misc: vmw_vmci: return the correct errno code When kzalloc failed, should return -ENOMEM rather than -EINVAL. Signed-off-by: Junlin Yang Link: https://lore.kernel.org/r/20210619112854.1720-1-angkery@163.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_vmci/vmci_context.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/vmw_vmci/vmci_context.c b/drivers/misc/vmw_vmci/vmci_context.c index 26ff49fdf0f7..c0b5e339d5a1 100644 --- a/drivers/misc/vmw_vmci/vmci_context.c +++ b/drivers/misc/vmw_vmci/vmci_context.c @@ -107,7 +107,7 @@ struct vmci_ctx *vmci_ctx_create(u32 cid, u32 priv_flags, context = kzalloc(sizeof(*context), GFP_KERNEL); if (!context) { pr_warn("Failed to allocate memory for VMCI context\n"); - error = -EINVAL; + error = -ENOMEM; goto err_out; } -- cgit v1.2.3 From 1db376113e45e31eeeda6f91096808cf1827e70c Mon Sep 17 00:00:00 2001 From: Guoqing Chi Date: Mon, 21 Jun 2021 03:11:00 +0000 Subject: misc: ibmasm: Modify matricies to matrices The plural of "matrix" is "matrices". Signed-off-by: Guoqing Chi Link: https://lore.kernel.org/r/20210621031100.13093-1-chi962464zy@163.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/ibmasm/remote.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/ibmasm/remote.h b/drivers/misc/ibmasm/remote.h index 8d364462aeea..ec4e78ec5a67 100644 --- a/drivers/misc/ibmasm/remote.h +++ b/drivers/misc/ibmasm/remote.h @@ -43,7 +43,7 @@ #define REMOTE_BUTTON_MIDDLE 0x02 #define REMOTE_BUTTON_RIGHT 0x04 -/* size of keysym/keycode translation matricies */ +/* size of keysym/keycode translation matrices */ #define XLATE_SIZE 256 struct mouse_input { -- cgit v1.2.3