Zhao Qunqin (3): pci/quirks: LS7A2000: fix pm transition of devices under pcie port net: stmmac: dwmac-loongson: fix Mac DMA reset drivers/char: add ACPI firmware support for Loongson SE driver
wanghongliang (3): LoongArch: fix i2c related issues LoongArch: eiointc: fix ext irq route error LoongArch: adjust the calc method of number of packages.
arch/loongarch/configs/loongson3_defconfig | 2 + arch/loongarch/include/asm/topology.h | 4 + arch/loongarch/kernel/setup.c | 1 + arch/loongarch/kernel/smp.c | 3 + drivers/char/loongson_se.c | 440 +++++++----------- drivers/char/lsse_sdf_cdev.c | 310 ++++++------ drivers/gpio/gpio-loongson-64bit.c | 298 ++++++++++-- drivers/i2c/busses/i2c-ls2x.c | 12 +- drivers/irqchip/irq-loongson-eiointc.c | 47 +- .../ethernet/stmicro/stmmac/dwmac-loongson.c | 14 + drivers/pci/quirks.c | 30 ++ drivers/platform/loongarch/cpu_hwmon.c | 3 +- include/linux/pci.h | 1 + .../include/asm => include/soc/loongson}/se.h | 52 +-- 14 files changed, 710 insertions(+), 507 deletions(-) rename {arch/loongarch/include/asm => include/soc/loongson}/se.h (68%)
From: Zhao Qunqin zhaoqunqin@loongson.cn
LoongArch inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IBENRY CVE: NA
--------------------------------
The CPU may not be able to access the PCI header of the device if it is in low-power mode.
Signed-off-by: Zhao Qunqin zhaoqunqin@loongson.cn --- drivers/pci/quirks.c | 30 ++++++++++++++++++++++++++++++ include/linux/pci.h | 1 + 2 files changed, 31 insertions(+)
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index b8a8fbf15cdc..a86e7d791b7a 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -410,6 +410,36 @@ static void loongson_pcie_msi_quirk(struct pci_dev *dev) } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, 0x7a59, loongson_pcie_msi_quirk);
+#define DEV_PCIE_PORT_4 0x7a39 +#define DEV_PCIE_PORT_5 0x7a49 +#define DEV_PCIE_PORT_6 0x7a59 +#define DEV_PCIE_PORT_7 0x7a69 +static void loongson_d3_and_link_quirk(struct pci_dev *dev) +{ + struct pci_bus *bus = dev->bus; + struct pci_dev *bridge; + static const struct pci_device_id bridge_devids[] = { + { PCI_VDEVICE(LOONGSON, DEV_PCIE_PORT_4) }, + { PCI_VDEVICE(LOONGSON, DEV_PCIE_PORT_5) }, + { PCI_VDEVICE(LOONGSON, DEV_PCIE_PORT_6) }, + { PCI_VDEVICE(LOONGSON, DEV_PCIE_PORT_7) }, + { 0, }, + }; + + /* look for the matching bridge */ + while (!pci_is_root_bus(bus)) { + bridge = bus->self; + bus = bus->parent; + if (bridge && pci_match_id(bridge_devids, bridge)) { + dev->dev_flags |= (PCI_DEV_FLAGS_NO_D3 | + PCI_DEV_FLAGS_NO_LINK_SPEED_CHANGE); + dev->no_d1d2 = 1; + break; + } + } +} +DECLARE_PCI_FIXUP_ENABLE(PCI_ANY_ID, PCI_ANY_ID, loongson_d3_and_link_quirk); + /* Chipsets where PCI->PCI transfers vanish or hang */ static void quirk_nopcipci(struct pci_dev *dev) { diff --git a/include/linux/pci.h b/include/linux/pci.h index 3eb0e343c16c..645229577081 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -246,6 +246,7 @@ enum pci_dev_flags { PCI_DEV_FLAGS_NO_RELAXED_ORDERING = (__force pci_dev_flags_t) (1 << 11), /* Device does honor MSI masking despite saying otherwise */ PCI_DEV_FLAGS_HAS_MSI_MASKING = (__force pci_dev_flags_t) (1 << 12), + PCI_DEV_FLAGS_NO_LINK_SPEED_CHANGE = (__force pci_dev_flags_t) (1 << 15), };
enum pci_irq_reroute_variant {
From: Zhao Qunqin zhaoqunqin@loongson.cn
LoongArch inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IBENRY CVE: NA
--------------------------------
DMA reset of Loongson's Mac may take over a second
Signed-off-by: Zhao Qunqin zhaoqunqin@loongson.cn Change-Id: I62011c25f54a240ec0283209eb020d5e42b9eaef --- .../net/ethernet/stmicro/stmmac/dwmac-loongson.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c index f03d78385ed9..357d09656a7a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c @@ -443,6 +443,19 @@ static struct mac_device_info *loongson_dwmac_setup(void *apriv) return mac; }
+static int loongson_fix_soc_reset(void *priv, void __iomem *ioaddr) +{ + u32 value = readl(ioaddr + DMA_BUS_MODE); + + /* DMA SW reset */ + value |= DMA_BUS_MODE_SFT_RESET; + writel(value, ioaddr + DMA_BUS_MODE); + + return readl_poll_timeout(ioaddr + DMA_BUS_MODE, value, + !(value & DMA_BUS_MODE_SFT_RESET), + 10000, 2000000); +} + static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct plat_stmmacenet_data *plat; @@ -518,6 +531,7 @@ static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id
plat->bsp_priv = ld; plat->setup = loongson_dwmac_setup; + plat->fix_soc_reset = loongson_fix_soc_reset; ld->dev = &pdev->dev;
memset(&res, 0, sizeof(res));
From: wanghongliang wanghongliang@loongson.cn
LoongArch inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IBENRY CVE: NA
--------------------------------
Signed-off-by: wanghongliang wanghongliang@loongson.cn --- arch/loongarch/configs/loongson3_defconfig | 2 + drivers/gpio/gpio-loongson-64bit.c | 298 ++++++++++++++++++--- drivers/i2c/busses/i2c-ls2x.c | 12 +- 3 files changed, 267 insertions(+), 45 deletions(-)
diff --git a/arch/loongarch/configs/loongson3_defconfig b/arch/loongarch/configs/loongson3_defconfig index 49f9ade46023..444849a5a10f 100644 --- a/arch/loongarch/configs/loongson3_defconfig +++ b/arch/loongarch/configs/loongson3_defconfig @@ -1671,6 +1671,8 @@ CONFIG_HID_ALPS=m CONFIG_HID_PID=y CONFIG_USB_HIDDEV=y CONFIG_I2C_HID=m +CONFIG_I2C_HID_ACPI=m +CONFIG_I2C_HID_OF=m CONFIG_USB_LED_TRIG=y CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y diff --git a/drivers/gpio/gpio-loongson-64bit.c b/drivers/gpio/gpio-loongson-64bit.c index 06213bbfabdd..f916a5ae0290 100644 --- a/drivers/gpio/gpio-loongson-64bit.c +++ b/drivers/gpio/gpio-loongson-64bit.c @@ -26,6 +26,7 @@ struct loongson_gpio_chip_data { unsigned int conf_offset; unsigned int out_offset; unsigned int in_offset; + unsigned int inten_offset; };
struct loongson_gpio_chip { @@ -33,6 +34,8 @@ struct loongson_gpio_chip { struct fwnode_handle *fwnode; spinlock_t lock; void __iomem *reg_base; + u16 *gsi_idx_map; + u16 mapsize; const struct loongson_gpio_chip_data *chip_data; };
@@ -41,15 +44,40 @@ static inline struct loongson_gpio_chip *to_loongson_gpio_chip(struct gpio_chip return container_of(chip, struct loongson_gpio_chip, chip); }
-static inline void loongson_commit_direction(struct loongson_gpio_chip *lgpio, unsigned int pin, - int input) +static inline void loongson_commit_direction_bit(struct loongson_gpio_chip *lgpio, + unsigned int pin, int input) +{ + u64 temp; + + temp = readq(lgpio->reg_base + lgpio->chip_data->conf_offset); + if (input) + temp |= 1ULL << pin; + else + temp &= ~(1ULL << pin); + writeq(temp, lgpio->reg_base + lgpio->chip_data->conf_offset); +} + +static inline void loongson_commit_direction_byte(struct loongson_gpio_chip *lgpio, + unsigned int pin, int input) { u8 bval = input ? 1 : 0;
writeb(bval, lgpio->reg_base + lgpio->chip_data->conf_offset + pin); }
-static void loongson_commit_level(struct loongson_gpio_chip *lgpio, unsigned int pin, int high) +static void loongson_commit_level_bit(struct loongson_gpio_chip *lgpio, unsigned int pin, int high) +{ + u64 temp; + + temp = readq(lgpio->reg_base + lgpio->chip_data->out_offset); + if (high) + temp |= 1ULL << pin; + else + temp &= ~(1ULL << pin); + writeq(temp, lgpio->reg_base + lgpio->chip_data->out_offset); +} + +static void loongson_commit_level_byte(struct loongson_gpio_chip *lgpio, unsigned int pin, int high) { u8 bval = high ? 1 : 0;
@@ -62,7 +90,10 @@ static int loongson_gpio_direction_input(struct gpio_chip *chip, unsigned int pi struct loongson_gpio_chip *lgpio = to_loongson_gpio_chip(chip);
spin_lock_irqsave(&lgpio->lock, flags); - loongson_commit_direction(lgpio, pin, 1); + if (lgpio->chip_data->mode == BIT_CTRL_MODE) + loongson_commit_direction_bit(lgpio, pin, 1); + else + loongson_commit_direction_byte(lgpio, pin, 1); spin_unlock_irqrestore(&lgpio->lock, flags);
return 0; @@ -74,8 +105,13 @@ static int loongson_gpio_direction_output(struct gpio_chip *chip, unsigned int p struct loongson_gpio_chip *lgpio = to_loongson_gpio_chip(chip);
spin_lock_irqsave(&lgpio->lock, flags); - loongson_commit_level(lgpio, pin, value); - loongson_commit_direction(lgpio, pin, 0); + if (lgpio->chip_data->mode == BIT_CTRL_MODE) { + loongson_commit_level_bit(lgpio, pin, value); + loongson_commit_direction_bit(lgpio, pin, 0); + } else { + loongson_commit_level_byte(lgpio, pin, value); + loongson_commit_direction_byte(lgpio, pin, 0); + } spin_unlock_irqrestore(&lgpio->lock, flags);
return 0; @@ -84,11 +120,17 @@ static int loongson_gpio_direction_output(struct gpio_chip *chip, unsigned int p static int loongson_gpio_get(struct gpio_chip *chip, unsigned int pin) { u8 bval; + u64 qval; int val; struct loongson_gpio_chip *lgpio = to_loongson_gpio_chip(chip);
- bval = readb(lgpio->reg_base + lgpio->chip_data->in_offset + pin); - val = bval & 1; + if (lgpio->chip_data->mode == BIT_CTRL_MODE) { + qval = readq(lgpio->reg_base + lgpio->chip_data->in_offset); + val = ((qval & (1ULL << pin)) != 0); + } else { + bval = readb(lgpio->reg_base + lgpio->chip_data->in_offset + pin); + val = (bval & 1); + }
return val; } @@ -96,13 +138,22 @@ static int loongson_gpio_get(struct gpio_chip *chip, unsigned int pin) static int loongson_gpio_get_direction(struct gpio_chip *chip, unsigned int pin) { u8 bval; + u64 qval; + int val; struct loongson_gpio_chip *lgpio = to_loongson_gpio_chip(chip);
- bval = readb(lgpio->reg_base + lgpio->chip_data->conf_offset + pin); - if (bval & 1) - return GPIO_LINE_DIRECTION_IN; + if (lgpio->chip_data->mode == BIT_CTRL_MODE) { + qval = readq(lgpio->reg_base + lgpio->chip_data->conf_offset); + val = ((qval & (1ULL << pin)) != 0); + } else { + bval = readb(lgpio->reg_base + lgpio->chip_data->conf_offset + pin); + val = bval & 1; + } + + if (val) + return 1;
- return GPIO_LINE_DIRECTION_OUT; + return 0; }
static void loongson_gpio_set(struct gpio_chip *chip, unsigned int pin, int value) @@ -111,52 +162,73 @@ static void loongson_gpio_set(struct gpio_chip *chip, unsigned int pin, int valu struct loongson_gpio_chip *lgpio = to_loongson_gpio_chip(chip);
spin_lock_irqsave(&lgpio->lock, flags); - loongson_commit_level(lgpio, pin, value); + if (lgpio->chip_data->mode == BIT_CTRL_MODE) + loongson_commit_level_bit(lgpio, pin, value); + else + loongson_commit_level_byte(lgpio, pin, value); spin_unlock_irqrestore(&lgpio->lock, flags); }
static int loongson_gpio_to_irq(struct gpio_chip *chip, unsigned int offset) { + unsigned int u; struct platform_device *pdev = to_platform_device(chip->parent); + struct loongson_gpio_chip *lgpio = to_loongson_gpio_chip(chip); + + if (lgpio->chip_data->mode == BIT_CTRL_MODE) { + /* Get the register index from offset then multiply by bytes per register */ + u = readl(lgpio->reg_base + lgpio->chip_data->inten_offset + (offset / 32) * 4); + u |= BIT(offset % 32); + writel(u, lgpio->reg_base + lgpio->chip_data->inten_offset + (offset / 32) * 4); + } else { + writeb(1, lgpio->reg_base + lgpio->chip_data->inten_offset + offset); + } + + if ((lgpio->gsi_idx_map != NULL) && (offset < lgpio->mapsize)) + offset = lgpio->gsi_idx_map[offset];
return platform_get_irq(pdev, offset); }
static int loongson_gpio_init(struct device *dev, struct loongson_gpio_chip *lgpio, - struct device_node *np, void __iomem *reg_base) + void __iomem *reg_base) { - int ret; u32 ngpios; + u32 gpio_base; + int rval;
lgpio->reg_base = reg_base; - - if (lgpio->chip_data->mode == BIT_CTRL_MODE) { - ret = bgpio_init(&lgpio->chip, dev, 8, - lgpio->reg_base + lgpio->chip_data->in_offset, - lgpio->reg_base + lgpio->chip_data->out_offset, - NULL, NULL, - lgpio->reg_base + lgpio->chip_data->conf_offset, - 0); - if (ret) { - dev_err(dev, "unable to init generic GPIO\n"); - return ret; + lgpio->chip.direction_input = loongson_gpio_direction_input; + lgpio->chip.get = loongson_gpio_get; + lgpio->chip.get_direction = loongson_gpio_get_direction; + lgpio->chip.direction_output = loongson_gpio_direction_output; + lgpio->chip.set = loongson_gpio_set; + lgpio->chip.parent = dev; + device_property_read_u32(dev, "gpio_base", &gpio_base); + if (!gpio_base) + gpio_base = -1; + lgpio->chip.base = gpio_base; + device_property_read_u32(dev, "ngpios", &ngpios); + lgpio->chip.ngpio = ngpios; + rval = device_property_read_u16_array(dev, "gsi_idx_map", NULL, 0); + if (rval > 0) { + lgpio->gsi_idx_map = + kmalloc_array(rval, sizeof(*lgpio->gsi_idx_map), + GFP_KERNEL); + if (unlikely(!lgpio->gsi_idx_map)) { + dev_err(dev, "Alloc gsi_idx_map fail!\n"); + } else { + lgpio->mapsize = rval; + device_property_read_u16_array(dev, "gsi_idx_map", + lgpio->gsi_idx_map, lgpio->mapsize); } - } else { - lgpio->chip.direction_input = loongson_gpio_direction_input; - lgpio->chip.get = loongson_gpio_get; - lgpio->chip.get_direction = loongson_gpio_get_direction; - lgpio->chip.direction_output = loongson_gpio_direction_output; - lgpio->chip.set = loongson_gpio_set; - lgpio->chip.parent = dev; - spin_lock_init(&lgpio->lock); } + spin_lock_init(&lgpio->lock);
- device_property_read_u32(dev, "ngpios", &ngpios); - - lgpio->chip.can_sleep = 0; - lgpio->chip.ngpio = ngpios; lgpio->chip.label = lgpio->chip_data->label; - lgpio->chip.to_irq = loongson_gpio_to_irq; + lgpio->chip.can_sleep = false; + if (lgpio->chip_data->inten_offset) + lgpio->chip.to_irq = loongson_gpio_to_irq;
return devm_gpiochip_add_data(dev, &lgpio->chip, lgpio); } @@ -165,7 +237,6 @@ static int loongson_gpio_probe(struct platform_device *pdev) { void __iomem *reg_base; struct loongson_gpio_chip *lgpio; - struct device_node *np = pdev->dev.of_node; struct device *dev = &pdev->dev;
lgpio = devm_kzalloc(dev, sizeof(*lgpio), GFP_KERNEL); @@ -178,7 +249,7 @@ static int loongson_gpio_probe(struct platform_device *pdev) if (IS_ERR(reg_base)) return PTR_ERR(reg_base);
- return loongson_gpio_init(dev, lgpio, np, reg_base); + return loongson_gpio_init(dev, lgpio, reg_base); }
static const struct loongson_gpio_chip_data loongson_gpio_ls2k_data = { @@ -187,6 +258,60 @@ static const struct loongson_gpio_chip_data loongson_gpio_ls2k_data = { .conf_offset = 0x0, .in_offset = 0x20, .out_offset = 0x10, + .inten_offset = 0x30, +}; + +static const struct loongson_gpio_chip_data loongson_gpio_ls2k0500_data0 = { + .label = "ls2k0500_gpio", + .mode = BIT_CTRL_MODE, + .conf_offset = 0x0, + .in_offset = 0x8, + .out_offset = 0x10, + .inten_offset = 0xb0, +}; + +static const struct loongson_gpio_chip_data loongson_gpio_ls2k0500_data1 = { + .label = "ls2k0500_gpio", + .mode = BIT_CTRL_MODE, + .conf_offset = 0x0, + .in_offset = 0x8, + .out_offset = 0x10, + .inten_offset = 0x98, +}; + +static const struct loongson_gpio_chip_data loongson_gpio_ls2k2000_data0 = { + .label = "ls2k2000_gpio", + .mode = BIT_CTRL_MODE, + .conf_offset = 0x0, + .in_offset = 0xc, + .out_offset = 0x8, + .inten_offset = 0x14, +}; + +static const struct loongson_gpio_chip_data loongson_gpio_ls2k2000_data1 = { + .label = "ls2k2000_gpio", + .mode = BIT_CTRL_MODE, + .conf_offset = 0x0, + .in_offset = 0x20, + .out_offset = 0x10, + .inten_offset = 0x30, +}; + +static const struct loongson_gpio_chip_data loongson_gpio_ls2k2000_data2 = { + .label = "ls2k2000_gpio", + .mode = BIT_CTRL_MODE, + .conf_offset = 0x4, + .in_offset = 0x8, + .out_offset = 0x0, +}; + +static const struct loongson_gpio_chip_data loongson_gpio_ls3a5000_data = { + .label = "ls3a5000_gpio", + .mode = BIT_CTRL_MODE, + .conf_offset = 0x0, + .in_offset = 0xc, + .out_offset = 0x8, + .inten_offset = 0x14, };
static const struct loongson_gpio_chip_data loongson_gpio_ls7a_data = { @@ -195,6 +320,33 @@ static const struct loongson_gpio_chip_data loongson_gpio_ls7a_data = { .conf_offset = 0x800, .in_offset = 0xa00, .out_offset = 0x900, + .inten_offset = 0xb00, +}; + +static const struct loongson_gpio_chip_data loongson_gpio_ls7a2000_data0 = { + .label = "ls7a2000_gpio", + .mode = BYTE_CTRL_MODE, + .conf_offset = 0x800, + .in_offset = 0xa00, + .out_offset = 0x900, + .inten_offset = 0xb00, +}; + +static const struct loongson_gpio_chip_data loongson_gpio_ls7a2000_data1 = { + .label = "ls7a2000_gpio", + .mode = BYTE_CTRL_MODE, + .conf_offset = 0x84, + .in_offset = 0x88, + .out_offset = 0x80, +}; + +static const struct loongson_gpio_chip_data loongson_gpio_ls3a6000_data = { + .label = "ls3a6000_gpio", + .mode = BIT_CTRL_MODE, + .conf_offset = 0x0, + .in_offset = 0xc, + .out_offset = 0x8, + .inten_offset = 0x14, };
static const struct of_device_id loongson_gpio_of_match[] = { @@ -202,10 +354,46 @@ static const struct of_device_id loongson_gpio_of_match[] = { .compatible = "loongson,ls2k-gpio", .data = &loongson_gpio_ls2k_data, }, + { + .compatible = "loongson,ls2k0500-gpio0", + .data = &loongson_gpio_ls2k0500_data0, + }, + { + .compatible = "loongson,ls2k0500-gpio1", + .data = &loongson_gpio_ls2k0500_data1, + }, + { + .compatible = "loongson,ls2k2000-gpio0", + .data = &loongson_gpio_ls2k2000_data0, + }, + { + .compatible = "loongson,ls2k2000-gpio1", + .data = &loongson_gpio_ls2k2000_data1, + }, + { + .compatible = "loongson,ls2k2000-gpio2", + .data = &loongson_gpio_ls2k2000_data2, + }, + { + .compatible = "loongson,ls3a5000-gpio", + .data = &loongson_gpio_ls3a5000_data, + }, { .compatible = "loongson,ls7a-gpio", .data = &loongson_gpio_ls7a_data, }, + { + .compatible = "loongson,ls7a2000-gpio1", + .data = &loongson_gpio_ls7a2000_data0, + }, + { + .compatible = "loongson,ls7a2000-gpio2", + .data = &loongson_gpio_ls7a2000_data1, + }, + { + .compatible = "loongson,ls3a6000-gpio", + .data = &loongson_gpio_ls3a6000_data, + }, {} }; MODULE_DEVICE_TABLE(of, loongson_gpio_of_match); @@ -215,6 +403,34 @@ static const struct acpi_device_id loongson_gpio_acpi_match[] = { .id = "LOON0002", .driver_data = (kernel_ulong_t)&loongson_gpio_ls7a_data, }, + { + .id = "LOON0007", + .driver_data = (kernel_ulong_t)&loongson_gpio_ls3a5000_data, + }, + { + .id = "LOON000A", + .driver_data = (kernel_ulong_t)&loongson_gpio_ls2k2000_data0, + }, + { + .id = "LOON000B", + .driver_data = (kernel_ulong_t)&loongson_gpio_ls2k2000_data1, + }, + { + .id = "LOON000C", + .driver_data = (kernel_ulong_t)&loongson_gpio_ls2k2000_data2, + }, + { + .id = "LOON000D", + .driver_data = (kernel_ulong_t)&loongson_gpio_ls7a2000_data0, + }, + { + .id = "LOON000E", + .driver_data = (kernel_ulong_t)&loongson_gpio_ls7a2000_data1, + }, + { + .id = "LOON000F", + .driver_data = (kernel_ulong_t)&loongson_gpio_ls3a6000_data, + }, {} }; MODULE_DEVICE_TABLE(acpi, loongson_gpio_acpi_match); diff --git a/drivers/i2c/busses/i2c-ls2x.c b/drivers/i2c/busses/i2c-ls2x.c index ebae6035701d..871ceedec74f 100644 --- a/drivers/i2c/busses/i2c-ls2x.c +++ b/drivers/i2c/busses/i2c-ls2x.c @@ -26,7 +26,8 @@ #include <linux/units.h>
/* I2C Registers */ -#define I2C_LS2X_PRER 0x0 /* Freq Division Register(16 bits) */ +#define I2C_LS2X_PRER_LO 0x0 /* Freq Division Register Lo(8 bits) */ +#define I2C_LS2X_PRER_HI 0x1 /* Freq Division Register Hi(8 bits) */ #define I2C_LS2X_CTR 0x2 /* Control Register */ #define I2C_LS2X_TXR 0x3 /* Transport Data Register */ #define I2C_LS2X_RXR 0x3 /* Receive Data Register */ @@ -96,6 +97,7 @@ static void ls2x_i2c_adjust_bus_speed(struct ls2x_i2c_priv *priv) struct i2c_timings *t = &priv->i2c_t; struct device *dev = priv->adapter.dev.parent; u32 acpi_speed = i2c_acpi_find_bus_speed(dev); + u16 prer_val;
i2c_parse_fw_timings(dev, t, false);
@@ -104,9 +106,11 @@ static void ls2x_i2c_adjust_bus_speed(struct ls2x_i2c_priv *priv) else t->bus_freq_hz = LS2X_I2C_FREQ_STD;
- /* Calculate and set i2c frequency. */ - writew(LS2X_I2C_PCLK_FREQ / (5 * t->bus_freq_hz) - 1, - priv->base + I2C_LS2X_PRER); + prer_val = LS2X_I2C_PCLK_FREQ / (5 * t->bus_freq_hz) - 1; + + /* set i2c frequency. */ + writeb(prer_val & 0xFF, priv->base + I2C_LS2X_PRER_LO); + writeb((prer_val & 0xFF00) >> 8, priv->base + I2C_LS2X_PRER_HI); }
static void ls2x_i2c_init(struct ls2x_i2c_priv *priv)
From: Zhao Qunqin zhaoqunqin@loongson.cn
LoongArch inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IBENRY CVE: NA
--------------------------------
ACPI HID for Loongson SE is "LOONG0011", for Loongson SDF is "LOON0012". And cleanned up coding style. Moved SE header file form arch/loongarch/include/asm to include/soc/loongson.
Signed-off-by: Zhao Qunqin zhaoqunqin@loongson.cn Change-Id: Ie15d377ce0435643ac950b34dff48142f21f2d02 --- drivers/char/loongson_se.c | 440 +++++++----------- drivers/char/lsse_sdf_cdev.c | 310 ++++++------ .../include/asm => include/soc/loongson}/se.h | 52 +-- 3 files changed, 355 insertions(+), 447 deletions(-) rename {arch/loongarch/include/asm => include/soc/loongson}/se.h (68%)
diff --git a/drivers/char/loongson_se.c b/drivers/char/loongson_se.c index 40d2d6518265..853f7e10cd41 100644 --- a/drivers/char/loongson_se.c +++ b/drivers/char/loongson_se.c @@ -1,67 +1,61 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2024 Loongson Technology Corporation Limited + */
-#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/errno.h> +#include <linux/acpi.h> #include <linux/cdev.h> +#include <linux/delay.h> #include <linux/device.h> -#include <linux/of.h> -#include <linux/of_address.h> -#include <linux/platform_device.h> -#include <linux/miscdevice.h> -#include <linux/iopoll.h> #include <linux/dma-mapping.h> +#include <linux/errno.h> +#include <linux/init.h> #include <linux/interrupt.h> -#include <asm/se.h> - -static int se_mem_size = 0x800000; -module_param(se_mem_size, int, 0444); -MODULE_PARM_DESC(se_mem_size, "LOONGSON SE shared memory size"); - -static int se_mem_page = PAGE_SIZE; -module_param(se_mem_page, int, 0444); -MODULE_PARM_DESC(se_mem_page, "LOONGSON SE shared memory page size"); - -static struct loongson_se se_dev; - -static int lsse_open(struct inode *inode, struct file *filp) -{ - return 0; -} - -static ssize_t lsse_write(struct file *filp, const char __user *buf, - size_t cnt, loff_t *offt) -{ - return 0; -} - -static const struct file_operations lsse_fops = { - .owner = THIS_MODULE, - .open = lsse_open, - .write = lsse_write, -}; - -static const struct miscdevice lsse_miscdev = { - .minor = MISC_DYNAMIC_MINOR, - .name = "loongson-se", - .fops = &lsse_fops, -}; - -static inline u32 se_readl(u64 addr) +#include <linux/iopoll.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <soc/loongson/se.h> + +/* + * The Loongson Security Module provides the control for hardware + * encryption acceleration child devices. The SE framework is + * shown as follows: + * + * +------------+ + * | CPU | + * +------------+ + * ^ ^ + * DMA | | IRQ + * v v + * +-----------------------------------+ + * | Loongson Security Module | + * +-----------------------------------+ + * ^ ^ + * chnnel0 | channel1 | + * v v + * +-----------+ +----------+ + * | sub-dev0 | | sub-dev1 | ..... Max sub-dev31 + * +-----------+ +----------+ + * + * The CPU cannot directly communicate with SE's sub devices, + * but sends commands to SE, which processes the commands and + * sends them to the corresponding sub devices. + */ + +static inline u32 se_readl(struct loongson_se *se, u32 off) { - return readl(se_dev.base + addr); + return readl(se->base + off); }
-static inline void se_writel(u32 val, u64 addr) +static inline void se_writel(struct loongson_se *se, u32 val, u32 off) { - writel(val, se_dev.base + addr); + writel(val, se->base + off); }
static inline bool se_ch_status(struct loongson_se *se, u32 int_bit) { - return !!(se->ch_status & int_bit) == 1; + return !!(se->ch_status & int_bit); }
static void se_enable_int(struct loongson_se *se, u32 int_bit) @@ -69,14 +63,11 @@ static void se_enable_int(struct loongson_se *se, u32 int_bit) unsigned long flag; u32 tmp;
- if (!int_bit) - return; - spin_lock_irqsave(&se->dev_lock, flag);
- tmp = se_readl(SE_S2LINT_EN); + tmp = se_readl(se, SE_S2LINT_EN); tmp |= int_bit; - se_writel(tmp, SE_S2LINT_EN); + se_writel(se, tmp, SE_S2LINT_EN);
spin_unlock_irqrestore(&se->dev_lock, flag); } @@ -86,50 +77,43 @@ static void se_disable_int(struct loongson_se *se, u32 int_bit) unsigned long flag; u32 tmp;
- if (!int_bit) - return; - spin_lock_irqsave(&se->dev_lock, flag);
- tmp = se_readl(SE_S2LINT_EN); + tmp = se_readl(se, SE_S2LINT_EN); tmp &= ~(int_bit); - se_writel(tmp, SE_S2LINT_EN); + se_writel(se, tmp, SE_S2LINT_EN);
spin_unlock_irqrestore(&se->dev_lock, flag); }
-static int se_send_requeset(struct loongson_se *se, - struct se_mailbox_data *req) +static int se_send_requeset(struct loongson_se *se, struct se_data *req) { unsigned long flag; u32 status; - int err = 0; + int err; int i;
if (!se || !req) return -EINVAL;
- if (se_readl(SE_L2SINT_STAT) || - !(se_readl(SE_L2SINT_EN) & req->int_bit)) + if (se_readl(se, SE_L2SINT_STAT) || + !(se_readl(se, SE_L2SINT_EN) & req->int_bit)) return -EBUSY;
spin_lock_irqsave(&se->cmd_lock, flag);
- for (i = 0; i < ARRAY_SIZE(req->u.mailbox); i++) - se_writel(req->u.mailbox[i], SE_MAILBOX_S + i * 4); - - se_writel(req->int_bit, SE_L2SINT_SET); - + for (i = 0; i < ARRAY_SIZE(req->u.data); i++) + se_writel(se, req->u.data[i], SE_DATA_S + i * 4); + se_writel(se, req->int_bit, SE_L2SINT_SET); err = readl_relaxed_poll_timeout_atomic(se->base + SE_L2SINT_STAT, status, - !(status & req->int_bit), 10, 10000); + !(status & req->int_bit), 10, 10000);
spin_unlock_irqrestore(&se->cmd_lock, flag);
return err; }
-static int se_get_response(struct loongson_se *se, - struct se_mailbox_data *res) +static int se_get_response(struct loongson_se *se, struct se_data *res) { unsigned long flag; int i; @@ -137,15 +121,14 @@ static int se_get_response(struct loongson_se *se, if (!se || !res) return -EINVAL;
- if ((se_readl(SE_S2LINT_STAT) & res->int_bit) == 0) + if ((se_readl(se, SE_S2LINT_STAT) & res->int_bit) == 0) return -EBUSY;
spin_lock_irqsave(&se->cmd_lock, flag);
- for (i = 0; i < ARRAY_SIZE(res->u.mailbox); i++) - res->u.mailbox[i] = se_readl(SE_MAILBOX_L + i * 4); - - se_writel(res->int_bit, SE_S2LINT_CL); + for (i = 0; i < ARRAY_SIZE(res->u.data); i++) + res->u.data[i] = se_readl(se, SE_DATA_L + i * 4); + se_writel(se, res->int_bit, SE_S2LINT_CL);
spin_unlock_irqrestore(&se->cmd_lock, flag);
@@ -153,10 +136,8 @@ static int se_get_response(struct loongson_se *se, }
static int loongson_se_get_res(struct loongson_se *se, u32 int_bit, u32 cmd, - struct se_mailbox_data *res) + struct se_data *res) { - int err = 0; - res->int_bit = int_bit;
if (se_get_response(se, res)) { @@ -165,21 +146,19 @@ static int loongson_se_get_res(struct loongson_se *se, u32 int_bit, u32 cmd, }
/* Check response */ - if (res->u.res.cmd == cmd) - err = 0; - else { + if (res->u.res.cmd != cmd) { dev_err(se->dev, "Response cmd is 0x%x, not expect cmd 0x%x.\n", - res->u.res.cmd, cmd); - err = -EFAULT; + res->u.res.cmd, cmd); + return -EFAULT; }
- return err; + return 0; }
-static int se_send_genl_cmd(struct loongson_se *se, struct se_mailbox_data *req, - struct se_mailbox_data *res, int retry) +static int se_send_genl_cmd(struct loongson_se *se, struct se_data *req, + struct se_data *res, int retry) { - int err = 0, cnt = 0; + int err, cnt = 0;
try_again: if (cnt++ >= retry) { @@ -193,12 +172,10 @@ static int se_send_genl_cmd(struct loongson_se *se, struct se_mailbox_data *req, if (err) goto try_again;
- if (!wait_for_completion_timeout(&se->cmd_completion, - msecs_to_jiffies(0x1000))) { + if (!wait_for_completion_timeout(&se->cmd_completion, HZ)) { se_enable_int(se, req->int_bit); goto try_again; } - err = loongson_se_get_res(se, req->int_bit, req->u.gcmd.cmd, res); if (err || res->u.res.cmd_ret) { se_enable_int(se, req->int_bit); @@ -214,8 +191,8 @@ static int se_send_genl_cmd(struct loongson_se *se, struct se_mailbox_data *req, static int loongson_se_set_msg(struct lsse_ch *ch) { struct loongson_se *se = ch->se; - struct se_mailbox_data req = {0}; - struct se_mailbox_data res = {0}; + struct se_data req = {0}; + struct se_data res = {0}; int err;
req.int_bit = SE_INT_SETUP; @@ -225,8 +202,8 @@ static int loongson_se_set_msg(struct lsse_ch *ch) req.u.gcmd.info[1] = ch->smsg - se->mem_base; req.u.gcmd.info[2] = ch->msg_size;
- dev_dbg(se->dev, "Set Channel %d msg off 0x%x, msg size %d\n", ch->id, - req.u.gcmd.info[1], req.u.gcmd.info[2]); + dev_dbg(se->dev, "Set Channel %d msg off 0x%x, msg size %d\n", + ch->id, req.u.gcmd.info[1], req.u.gcmd.info[2]);
err = se_send_genl_cmd(se, &req, &res, 5); if (res.u.res.cmd_ret) @@ -235,13 +212,13 @@ static int loongson_se_set_msg(struct lsse_ch *ch) return err; }
-static irqreturn_t loongson_se_irq(int irq, void *dev_id) +static irqreturn_t se_irq(int irq, void *dev_id) { struct loongson_se *se = (struct loongson_se *)dev_id; struct lsse_ch *ch; u32 int_status;
- int_status = se_readl(SE_S2LINT_STAT); + int_status = se_readl(se, SE_S2LINT_STAT);
dev_dbg(se->dev, "%s int status is 0x%x\n", __func__, int_status);
@@ -259,32 +236,23 @@ static irqreturn_t loongson_se_irq(int irq, void *dev_id) if (ch->complete) ch->complete(ch); int_status &= ~BIT(id); - se_writel(BIT(id), SE_S2LINT_CL); + se_writel(se, BIT(id), SE_S2LINT_CL); }
return IRQ_HANDLED; }
-static int se_init_hw(struct loongson_se *se) +static int se_init_hw(struct loongson_se *se, dma_addr_t addr, int size) { - struct se_mailbox_data req = {0}; - struct se_mailbox_data res = {0}; - struct device *dev = se->dev; + struct se_data req; + struct se_data res; int err, retry = 5; - u64 size; - - size = se_mem_size; - - if (size & (size - 1)) { - size = roundup_pow_of_two(size); - se_mem_size = size; - }
se_enable_int(se, SE_INT_SETUP);
/* Start engine */ - memset(&req, 0, sizeof(struct se_mailbox_data)); - memset(&res, 0, sizeof(struct se_mailbox_data)); + memset(&req, 0, sizeof(struct se_data)); + memset(&res, 0, sizeof(struct se_data)); req.int_bit = SE_INT_SETUP; req.u.gcmd.cmd = SE_CMD_START; err = se_send_genl_cmd(se, &req, &res, retry); @@ -292,99 +260,82 @@ static int se_init_hw(struct loongson_se *se) return err;
/* Get Version */ - memset(&req, 0, sizeof(struct se_mailbox_data)); - memset(&res, 0, sizeof(struct se_mailbox_data)); + memset(&req, 0, sizeof(struct se_data)); + memset(&res, 0, sizeof(struct se_data)); req.int_bit = SE_INT_SETUP; req.u.gcmd.cmd = SE_CMD_GETVER; err = se_send_genl_cmd(se, &req, &res, retry); if (err) return err; - se->version = res.u.res.info[0];
- /* Setup data buffer */ - se->mem_base = dmam_alloc_coherent(dev, size, - &se->mem_addr, GFP_KERNEL); - if (!se->mem_base) - return -ENOMEM; - - memset(se->mem_base, 0, size); - - memset(&req, 0, sizeof(struct se_mailbox_data)); - memset(&res, 0, sizeof(struct se_mailbox_data)); + /* Set shared mem */ + memset(&req, 0, sizeof(struct se_data)); + memset(&res, 0, sizeof(struct se_data)); req.int_bit = SE_INT_SETUP; req.u.gcmd.cmd = SE_CMD_SETBUF; /* MMAP */ - req.u.gcmd.info[0] = (se->mem_addr & 0xffffffff) | 0x80; - req.u.gcmd.info[1] = se->mem_addr >> 32; + req.u.gcmd.info[0] = addr & 0xffffffff; + req.u.gcmd.info[1] = addr >> 32; /* MASK */ req.u.gcmd.info[2] = ~(size - 1); req.u.gcmd.info[3] = 0xffffffff; - - pr_debug("Set win mmap 0x%llx, mask 0x%llx\n", - ((u64)req.u.gcmd.info[1] << 32) | req.u.gcmd.info[0], - ((u64)req.u.gcmd.info[3] << 32) | req.u.gcmd.info[2]); - err = se_send_genl_cmd(se, &req, &res, retry); if (err) return err; - - se->mem_map_size = size / se_mem_page; - se->mem_map = bitmap_zalloc(se->mem_map_size, GFP_KERNEL); - if (!se->mem_map) - return -ENOMEM; - - dev_info(se->dev, "SE module setup down, shared memory size is 0x%x bytes, memory page size is 0x%x bytes\n", - se_mem_size, se_mem_page); + pr_debug("Set win mmap 0x%llx, mask 0x%llx\n", + ((u64)req.u.gcmd.info[1] << 32) | req.u.gcmd.info[0], + ((u64)req.u.gcmd.info[3] << 32) | req.u.gcmd.info[2]);
return err; }
-static void loongson_se_disable_hw(struct loongson_se *se) +static void se_disable_hw(struct loongson_se *se) { - struct se_mailbox_data req = {0}; - struct se_mailbox_data res = {0}; - int retry = 5; + struct se_data req = {0}; + struct se_data res = {0};
/* Stop engine */ req.int_bit = SE_INT_SETUP; req.u.gcmd.cmd = SE_CMD_STOP; - se_send_genl_cmd(se, &req, &res, retry); - + se_send_genl_cmd(se, &req, &res, 5); se_disable_int(se, SE_INT_ALL); - kfree(se->mem_map); }
+/* + * Called by SE's child device driver. + */ int se_send_ch_requeset(struct lsse_ch *ch) { struct loongson_se *se; u32 status, int_bit; - int err = 0; - - if (!ch) - return -EINVAL;
se = ch->se; int_bit = ch->int_bit; - - if ((se_readl(SE_L2SINT_STAT) & int_bit) || - !(se_readl(SE_L2SINT_EN) & int_bit)) + if ((se_readl(se, SE_L2SINT_STAT) & int_bit) || + !(se_readl(se, SE_L2SINT_EN) & int_bit)) return -EBUSY;
se_enable_int(se, int_bit); - se_writel(int_bit, SE_L2SINT_SET); + se_writel(se, int_bit, SE_L2SINT_SET);
- err = readl_relaxed_poll_timeout_atomic(se->base + SE_L2SINT_STAT, status, - !(status & int_bit), 10, 10000); + return readl_relaxed_poll_timeout_atomic(se->base + SE_L2SINT_STAT, status, + !(status & int_bit), 10, 10000);
- return err; } EXPORT_SYMBOL_GPL(se_send_ch_requeset);
-struct lsse_ch *se_init_ch(int id, int data_size, int msg_size, void *priv, - void (*complete)(struct lsse_ch *se_ch)) +/* + * se_init_ch() - Init the channel used by child device. + * + * Allocate the shared memory agreed upon with SE on SE probe, + * and register the callback function when the data processing + * in this channel is completed. + */ +struct lsse_ch *se_init_ch(struct device *dev, int id, int data_size, int msg_size, + void *priv, void (*complete)(struct lsse_ch *se_ch)) { - struct loongson_se *se = &se_dev; + struct loongson_se *se = dev_get_drvdata(dev); struct lsse_ch *ch; unsigned long flag; int data_first, data_nr; @@ -395,7 +346,7 @@ struct lsse_ch *se_init_ch(int id, int data_size, int msg_size, void *priv, return NULL; }
- if (id == 0 || id > SE_CH_MAX) { + if (id > SE_CH_MAX) { dev_err(se->dev, "Channel number %d is invalid\n", id); return NULL; } @@ -407,30 +358,30 @@ struct lsse_ch *se_init_ch(int id, int data_size, int msg_size, void *priv,
spin_lock_irqsave(&se->dev_lock, flag);
- ch = &se_dev.chs[id]; + ch = &se->chs[id]; ch->se = se; ch->id = id; ch->int_bit = BIT(id); se->ch_status |= BIT(id);
- data_nr = round_up(data_size, se_mem_page) / se_mem_page; - data_first = bitmap_find_next_zero_area(se->mem_map, se->mem_map_size, - 0, data_nr, 0); - if (data_first >= se->mem_map_size) { + data_nr = round_up(data_size, PAGE_SIZE) / PAGE_SIZE; + data_first = bitmap_find_next_zero_area(se->mem_map, se->mem_map_pages, + 0, data_nr, 0); + if (data_first >= se->mem_map_pages) { dev_err(se->dev, "Insufficient memory space\n"); spin_unlock_irqrestore(&se->dev_lock, flag); return NULL; }
bitmap_set(se->mem_map, data_first, data_nr); - ch->data_buffer = se->mem_base + data_first * se_mem_page; - ch->data_addr = se->mem_addr + data_first * se_mem_page; + ch->data_buffer = se->mem_base + data_first * PAGE_SIZE; + ch->data_addr = se->mem_addr + data_first * PAGE_SIZE; ch->data_size = data_size;
- msg_nr = round_up(msg_size, se_mem_page) / se_mem_page; - msg_first = bitmap_find_next_zero_area(se->mem_map, se->mem_map_size, - 0, msg_nr, 0); - if (msg_first >= se->mem_map_size) { + msg_nr = round_up(msg_size, PAGE_SIZE) / PAGE_SIZE; + msg_first = bitmap_find_next_zero_area(se->mem_map, se->mem_map_pages, + 0, msg_nr, 0); + if (msg_first >= se->mem_map_pages) { dev_err(se->dev, "Insufficient memory space\n"); bitmap_clear(se->mem_map, data_first, data_nr); spin_unlock_irqrestore(&se->dev_lock, flag); @@ -438,13 +389,11 @@ struct lsse_ch *se_init_ch(int id, int data_size, int msg_size, void *priv, }
bitmap_set(se->mem_map, msg_first, msg_nr); - ch->smsg = se->mem_base + msg_first * se_mem_page; + ch->smsg = se->mem_base + msg_first * PAGE_SIZE; ch->rmsg = ch->smsg + msg_size / 2; ch->msg_size = msg_size; - ch->complete = complete; ch->priv = priv; - spin_lock_init(&ch->ch_lock);
spin_unlock_irqrestore(&se->dev_lock, flag); @@ -462,7 +411,7 @@ EXPORT_SYMBOL_GPL(se_init_ch);
void se_deinit_ch(struct lsse_ch *ch) { - struct loongson_se *se = &se_dev; + struct loongson_se *se = ch->se; unsigned long flag; int first, nr; int id = ch->id; @@ -472,7 +421,7 @@ void se_deinit_ch(struct lsse_ch *ch) return; }
- if (id == 0 || id > SE_CH_MAX) { + if (id > SE_CH_MAX) { dev_err(se->dev, "Channel number %d is invalid\n", id); return; } @@ -483,119 +432,92 @@ void se_deinit_ch(struct lsse_ch *ch) }
spin_lock_irqsave(&se->dev_lock, flag); - se->ch_status &= ~BIT(ch->id);
- first = (ch->data_buffer - se->mem_base) / se_mem_page; - nr = round_up(ch->data_size, se_mem_page) / se_mem_page; + first = (ch->data_buffer - se->mem_base) / PAGE_SIZE; + nr = round_up(ch->data_size, PAGE_SIZE) / PAGE_SIZE; bitmap_clear(se->mem_map, first, nr);
- first = (ch->smsg - se->mem_base) / se_mem_page; - nr = round_up(ch->msg_size, se_mem_page) / se_mem_page; + first = (ch->smsg - se->mem_base) / PAGE_SIZE; + nr = round_up(ch->msg_size, PAGE_SIZE) / PAGE_SIZE; bitmap_clear(se->mem_map, first, nr);
+ se_disable_int(se, ch->int_bit); spin_unlock_irqrestore(&se->dev_lock, flag);
- se_disable_int(se, ch->int_bit); } EXPORT_SYMBOL_GPL(se_deinit_ch);
-static struct platform_device lsse_sdf_pdev = { - .name = "loongson-sdf", - .id = -1, -}; - -static const struct of_device_id loongson_se_of_match[] = { - { .compatible = "loongson,ls3c6000se", }, - {} -}; -MODULE_DEVICE_TABLE(of, loongson_se_of_match); - static int loongson_se_probe(struct platform_device *pdev) { - struct loongson_se *se = &se_dev; - struct resource *res; + struct loongson_se *se; struct device *dev = &pdev->dev; - int nr_irq, err, i; - int irq[8]; - - nr_irq = platform_irq_count(pdev); - if (nr_irq < 0) - return -ENODEV; - - for (i = 0; i < nr_irq; i++) { - irq[i] = platform_get_irq(pdev, i); - if (irq[i] < 0) - return -ENODEV; - } + int nr_irq, irq, err, size;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) + se = devm_kmalloc(dev, sizeof(*se), GFP_KERNEL); + if (!se) + return -ENOMEM; + se->dev = dev; + dev_set_drvdata(dev, se); + init_completion(&se->cmd_completion); + spin_lock_init(&se->cmd_lock); + spin_lock_init(&se->dev_lock); + /* Setup DMA buffer */ + dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); + if (device_property_read_u32(dev, "dmam_size", &size)) return -ENODEV; + size = roundup_pow_of_two(size); + se->mem_base = dmam_alloc_coherent(dev, size, &se->mem_addr, GFP_KERNEL); + if (!se->mem_base) + return -ENOMEM; + se->mem_map_pages = size / PAGE_SIZE; + se->mem_map = devm_bitmap_zalloc(dev, se->mem_map_pages, GFP_KERNEL); + if (!se->mem_map) + return -ENOMEM;
- se->base = devm_ioremap_resource(dev, res); + se->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(se->base)) return PTR_ERR(se->base);
- se->dev = &pdev->dev; - platform_set_drvdata(pdev, se); - dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); - init_completion(&se->cmd_completion); - spin_lock_init(&se->cmd_lock); - spin_lock_init(&se->dev_lock); - - for (i = 0; i < nr_irq; i++) { - err = devm_request_irq(dev, irq[i], loongson_se_irq, 0, - "loongson-se", se); + nr_irq = platform_irq_count(pdev); + if (nr_irq <= 0) + return -ENODEV; + while (nr_irq) { + irq = platform_get_irq(pdev, --nr_irq); + if (irq < 0) + return -ENODEV; + /* Use the same interrupt handler address. + * Determine which irq it is accroding + * SE_S2LINT_STAT register. + */ + err = devm_request_irq(dev, irq, se_irq, 0, + "loongson-se", se); if (err) - goto out; + dev_err(dev, "failed to request irq: %d\n", err); }
- err = se_init_hw(se); - if (err) - goto disable_hw; - - err = misc_register(&lsse_miscdev); + err = se_init_hw(se, se->mem_addr, size); if (err) - goto disable_hw; - - err = platform_device_register(&lsse_sdf_pdev); - if (err) - pr_err("register sdf device failed\n"); - - return 0; - -disable_hw: - loongson_se_disable_hw(se); -out: - for ( ; i >= 0; i--) - devm_free_irq(dev, irq[i], se); + se_disable_hw(se);
return err; }
-static int loongson_se_remove(struct platform_device *pdev) -{ - struct loongson_se *se = platform_get_drvdata(pdev); - - misc_deregister(&lsse_miscdev); - loongson_se_disable_hw(se); - platform_device_unregister(&lsse_sdf_pdev); - - return 0; -} +static const struct acpi_device_id loongson_se_acpi_match[] = { + {"LOON0011", 0}, + {} +}; +MODULE_DEVICE_TABLE(acpi, loongson_se_acpi_match);
static struct platform_driver loongson_se_driver = { .probe = loongson_se_probe, - .remove = loongson_se_remove, .driver = { .name = "loongson-se", - .of_match_table = loongson_se_of_match, + .acpi_match_table = loongson_se_acpi_match, }, }; - module_platform_driver(loongson_se_driver);
-MODULE_AUTHOR("Yinggang Gu"); -MODULE_DESCRIPTION("Loongson SE driver"); MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Loongson Technology Corporation"); +MODULE_DESCRIPTION("Loongson Security Module driver"); diff --git a/drivers/char/lsse_sdf_cdev.c b/drivers/char/lsse_sdf_cdev.c index a4806fbf08d1..3bbe3cbb35ae 100644 --- a/drivers/char/lsse_sdf_cdev.c +++ b/drivers/char/lsse_sdf_cdev.c @@ -1,25 +1,29 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2024 Loongson Technology Corporation Limited + */
-#include <linux/kernel.h> -#include <linux/slab.h> +#include <linux/acpi.h> +#include <linux/cdev.h> #include <linux/init.h> +#include <linux/iopoll.h> +#include <linux/kernel.h> +#include <linux/list.h> #include <linux/miscdevice.h> #include <linux/module.h> -#include <linux/cdev.h> -#include <linux/module.h> -#include <linux/wait.h> #include <linux/of.h> -#include <linux/iopoll.h> #include <linux/platform_device.h> +#include <linux/slab.h> #include <linux/uaccess.h> -#include <asm/se.h> -#include <linux/list.h> +#include <linux/wait.h> +#include <soc/loongson/se.h>
#define SE_SDF_BUFSIZE (PAGE_SIZE * 2) -#define SDF_OPENSESSION 0x204 -#define SDF_CLOSESESSION 0x205 +#define SDF_OPENSESSION (0x204) +#define SDF_CLOSESESSION (0x205)
-struct lsse_sdf_dev { +struct sdf_dev { + struct miscdevice miscdev; struct lsse_ch *se_ch; struct mutex data_lock; bool processing_cmd; @@ -49,37 +53,32 @@ struct sdf_kernel_command { void *handle; };
-#define KERNEL_COMMAND_SIZE (sizeof(struct sdf_kernel_command)) - struct sdf_handle { struct list_head handle_list; void *handle; };
struct sdf_file_pvt_data { - struct lsse_sdf_dev *se; + struct sdf_dev *se; struct list_head handle_list; struct sdf_kernel_command skc; struct sdf_handle *ph; };
-static struct lsse_sdf_dev *se_sdf_dev; - -static void lsse_sdf_complete(struct lsse_ch *ch) +static void sdf_complete(struct lsse_ch *ch) { - struct lsse_sdf_dev *se = (struct lsse_sdf_dev *)ch->priv; + struct sdf_dev *se = (struct sdf_dev *)ch->priv;
se->processing_cmd = false; wake_up(&se->wq); }
-static int se_send_sdf_cmd(struct lsse_sdf_dev *se, int len, int retry) +static int se_send_sdf_cmd(struct sdf_dev *se, int len, int retry) { struct se_sdf_msg *smsg = (struct se_sdf_msg *)se->se_ch->smsg; - unsigned long flag; int err;
- spin_lock_irqsave(&se->se_ch->ch_lock, flag); + spin_lock_irq(&se->se_ch->ch_lock);
smsg->cmd = SE_CMD_SDF; /* One time one cmd */ @@ -90,8 +89,6 @@ static int se_send_sdf_cmd(struct lsse_sdf_dev *se, int len, int retry) if (!retry--) goto out;
- pr_debug("Send sdf cmd, last retry %d times\n", retry); - err = se_send_ch_requeset(se->se_ch); if (err) { udelay(5); @@ -99,27 +96,20 @@ static int se_send_sdf_cmd(struct lsse_sdf_dev *se, int len, int retry) }
out: - spin_unlock_irqrestore(&se->se_ch->ch_lock, flag); + spin_unlock_irq(&se->se_ch->ch_lock);
return err; }
-static int lsse_sdf_recv(struct sdf_file_pvt_data *pvt, char *buf, - size_t size, int user, int *se_ret) +static int sdf_recvu(struct sdf_file_pvt_data *pvt, char __user *buf, int *se_ret) { - int len, time, ret = 0; - struct se_sdf_msg *rmsg; + struct sdf_dev *se = pvt->se; struct sdf_kernel_command *skc; + struct se_sdf_msg *rmsg; struct sdf_handle *ph; - struct lsse_sdf_dev *se = pvt->se; - - if (!se->se_ch->rmsg) { - pr_err("se device is not ready\n"); - return -EBUSY; - } + int ret;
- time = wait_event_timeout(se->wq, !se->processing_cmd, HZ*30); - if (!time) + if (!wait_event_timeout(se->wq, !se->processing_cmd, HZ*10)) return -ETIME;
rmsg = (struct se_sdf_msg *)se->se_ch->rmsg; @@ -127,36 +117,25 @@ static int lsse_sdf_recv(struct sdf_file_pvt_data *pvt, char *buf, pr_err("se get wrong response\n"); return -EIO; } - len = rmsg->data_len; - - if ((!user && len > KERNEL_COMMAND_SIZE) || len > SE_SDF_BUFSIZE - || (size && len > size)) - return -E2BIG;
- if (user) { - ret = copy_to_user((char __user *)buf, - se->se_ch->data_buffer + rmsg->data_off, len); - if (!se_ret) - return ret; - - skc = (struct sdf_kernel_command *) - (se->se_ch->data_buffer + rmsg->data_off); - *se_ret = skc->header.u.ret; - if (skc->header.command == SDF_OPENSESSION && !*se_ret) { - ph = kmalloc(sizeof(*ph), GFP_KERNEL); - if (!ph) - return -ENOMEM; - ph->handle = skc->handle; - list_add(&ph->handle_list, &pvt->handle_list); - } - } else - memcpy(buf, se->se_ch->data_buffer + rmsg->data_off, len); + ret = copy_to_user((char __user *)buf, + se->se_ch->data_buffer + rmsg->data_off, rmsg->data_len); + + skc = (struct sdf_kernel_command *)(se->se_ch->data_buffer + rmsg->data_off); + *se_ret = skc->header.u.ret; + if (skc->header.command == SDF_OPENSESSION && !*se_ret) { + ph = kmalloc(sizeof(*ph), GFP_KERNEL); + if (!ph) + return -ENOMEM; + ph->handle = skc->handle; + list_add(&ph->handle_list, &pvt->handle_list); + }
return ret; }
static struct sdf_handle *find_sdf_handle(void *handle, - struct sdf_file_pvt_data *pvt) + struct sdf_file_pvt_data *pvt) { struct sdf_handle *ph;
@@ -168,43 +147,23 @@ static struct sdf_handle *find_sdf_handle(void *handle, return NULL; }
-static int lsse_sdf_send(struct sdf_file_pvt_data *pvt, const char *buf, - size_t count, int user) +static int sdf_sendu(struct sdf_file_pvt_data *pvt, + const char __user *buf, size_t count) { - int ret, se_ret; - struct sdf_handle *ph = NULL; + struct sdf_dev *se = pvt->se; struct sdf_kernel_command *skc; - struct lsse_sdf_dev *se = pvt->se; + struct sdf_handle *ph = NULL; + int ret, se_ret;
- if (!se->se_ch->smsg) { - pr_err("se device is not ready\n"); - return 0; - } + mutex_lock(&se->data_lock);
- if (count > se->se_ch->data_size) { - pr_err("Invalid size in send: count=%zd, size=%d\n", - count, se->se_ch->data_size); - return -EIO; + if (copy_from_user(se->se_ch->data_buffer, buf, count)) { + ret = -EFAULT; + goto out_unlock; } - - if (user) { - ret = mutex_lock_interruptible(&se->data_lock); - if (ret) - goto out; - } else - mutex_lock(&se->data_lock); - - if (user) { - ret = copy_from_user(se->se_ch->data_buffer, buf, count); - if (ret) { - ret = -EFAULT; - goto out_unlock; - } - skc = (struct sdf_kernel_command *)se->se_ch->data_buffer; - if (skc->header.command == SDF_CLOSESESSION) - ph = find_sdf_handle(skc->handle, pvt); - } else - memcpy(se->se_ch->data_buffer, buf, count); + skc = (struct sdf_kernel_command *)se->se_ch->data_buffer; + if (skc->header.command == SDF_CLOSESESSION) + ph = find_sdf_handle(skc->handle, pvt);
se->processing_cmd = true; ret = se_send_sdf_cmd(se, count, 5); @@ -213,65 +172,107 @@ static int lsse_sdf_send(struct sdf_file_pvt_data *pvt, const char *buf, goto out_unlock; }
- ret = lsse_sdf_recv(pvt, (char *)buf, 0, user, &se_ret); + ret = sdf_recvu(pvt, (char __user *)buf, &se_ret); if (ret) { pr_err("recv failed ret: %x\n", ret); goto out_unlock; } + if (ph && !se_ret) { list_del(&ph->handle_list); kfree(ph); } + out_unlock: mutex_unlock(&se->data_lock); -out: + return ret; }
-static ssize_t lsse_sdf_write(struct file *filp, const char __user *buf, - size_t cnt, loff_t *offt) +static ssize_t sdf_write(struct file *filp, const char __user *buf, + size_t cnt, loff_t *offt) { struct sdf_file_pvt_data *pvt = filp->private_data;
if (cnt > SE_SDF_BUFSIZE) return -E2BIG;
- if (lsse_sdf_send(pvt, buf, cnt, 1)) + if (sdf_sendu(pvt, buf, cnt)) return -EFAULT;
return cnt; }
-static ssize_t lsse_sdf_read(struct file *filp, char __user *buf, - size_t size, loff_t *off) +static int sdf_recvk(struct sdf_file_pvt_data *pvt, char *buf) +{ + struct sdf_dev *se = pvt->se; + struct se_sdf_msg *rmsg; + int time; + + time = wait_event_timeout(se->wq, !se->processing_cmd, HZ*10); + if (!time) + return -ETIME; + + rmsg = (struct se_sdf_msg *)se->se_ch->rmsg; + if (rmsg->cmd != SE_CMD_SDF) { + pr_err("se get wrong response\n"); + return -EIO; + } + memcpy(buf, se->se_ch->data_buffer + rmsg->data_off, rmsg->data_len); + + return 0; +} + +static int sdf_sendk(struct sdf_file_pvt_data *pvt, char *buf, size_t count) { - return lsse_sdf_recv(filp->private_data, buf, size, 1, NULL); + struct sdf_dev *se = pvt->se; + int ret; + + mutex_lock(&se->data_lock); + + memcpy(se->se_ch->data_buffer, buf, count); + se->processing_cmd = true; + ret = se_send_sdf_cmd(se, count, 5); + if (ret) { + pr_err("se_send_sdf_cmd failed\n"); + goto out_unlock; + } + + ret = sdf_recvk(pvt, buf); + if (ret) + pr_err("recv failed ret: %x\n", ret); + +out_unlock: + mutex_unlock(&se->data_lock); + + return ret; }
static int close_one_handle(struct sdf_file_pvt_data *pvt, struct sdf_handle *ph) { struct sdf_kernel_command *skc = &pvt->skc; + int ret;
- skc->header.command = 0x205; + skc->header.command = SDF_CLOSESESSION; skc->header.u.param_cnt = 1; - skc->header.param_len[0] = 8; skc->handle = ph->handle; + skc->header.param_len[0] = sizeof(skc->handle); /* close one session */ - lsse_sdf_send(pvt, (char *)&pvt->skc, KERNEL_COMMAND_SIZE, 0); + ret = sdf_sendk(pvt, (char *)&pvt->skc, sizeof(*skc)); if (skc->header.u.ret) { pr_err("Auto Close Session failed, session handle: %llx, ret: %d\n", - (u64)ph->handle, skc->header.u.ret); + (u64)ph->handle, skc->header.u.ret); return skc->header.u.ret; } kfree(ph);
- return 0; + return ret; }
static int close_all_handle(struct sdf_file_pvt_data *pvt) { - int ret = 0; struct sdf_handle *ph, *tmp; + int ret;
list_for_each_entry_safe(ph, tmp, &pvt->handle_list, handle_list) { list_del(&ph->handle_list); @@ -283,98 +284,95 @@ static int close_all_handle(struct sdf_file_pvt_data *pvt) return 0; }
-static int lsse_sdf_release(struct inode *inode, struct file *filp) +static int sdf_release(struct inode *inode, struct file *filp) { - int ret; struct sdf_file_pvt_data *pvt = filp->private_data; + int ret;
ret = close_all_handle(pvt); - filp->private_data = NULL; kfree(pvt);
- if (ret) - ret = -EFAULT; return ret; }
-static int lsse_sdf_open(struct inode *inode, struct file *filp) +static int sdf_open(struct inode *inode, struct file *filp) { - struct sdf_file_pvt_data *pvt = kmalloc(sizeof(*pvt), GFP_KERNEL); + struct sdf_file_pvt_data *pvt;
+ pvt = kmalloc(sizeof(*pvt), GFP_KERNEL); if (!pvt) return -ENOMEM;
INIT_LIST_HEAD(&pvt->handle_list); - pvt->se = se_sdf_dev; + pvt->se = container_of(filp->private_data, + struct sdf_dev, miscdev); filp->private_data = pvt;
return 0; }
-static const struct file_operations lsse_sdf_fops = { +static const struct file_operations sdf_fops = { .owner = THIS_MODULE, - .open = lsse_sdf_open, - .write = lsse_sdf_write, - .read = lsse_sdf_read, - .release = lsse_sdf_release, + .open = sdf_open, + .write = sdf_write, + .release = sdf_release, };
-static const struct miscdevice lsse_sdf_miscdev = { - .minor = MISC_DYNAMIC_MINOR, - .name = "lsse_sdf", - .fops = &lsse_sdf_fops, -}; - -static int lsse_sdf_probe(struct platform_device *pdev) +static int sdf_probe(struct platform_device *pdev) { - int msg_size; - int ret; + struct sdf_dev *sdf; + int msg_size, ret, ch;
- se_sdf_dev = kzalloc(sizeof(*se_sdf_dev), GFP_KERNEL); - if (IS_ERR_OR_NULL(se_sdf_dev)) - return PTR_ERR(se_sdf_dev); - - mutex_init(&se_sdf_dev->data_lock); - init_waitqueue_head(&se_sdf_dev->wq); - se_sdf_dev->processing_cmd = false; + sdf = devm_kzalloc(&pdev->dev, sizeof(*sdf), GFP_KERNEL); + if (!sdf) + return -ENOMEM; + mutex_init(&sdf->data_lock); + init_waitqueue_head(&sdf->wq); + sdf->processing_cmd = false; + platform_set_drvdata(pdev, sdf);
+ if (device_property_read_u32(&pdev->dev, "channel", &ch)) + return -ENODEV; msg_size = 2 * sizeof(struct se_sdf_msg); - se_sdf_dev->se_ch = se_init_ch(SE_CH_SDF, SE_SDF_BUFSIZE, msg_size, - se_sdf_dev, lsse_sdf_complete); + sdf->se_ch = se_init_ch(pdev->dev.parent, ch, SE_SDF_BUFSIZE, + msg_size, sdf, sdf_complete);
- ret = misc_register(&lsse_sdf_miscdev); - if (ret < 0) { + sdf->miscdev.minor = MISC_DYNAMIC_MINOR; + sdf->miscdev.name = "lsse_sdf"; + sdf->miscdev.fops = &sdf_fops; + ret = misc_register(&sdf->miscdev); + if (ret) pr_err("register sdf dev failed!\n"); - goto out; - } - - return 0; - -out: - kfree(se_sdf_dev);
return ret; }
-static int lsse_sdf_remove(struct platform_device *pdev) +static int sdf_remove(struct platform_device *pdev) { - misc_deregister(&lsse_sdf_miscdev); - se_deinit_ch(se_sdf_dev->se_ch); - kfree(se_sdf_dev); + struct sdf_dev *sdf = platform_get_drvdata(pdev); + + misc_deregister(&sdf->miscdev); + se_deinit_ch(sdf->se_ch);
return 0; }
+static const struct acpi_device_id loongson_sdf_acpi_match[] = { + {"LOON0012", 0}, + {} +}; +MODULE_DEVICE_TABLE(acpi, loongson_sdf_acpi_match); + static struct platform_driver loongson_sdf_driver = { - .probe = lsse_sdf_probe, - .remove = lsse_sdf_remove, + .probe = sdf_probe, + .remove = sdf_remove, .driver = { .name = "loongson-sdf", + .acpi_match_table = loongson_sdf_acpi_match, }, }; module_platform_driver(loongson_sdf_driver);
-MODULE_ALIAS("platform:loongson-sdf"); -MODULE_AUTHOR("Yinggang Gu"); -MODULE_DESCRIPTION("Loongson SE sdf driver"); MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Loongson Technology Corporation"); +MODULE_DESCRIPTION("Loongson Secure Device Function driver"); diff --git a/arch/loongarch/include/asm/se.h b/include/soc/loongson/se.h similarity index 68% rename from arch/loongarch/include/asm/se.h rename to include/soc/loongson/se.h index d0f9d43d60d2..d9864e3f3b85 100644 --- a/arch/loongarch/include/asm/se.h +++ b/include/soc/loongson/se.h @@ -1,23 +1,11 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2012 IBM Corporation - * - * Copyright 2023 Loongson Technology, Inc. - * Yinggang Gu guyinggang@loongson.cn - * - * Device driver for Loongson SE module. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. - * - */ +/* Copyright (C) 2024 Loongson Technology Corporation Limited */ + #ifndef __LOONGSON_SE_H__ #define __LOONGSON_SE_H__
-#define SE_MAILBOX_S 0x0 -#define SE_MAILBOX_L 0x20 +#define SE_DATA_S 0x0 +#define SE_DATA_L 0x20 #define SE_S2LINT_STAT 0x88 #define SE_S2LINT_EN 0x8c #define SE_S2LINT_SET 0x90 @@ -29,20 +17,20 @@
/* INT bit definition */ #define SE_INT_SETUP BIT(0) -#define SE_INT_SM2 BIT(0) -#define SE_INT_SM3 BIT(0) -#define SE_INT_SM4 BIT(0) -#define SE_INT_RNG BIT(0) -#define SE_INT_TPM BIT(5) -#define SE_INT_ALL 0xffffffff +#define SE_INT_SM2 BIT(0) +#define SE_INT_SM3 BIT(0) +#define SE_INT_SM4 BIT(0) +#define SE_INT_RNG BIT(0) +#define SE_INT_TPM BIT(5) +#define SE_INT_ALL 0xffffffff
#define SE_CMD_START 0x0 -#define SE_CMD_STOP 0x1 +#define SE_CMD_STOP 0x1 #define SE_CMD_GETVER 0x2 #define SE_CMD_SETBUF 0x3 #define SE_CMD_SETMSG 0x4
-#define SE_CMD_RNG 0x100 +#define SE_CMD_RNG 0x100
#define SE_CMD_SM2_SIGN 0x200 #define SE_CMD_SM2_VSIGN 0x201 @@ -57,11 +45,11 @@ #define SE_CMD_SM4_CBC_DECRY 0x403 #define SE_CMD_SM4_CTR 0x404
-#define SE_CMD_TPM 0x500 +#define SE_CMD_TPM 0x500 #define SE_CMD_ZUC_INIT_READ 0x600 #define SE_CMD_ZUC_READ 0x601
-#define SE_CMD_SDF 0x700 +#define SE_CMD_SDF 0x700
#define SE_CH_MAX 32
@@ -91,10 +79,10 @@ struct se_res { u32 info[6]; };
-struct se_mailbox_data { +struct se_data { u32 int_bit; union { - u32 mailbox[8]; + u32 data[8]; struct se_cmd gcmd; struct se_res res; } u; @@ -128,19 +116,19 @@ struct loongson_se { void *mem_base; dma_addr_t mem_addr; unsigned long *mem_map; - int mem_map_size; + int mem_map_pages; void *smsg; void *rmsg;
/* Synchronous CMD */ struct completion cmd_completion;
- /* Virtual Channel */ + /* Channel */ struct lsse_ch chs[SE_CH_MAX]; };
-struct lsse_ch *se_init_ch(int id, int data_size, int msg_size, void *priv, - void (*complete)(struct lsse_ch *se_ch)); +struct lsse_ch *se_init_ch(struct device *dev, int id, int data_size, int msg_size, + void *priv, void (*complete)(struct lsse_ch *se_ch)); void se_deinit_ch(struct lsse_ch *ch); int se_send_ch_requeset(struct lsse_ch *ch);
From: wanghongliang wanghongliang@loongson.cn
LoongArch inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IBENRY CVE: NA
--------------------------------
Signed-off-by: wanghongliang wanghongliang@loongson.cn --- drivers/irqchip/irq-loongson-eiointc.c | 47 +++++++++++++++++++------- 1 file changed, 34 insertions(+), 13 deletions(-)
diff --git a/drivers/irqchip/irq-loongson-eiointc.c b/drivers/irqchip/irq-loongson-eiointc.c index 1c7f97dac83b..b4fbf52c7ef5 100644 --- a/drivers/irqchip/irq-loongson-eiointc.c +++ b/drivers/irqchip/irq-loongson-eiointc.c @@ -44,6 +44,16 @@
#define MAX_EIO_NODES (NR_CPUS / CORES_PER_EIO_NODE)
+typedef struct { DECLARE_BITMAP(bits, MAX_EIO_NODES); } extioi_node_map; + +#define EXTIOI_NODE_MASK_NONE \ +((extioi_node_map) { { \ + [0 ... BITS_TO_LONGS(MAX_EIO_NODES)-1] = 0UL \ +} }) + +extioi_node_map extioi_node_maps = EXTIOI_NODE_MASK_NONE; + + static int nr_pics;
struct eiointc_priv { @@ -79,6 +89,7 @@ static void eiointc_set_irq_route(int pos, unsigned int cpu, unsigned int mnode, int i, node, cpu_node, route_node; unsigned char coremap; uint32_t pos_off, data, data_byte, data_mask; + nodemask_t eio_node_map = *node_map;
pos_off = pos & ~3; data_byte = pos & 3; @@ -90,13 +101,14 @@ static void eiointc_set_irq_route(int pos, unsigned int cpu, unsigned int mnode,
for_each_online_cpu(i) { node = cpu_to_eio_node(i); - if (!node_isset(node, *node_map)) - continue; - - /* EIO node 0 is in charge of inter-node interrupt dispatch */ - route_node = (node == mnode) ? cpu_node : node; - data = ((coremap | (route_node << 4)) << (data_byte * 8)); - csr_any_send(EIOINTC_REG_ROUTE + pos_off, data, data_mask, node * CORES_PER_EIO_NODE); + if (node_isset(node, eio_node_map)) { + node_clear(node, eio_node_map); + /* EIO node 0 is in charge of inter-node interrupt dispatch */ + route_node = (node == mnode) ? cpu_node : node; + data = ((coremap | (route_node << 4)) << (data_byte * 8)); + csr_any_send(EIOINTC_REG_ROUTE + pos_off, data, data_mask, + cpu_logical_map(i)); + } } }
@@ -118,7 +130,7 @@ static void virt_extioi_set_irq_route(int irq, unsigned int cpu)
static int eiointc_set_irq_affinity(struct irq_data *d, const struct cpumask *affinity, bool force) { - unsigned int cpu; + unsigned int cpu, i; unsigned long flags; uint32_t vector, regaddr; struct cpumask intersect_affinity; @@ -143,16 +155,20 @@ static int eiointc_set_irq_affinity(struct irq_data *d, const struct cpumask *af virt_extioi_set_irq_route(vector, cpu); iocsr_write32(EIOINTC_ALL_ENABLE, regaddr); } else { + for_each_online_cpu(i) { + if (cpu_to_eio_node(i) == priv->node) + break; + } /* Mask target vector */ csr_any_send(regaddr, EIOINTC_ALL_ENABLE & (~BIT(vector & 0x1F)), - 0x0, priv->node * CORES_PER_EIO_NODE); + 0x0, cpu_logical_map(i));
/* Set route for target vector */ eiointc_set_irq_route(vector, cpu, priv->node, &priv->node_map);
/* Unmask target vector */ csr_any_send(regaddr, EIOINTC_ALL_ENABLE, - 0x0, priv->node * CORES_PER_EIO_NODE); + 0x0, cpu_logical_map(i)); }
irq_data_update_effective_affinity(d, cpumask_of(cpu)); @@ -187,7 +203,7 @@ static int eiointc_router_init(unsigned int cpu) return -1; }
- if ((cpu_logical_map(cpu) % cores) == 0) { + if (!test_bit(node, (&extioi_node_maps)->bits)) { eiointc_enable();
for (i = 0; i < eiointc_priv[0]->vec_count / 32; i++) { @@ -208,7 +224,9 @@ static int eiointc_router_init(unsigned int cpu) else if (index == 0) bit = BIT(cpu_logical_map(0)); else - bit = (eiointc_priv[index]->node << 4) | 1; + bit = (eiointc_priv[index]->node << 4) | + BIT(cpu_logical_map(smp_processor_id()) % + CORES_PER_EIO_NODE);
data = bit | (bit << 8) | (bit << 16) | (bit << 24); iocsr_write32(data, EIOINTC_REG_ROUTE + i * 4); @@ -217,8 +235,10 @@ static int eiointc_router_init(unsigned int cpu) for (i = 0; i < eiointc_priv[0]->vec_count / 32; i++) { data = 0xffffffff; iocsr_write32(data, EIOINTC_REG_ENABLE + i * 4); - iocsr_write32(data, EIOINTC_REG_BOUNCE + i * 4); + iocsr_write32(0, EIOINTC_REG_BOUNCE + i * 4); } + + set_bit(node, (&extioi_node_maps)->bits); }
return 0; @@ -348,6 +368,7 @@ static int eiointc_suspend(void)
static void eiointc_resume(void) { + extioi_node_maps = EXTIOI_NODE_MASK_NONE; eiointc_router_init(0); }
From: wanghongliang wanghongliang@loongson.cn
LoongArch inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IBENRY CVE: NA
--------------------------------
Signed-off-by: wanghongliang wanghongliang@loongson.cn --- arch/loongarch/include/asm/topology.h | 4 ++++ arch/loongarch/kernel/setup.c | 1 + arch/loongarch/kernel/smp.c | 3 +++ drivers/platform/loongarch/cpu_hwmon.c | 3 +-- 4 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/arch/loongarch/include/asm/topology.h b/arch/loongarch/include/asm/topology.h index 66128dec0bf6..379f5e4830eb 100644 --- a/arch/loongarch/include/asm/topology.h +++ b/arch/loongarch/include/asm/topology.h @@ -29,10 +29,14 @@ void numa_set_distance(int from, int to, int distance); #endif
#ifdef CONFIG_SMP +extern unsigned int __max_packages; +#define topology_max_packages() (__max_packages) #define topology_physical_package_id(cpu) (cpu_data[cpu].package) #define topology_core_id(cpu) (cpu_data[cpu].core) #define topology_core_cpumask(cpu) (&cpu_core_map[cpu]) #define topology_sibling_cpumask(cpu) (&cpu_sibling_map[cpu]) +#else +#define topology_max_packages() (1) #endif
#include <asm-generic/topology.h> diff --git a/arch/loongarch/kernel/setup.c b/arch/loongarch/kernel/setup.c index 8362cbe9f102..415f16464214 100644 --- a/arch/loongarch/kernel/setup.c +++ b/arch/loongarch/kernel/setup.c @@ -135,6 +135,7 @@ static void __init parse_cpu_table(const struct dmi_header *dm)
loongson_sysconf.cpuname = (void *)dmi_string_parse(dm, dmi_data[16]); loongson_sysconf.cores_per_package = *(dmi_data + SMBIOS_THREAD_PACKAGE_OFFSET); + __max_packages++;
pr_info("CpuClock = %llu\n", cpu_clock_freq); } diff --git a/arch/loongarch/kernel/smp.c b/arch/loongarch/kernel/smp.c index d4717fc9e1db..5d02bf5126b7 100644 --- a/arch/loongarch/kernel/smp.c +++ b/arch/loongarch/kernel/smp.c @@ -74,6 +74,9 @@ static const char *ipi_types[NR_IPI] __tracepoint_string = { [IPI_CLEAR_VECTOR] = "Clear vector interrupts", };
+unsigned int __max_packages __read_mostly; +EXPORT_SYMBOL(__max_packages); + void show_ipi_list(struct seq_file *p, int prec) { unsigned int cpu, i; diff --git a/drivers/platform/loongarch/cpu_hwmon.c b/drivers/platform/loongarch/cpu_hwmon.c index 93a05993745a..57e771f39781 100644 --- a/drivers/platform/loongarch/cpu_hwmon.c +++ b/drivers/platform/loongarch/cpu_hwmon.c @@ -154,8 +154,7 @@ static int __init loongson_hwmon_init(void)
pr_info("Loongson Hwmon Enter...\n");
- nr_packages = loongson_sysconf.nr_cpus / - loongson_sysconf.cores_per_package; + nr_packages = topology_max_packages();
cpu_hwmon_dev = hwmon_device_register_with_groups(NULL, "cpu_hwmon", NULL, cpu_hwmon_groups);
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://gitee.com/openeuler/kernel/pulls/14692 邮件列表地址:https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/2...
FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://gitee.com/openeuler/kernel/pulls/14692 Mailing list address: https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/2...