From c784e46c8445635afd81bd4089fc5e87271a8f3b Mon Sep 17 00:00:00 2001 From: Ralf Schlatterbeck Date: Wed, 19 May 2021 13:54:51 +0200 Subject: [PATCH 001/696] auxdisplay: Add I2C gpio expander example The hd44780 displays are often used with pcf8574 based I/O expanders. Add example to documentation. Suggested-by: Geert Uytterhoeven Signed-off-by: Ralf Schlatterbeck [Added Suggested-by tag] Signed-off-by: Miguel Ojeda --- .../bindings/auxdisplay/hit,hd44780.yaml | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/auxdisplay/hit,hd44780.yaml b/Documentation/devicetree/bindings/auxdisplay/hit,hd44780.yaml index 9222b06e93a0..fde07e4b119d 100644 --- a/Documentation/devicetree/bindings/auxdisplay/hit,hd44780.yaml +++ b/Documentation/devicetree/bindings/auxdisplay/hit,hd44780.yaml @@ -12,7 +12,10 @@ maintainers: description: The Hitachi HD44780 Character LCD Controller is commonly used on character LCDs that can display one or more lines of text. It exposes an M6800 bus - interface, which can be used in either 4-bit or 8-bit mode. + interface, which can be used in either 4-bit or 8-bit mode. By using a + GPIO expander it is possible to use the driver with one of the popular I2C + expander boards based on the PCF8574 available for these displays. For + an example see below. properties: compatible: @@ -94,3 +97,29 @@ examples: display-height-chars = <2>; display-width-chars = <16>; }; + - | + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + pcf8574: pcf8574@27 { + compatible = "nxp,pcf8574"; + reg = <0x27>; + gpio-controller; + #gpio-cells = <2>; + }; + }; + hd44780 { + compatible = "hit,hd44780"; + display-height-chars = <2>; + display-width-chars = <16>; + data-gpios = <&pcf8574 4 0>, + <&pcf8574 5 0>, + <&pcf8574 6 0>, + <&pcf8574 7 0>; + enable-gpios = <&pcf8574 2 0>; + rs-gpios = <&pcf8574 0 0>; + rw-gpios = <&pcf8574 1 0>; + backlight-gpios = <&pcf8574 3 0>; + }; From 53bb4a9dda0b51c161b2573641c586f7d5d7e189 Mon Sep 17 00:00:00 2001 From: Pu Lehui Date: Fri, 14 May 2021 14:44:38 +0800 Subject: [PATCH 002/696] firewire: net: remove unused variable 'guid' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GCC reports the following warning with W=1: drivers/firewire/net.c:493:9: warning: variable ‘guid’ set but not used [-Wunused-but-set-variable] 493 | __be64 guid; | ^~~~ This variable is not used anymore since commit 6752c8db8e0c ("firewire net, ipv4 arp: Extend hardware address and remove driver-level packet inspection."). Remove it to fix the warning. Signed-off-by: Pu Lehui Signed-off-by: Stefan Richter --- drivers/firewire/net.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c index 715e491dfbc3..4c3fd2eed1da 100644 --- a/drivers/firewire/net.c +++ b/drivers/firewire/net.c @@ -488,9 +488,7 @@ static int fwnet_finish_incoming_packet(struct net_device *net, struct sk_buff *skb, u16 source_node_id, bool is_broadcast, u16 ether_type) { - struct fwnet_device *dev; int status; - __be64 guid; switch (ether_type) { case ETH_P_ARP: @@ -503,7 +501,6 @@ static int fwnet_finish_incoming_packet(struct net_device *net, goto err; } - dev = netdev_priv(net); /* Write metadata, and then pass to the receive level */ skb->dev = net; skb->ip_summed = CHECKSUM_NONE; @@ -512,7 +509,6 @@ static int fwnet_finish_incoming_packet(struct net_device *net, * Parse the encapsulation header. This actually does the job of * converting to an ethernet-like pseudo frame header. */ - guid = cpu_to_be64(dev->card->guid); if (dev_hard_header(skb, net, ether_type, is_broadcast ? net->broadcast : net->dev_addr, NULL, skb->len) >= 0) { From 54b3bd99f094b3b919de4078f60d722e62a767e3 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 13 Jun 2021 15:27:43 +0200 Subject: [PATCH 003/696] firewire: nosy: switch from 'pci_' to 'dma_' API The wrappers in include/linux/pci-dma-compat.h should go away. The patch has been generated with the coccinelle script below and has been hand modified to replace GFP_ with a correct flag. It has been compile tested. When memory is allocated in 'add_card()', GFP_KERNEL can be used because this flag is already used a few lines above and no lock is taken in the between. While at it, also remove some useless casting. @@ @@ - PCI_DMA_BIDIRECTIONAL + DMA_BIDIRECTIONAL @@ @@ - PCI_DMA_TODEVICE + DMA_TO_DEVICE @@ @@ - PCI_DMA_FROMDEVICE + DMA_FROM_DEVICE @@ @@ - PCI_DMA_NONE + DMA_NONE @@ expression e1, e2, e3; @@ - pci_alloc_consistent(e1, e2, e3) + dma_alloc_coherent(&e1->dev, e2, e3, GFP_) @@ expression e1, e2, e3; @@ - pci_zalloc_consistent(e1, e2, e3) + dma_alloc_coherent(&e1->dev, e2, e3, GFP_) @@ expression e1, e2, e3, e4; @@ - pci_free_consistent(e1, e2, e3, e4) + dma_free_coherent(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_map_single(e1, e2, e3, e4) + dma_map_single(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_unmap_single(e1, e2, e3, e4) + dma_unmap_single(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4, e5; @@ - pci_map_page(e1, e2, e3, e4, e5) + dma_map_page(&e1->dev, e2, e3, e4, e5) @@ expression e1, e2, e3, e4; @@ - pci_unmap_page(e1, e2, e3, e4) + dma_unmap_page(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_map_sg(e1, e2, e3, e4) + dma_map_sg(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_unmap_sg(e1, e2, e3, e4) + dma_unmap_sg(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_single_for_cpu(e1, e2, e3, e4) + dma_sync_single_for_cpu(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_single_for_device(e1, e2, e3, e4) + dma_sync_single_for_device(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_sg_for_cpu(e1, e2, e3, e4) + dma_sync_sg_for_cpu(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_sg_for_device(e1, e2, e3, e4) + dma_sync_sg_for_device(&e1->dev, e2, e3, e4) @@ expression e1, e2; @@ - pci_dma_mapping_error(e1, e2) + dma_mapping_error(&e1->dev, e2) @@ expression e1, e2; @@ - pci_set_dma_mask(e1, e2) + dma_set_mask(&e1->dev, e2) @@ expression e1, e2; @@ - pci_set_consistent_dma_mask(e1, e2) + dma_set_coherent_mask(&e1->dev, e2) Signed-off-by: Christophe JAILLET Signed-off-by: Stefan Richter --- drivers/firewire/nosy.c | 43 +++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/drivers/firewire/nosy.c b/drivers/firewire/nosy.c index 88ed971e32c0..b0d671db178a 100644 --- a/drivers/firewire/nosy.c +++ b/drivers/firewire/nosy.c @@ -511,12 +511,12 @@ remove_card(struct pci_dev *dev) wake_up_interruptible(&client->buffer.wait); spin_unlock_irq(&lynx->client_list_lock); - pci_free_consistent(lynx->pci_device, sizeof(struct pcl), - lynx->rcv_start_pcl, lynx->rcv_start_pcl_bus); - pci_free_consistent(lynx->pci_device, sizeof(struct pcl), - lynx->rcv_pcl, lynx->rcv_pcl_bus); - pci_free_consistent(lynx->pci_device, PAGE_SIZE, - lynx->rcv_buffer, lynx->rcv_buffer_bus); + dma_free_coherent(&lynx->pci_device->dev, sizeof(struct pcl), + lynx->rcv_start_pcl, lynx->rcv_start_pcl_bus); + dma_free_coherent(&lynx->pci_device->dev, sizeof(struct pcl), + lynx->rcv_pcl, lynx->rcv_pcl_bus); + dma_free_coherent(&lynx->pci_device->dev, PAGE_SIZE, lynx->rcv_buffer, + lynx->rcv_buffer_bus); iounmap(lynx->registers); pci_disable_device(dev); @@ -532,7 +532,7 @@ add_card(struct pci_dev *dev, const struct pci_device_id *unused) u32 p, end; int ret, i; - if (pci_set_dma_mask(dev, DMA_BIT_MASK(32))) { + if (dma_set_mask(&dev->dev, DMA_BIT_MASK(32))) { dev_err(&dev->dev, "DMA address limits not supported for PCILynx hardware\n"); return -ENXIO; @@ -564,12 +564,16 @@ add_card(struct pci_dev *dev, const struct pci_device_id *unused) goto fail_deallocate_lynx; } - lynx->rcv_start_pcl = pci_alloc_consistent(lynx->pci_device, - sizeof(struct pcl), &lynx->rcv_start_pcl_bus); - lynx->rcv_pcl = pci_alloc_consistent(lynx->pci_device, - sizeof(struct pcl), &lynx->rcv_pcl_bus); - lynx->rcv_buffer = pci_alloc_consistent(lynx->pci_device, - RCV_BUFFER_SIZE, &lynx->rcv_buffer_bus); + lynx->rcv_start_pcl = dma_alloc_coherent(&lynx->pci_device->dev, + sizeof(struct pcl), + &lynx->rcv_start_pcl_bus, + GFP_KERNEL); + lynx->rcv_pcl = dma_alloc_coherent(&lynx->pci_device->dev, + sizeof(struct pcl), + &lynx->rcv_pcl_bus, GFP_KERNEL); + lynx->rcv_buffer = dma_alloc_coherent(&lynx->pci_device->dev, + RCV_BUFFER_SIZE, + &lynx->rcv_buffer_bus, GFP_KERNEL); if (lynx->rcv_start_pcl == NULL || lynx->rcv_pcl == NULL || lynx->rcv_buffer == NULL) { @@ -667,14 +671,15 @@ fail_free_irq: fail_deallocate_buffers: if (lynx->rcv_start_pcl) - pci_free_consistent(lynx->pci_device, sizeof(struct pcl), - lynx->rcv_start_pcl, lynx->rcv_start_pcl_bus); + dma_free_coherent(&lynx->pci_device->dev, sizeof(struct pcl), + lynx->rcv_start_pcl, + lynx->rcv_start_pcl_bus); if (lynx->rcv_pcl) - pci_free_consistent(lynx->pci_device, sizeof(struct pcl), - lynx->rcv_pcl, lynx->rcv_pcl_bus); + dma_free_coherent(&lynx->pci_device->dev, sizeof(struct pcl), + lynx->rcv_pcl, lynx->rcv_pcl_bus); if (lynx->rcv_buffer) - pci_free_consistent(lynx->pci_device, PAGE_SIZE, - lynx->rcv_buffer, lynx->rcv_buffer_bus); + dma_free_coherent(&lynx->pci_device->dev, PAGE_SIZE, + lynx->rcv_buffer, lynx->rcv_buffer_bus); iounmap(lynx->registers); fail_deallocate_lynx: From fe364a7d95c24e07e9b3f2ab917f01d6d8330bba Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 12 Jul 2021 14:39:40 +0300 Subject: [PATCH 004/696] dmaengine: dw: Program xBAR hardware for Elkhart Lake Intel Elkhart Lake PSE DMA implementation is integrated with crossbar IP in order to serve more hardware than there are DMA request lines available. Due to this, program xBAR hardware to make flexible support of PSE peripheral. The Device-to-Device has not been tested and it's not supported by DMA Engine, but it's left in the code for the sake of documenting hardware features. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210712113940.42753-1-andriy.shevchenko@linux.intel.com Signed-off-by: Vinod Koul --- drivers/dma/dw/idma32.c | 138 ++++++++++++++++++++++++++- drivers/dma/dw/internal.h | 16 ++++ drivers/dma/dw/pci.c | 6 +- drivers/dma/dw/platform.c | 6 +- include/linux/platform_data/dma-dw.h | 3 + 5 files changed, 160 insertions(+), 9 deletions(-) diff --git a/drivers/dma/dw/idma32.c b/drivers/dma/dw/idma32.c index 3ce44de25d33..58f4078d83fe 100644 --- a/drivers/dma/dw/idma32.c +++ b/drivers/dma/dw/idma32.c @@ -1,15 +1,144 @@ // SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2013,2018 Intel Corporation +// Copyright (C) 2013,2018,2020-2021 Intel Corporation #include #include #include +#include +#include #include #include #include "internal.h" -static void idma32_initialize_chan(struct dw_dma_chan *dwc) +#define DMA_CTL_CH(x) (0x1000 + (x) * 4) +#define DMA_SRC_ADDR_FILLIN(x) (0x1100 + (x) * 4) +#define DMA_DST_ADDR_FILLIN(x) (0x1200 + (x) * 4) +#define DMA_XBAR_SEL(x) (0x1300 + (x) * 4) +#define DMA_REGACCESS_CHID_CFG (0x1400) + +#define CTL_CH_TRANSFER_MODE_MASK GENMASK(1, 0) +#define CTL_CH_TRANSFER_MODE_S2S 0 +#define CTL_CH_TRANSFER_MODE_S2D 1 +#define CTL_CH_TRANSFER_MODE_D2S 2 +#define CTL_CH_TRANSFER_MODE_D2D 3 +#define CTL_CH_RD_RS_MASK GENMASK(4, 3) +#define CTL_CH_WR_RS_MASK GENMASK(6, 5) +#define CTL_CH_RD_NON_SNOOP_BIT BIT(8) +#define CTL_CH_WR_NON_SNOOP_BIT BIT(9) + +#define XBAR_SEL_DEVID_MASK GENMASK(15, 0) +#define XBAR_SEL_RX_TX_BIT BIT(16) +#define XBAR_SEL_RX_TX_SHIFT 16 + +#define REGACCESS_CHID_MASK GENMASK(2, 0) + +static unsigned int idma32_get_slave_devfn(struct dw_dma_chan *dwc) +{ + struct device *slave = dwc->chan.slave; + + if (!slave || !dev_is_pci(slave)) + return 0; + + return to_pci_dev(slave)->devfn; +} + +static void idma32_initialize_chan_xbar(struct dw_dma_chan *dwc) +{ + struct dw_dma *dw = to_dw_dma(dwc->chan.device); + void __iomem *misc = __dw_regs(dw); + u32 cfghi = 0, cfglo = 0; + u8 dst_id, src_id; + u32 value; + + /* DMA Channel ID Configuration register must be programmed first */ + value = readl(misc + DMA_REGACCESS_CHID_CFG); + + value &= ~REGACCESS_CHID_MASK; + value |= dwc->chan.chan_id; + + writel(value, misc + DMA_REGACCESS_CHID_CFG); + + /* Configure channel attributes */ + value = readl(misc + DMA_CTL_CH(dwc->chan.chan_id)); + + value &= ~(CTL_CH_RD_NON_SNOOP_BIT | CTL_CH_WR_NON_SNOOP_BIT); + value &= ~(CTL_CH_RD_RS_MASK | CTL_CH_WR_RS_MASK); + value &= ~CTL_CH_TRANSFER_MODE_MASK; + + switch (dwc->direction) { + case DMA_MEM_TO_DEV: + value |= CTL_CH_TRANSFER_MODE_D2S; + value |= CTL_CH_WR_NON_SNOOP_BIT; + break; + case DMA_DEV_TO_MEM: + value |= CTL_CH_TRANSFER_MODE_S2D; + value |= CTL_CH_RD_NON_SNOOP_BIT; + break; + default: + /* + * Memory-to-Memory and Device-to-Device are ignored for now. + * + * For Memory-to-Memory transfers we would need to set mode + * and disable snooping on both sides. + */ + return; + } + + writel(value, misc + DMA_CTL_CH(dwc->chan.chan_id)); + + /* Configure crossbar selection */ + value = readl(misc + DMA_XBAR_SEL(dwc->chan.chan_id)); + + /* DEVFN selection */ + value &= ~XBAR_SEL_DEVID_MASK; + value |= idma32_get_slave_devfn(dwc); + + switch (dwc->direction) { + case DMA_MEM_TO_DEV: + value |= XBAR_SEL_RX_TX_BIT; + break; + case DMA_DEV_TO_MEM: + value &= ~XBAR_SEL_RX_TX_BIT; + break; + default: + /* Memory-to-Memory and Device-to-Device are ignored for now */ + return; + } + + writel(value, misc + DMA_XBAR_SEL(dwc->chan.chan_id)); + + /* Configure DMA channel low and high registers */ + switch (dwc->direction) { + case DMA_MEM_TO_DEV: + dst_id = dwc->chan.chan_id; + src_id = dwc->dws.src_id; + break; + case DMA_DEV_TO_MEM: + dst_id = dwc->dws.dst_id; + src_id = dwc->chan.chan_id; + break; + default: + /* Memory-to-Memory and Device-to-Device are ignored for now */ + return; + } + + /* Set default burst alignment */ + cfglo |= IDMA32C_CFGL_DST_BURST_ALIGN | IDMA32C_CFGL_SRC_BURST_ALIGN; + + /* Low 4 bits of the request lines */ + cfghi |= IDMA32C_CFGH_DST_PER(dst_id & 0xf); + cfghi |= IDMA32C_CFGH_SRC_PER(src_id & 0xf); + + /* Request line extension (2 bits) */ + cfghi |= IDMA32C_CFGH_DST_PER_EXT(dst_id >> 4 & 0x3); + cfghi |= IDMA32C_CFGH_SRC_PER_EXT(src_id >> 4 & 0x3); + + channel_writel(dwc, CFG_LO, cfglo); + channel_writel(dwc, CFG_HI, cfghi); +} + +static void idma32_initialize_chan_generic(struct dw_dma_chan *dwc) { u32 cfghi = 0; u32 cfglo = 0; @@ -134,7 +263,10 @@ int idma32_dma_probe(struct dw_dma_chip *chip) return -ENOMEM; /* Channel operations */ - dw->initialize_chan = idma32_initialize_chan; + if (chip->pdata->quirks & DW_DMA_QUIRK_XBAR_PRESENT) + dw->initialize_chan = idma32_initialize_chan_xbar; + else + dw->initialize_chan = idma32_initialize_chan_generic; dw->suspend_chan = idma32_suspend_chan; dw->resume_chan = idma32_resume_chan; dw->prepare_ctllo = idma32_prepare_ctllo; diff --git a/drivers/dma/dw/internal.h b/drivers/dma/dw/internal.h index 2e1c52eefdeb..563ce73488db 100644 --- a/drivers/dma/dw/internal.h +++ b/drivers/dma/dw/internal.h @@ -74,4 +74,20 @@ static __maybe_unused const struct dw_dma_chip_pdata idma32_chip_pdata = { .remove = idma32_dma_remove, }; +static const struct dw_dma_platform_data xbar_pdata = { + .nr_channels = 8, + .chan_allocation_order = CHAN_ALLOCATION_ASCENDING, + .chan_priority = CHAN_PRIORITY_ASCENDING, + .block_size = 131071, + .nr_masters = 1, + .data_width = {4}, + .quirks = DW_DMA_QUIRK_XBAR_PRESENT, +}; + +static __maybe_unused const struct dw_dma_chip_pdata xbar_chip_pdata = { + .pdata = &xbar_pdata, + .probe = idma32_dma_probe, + .remove = idma32_dma_remove, +}; + #endif /* _DMA_DW_INTERNAL_H */ diff --git a/drivers/dma/dw/pci.c b/drivers/dma/dw/pci.c index 1142aa6f8c4a..26a3f926da02 100644 --- a/drivers/dma/dw/pci.c +++ b/drivers/dma/dw/pci.c @@ -120,9 +120,9 @@ static const struct pci_device_id dw_pci_id_table[] = { { PCI_VDEVICE(INTEL, 0x22c0), (kernel_ulong_t)&dw_dma_chip_pdata }, /* Elkhart Lake iDMA 32-bit (PSE DMA) */ - { PCI_VDEVICE(INTEL, 0x4bb4), (kernel_ulong_t)&idma32_chip_pdata }, - { PCI_VDEVICE(INTEL, 0x4bb5), (kernel_ulong_t)&idma32_chip_pdata }, - { PCI_VDEVICE(INTEL, 0x4bb6), (kernel_ulong_t)&idma32_chip_pdata }, + { PCI_VDEVICE(INTEL, 0x4bb4), (kernel_ulong_t)&xbar_chip_pdata }, + { PCI_VDEVICE(INTEL, 0x4bb5), (kernel_ulong_t)&xbar_chip_pdata }, + { PCI_VDEVICE(INTEL, 0x4bb6), (kernel_ulong_t)&xbar_chip_pdata }, /* Haswell */ { PCI_VDEVICE(INTEL, 0x9c60), (kernel_ulong_t)&dw_dma_chip_pdata }, diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c index 0585d749d935..246118955877 100644 --- a/drivers/dma/dw/platform.c +++ b/drivers/dma/dw/platform.c @@ -149,9 +149,9 @@ static const struct acpi_device_id dw_dma_acpi_id_table[] = { { "808622C0", (kernel_ulong_t)&dw_dma_chip_pdata }, /* Elkhart Lake iDMA 32-bit (PSE DMA) */ - { "80864BB4", (kernel_ulong_t)&idma32_chip_pdata }, - { "80864BB5", (kernel_ulong_t)&idma32_chip_pdata }, - { "80864BB6", (kernel_ulong_t)&idma32_chip_pdata }, + { "80864BB4", (kernel_ulong_t)&xbar_chip_pdata }, + { "80864BB5", (kernel_ulong_t)&xbar_chip_pdata }, + { "80864BB6", (kernel_ulong_t)&xbar_chip_pdata }, { } }; diff --git a/include/linux/platform_data/dma-dw.h b/include/linux/platform_data/dma-dw.h index b34a094b2258..b11b0c8bc5da 100644 --- a/include/linux/platform_data/dma-dw.h +++ b/include/linux/platform_data/dma-dw.h @@ -52,6 +52,7 @@ struct dw_dma_slave { * @max_burst: Maximum value of burst transaction size supported by hardware * per channel (in units of CTL.SRC_TR_WIDTH/CTL.DST_TR_WIDTH). * @protctl: Protection control signals setting per channel. + * @quirks: Optional platform quirks. */ struct dw_dma_platform_data { unsigned int nr_channels; @@ -71,6 +72,8 @@ struct dw_dma_platform_data { #define CHAN_PROTCTL_CACHEABLE BIT(2) #define CHAN_PROTCTL_MASK GENMASK(2, 0) unsigned char protctl; +#define DW_DMA_QUIRK_XBAR_PRESENT BIT(0) + unsigned int quirks; }; #endif /* _PLATFORM_DATA_DMA_DW_H */ From 53b50458110d829c8fc45e7803a335a515698fd8 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Thu, 8 Jul 2021 07:08:26 +0200 Subject: [PATCH 005/696] dmaengine: idxd: Simplify code and axe the use of a deprecated API The wrappers in include/linux/pci-dma-compat.h should go away. Replace 'pci_set_dma_mask/pci_set_consistent_dma_mask' by an equivalent and less verbose 'dma_set_mask_and_coherent()' call. Even if the code may look different, it should have exactly the same run-time behavior. If pci_set_dma_mask(64) fails and pci_set_dma_mask(32) succeeds, then pci_set_consistent_dma_mask(64) will also fail. Signed-off-by: Christophe JAILLET Acked-by: Dave Jiang Link: https://lore.kernel.org/r/70c8a3bc67e41c5fefb526ecd64c5174c1e2dc76.1625720835.git.christophe.jaillet@wanadoo.fr Signed-off-by: Vinod Koul --- drivers/dma/idxd/init.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c index c8ae41d36040..de300ba38b14 100644 --- a/drivers/dma/idxd/init.c +++ b/drivers/dma/idxd/init.c @@ -637,15 +637,9 @@ static int idxd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) } dev_dbg(dev, "Set DMA masks\n"); - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); + rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); if (rc) - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (rc) - goto err; - - rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); - if (rc) - rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); if (rc) goto err; From 0dcfe41e9a4ca759ccc87a48e3bb9cc3b08ff1e8 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Fri, 4 Jun 2021 17:06:21 -0700 Subject: [PATCH 006/696] dmanegine: idxd: cleanup all device related bits after disabling device The previous state cleanup patch only performed wq state cleanups. This does not go far enough as when device is disabled or reset, the state for groups and engines must also be cleaned up. Add additional state cleanup beyond wq cleanup. Tie those cleanups directly to device disable and reset, and wq disable and reset. Fixes: da32b28c95a7 ("dmaengine: idxd: cleanup workqueue config after disabling") Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/162285154108.2096632.5572805472362321307.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/device.c | 88 +++++++++++++++++++++++++++++---------- drivers/dma/idxd/idxd.h | 6 +-- drivers/dma/idxd/irq.c | 4 +- drivers/dma/idxd/sysfs.c | 22 +++------- 4 files changed, 74 insertions(+), 46 deletions(-) diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c index 420b93fe5feb..928c2c8817f0 100644 --- a/drivers/dma/idxd/device.c +++ b/drivers/dma/idxd/device.c @@ -15,6 +15,8 @@ static void idxd_cmd_exec(struct idxd_device *idxd, int cmd_code, u32 operand, u32 *status); +static void idxd_device_wqs_clear_state(struct idxd_device *idxd); +static void idxd_wq_disable_cleanup(struct idxd_wq *wq); /* Interrupt control bits */ void idxd_mask_msix_vector(struct idxd_device *idxd, int vec_id) @@ -234,7 +236,7 @@ int idxd_wq_enable(struct idxd_wq *wq) return 0; } -int idxd_wq_disable(struct idxd_wq *wq) +int idxd_wq_disable(struct idxd_wq *wq, bool reset_config) { struct idxd_device *idxd = wq->idxd; struct device *dev = &idxd->pdev->dev; @@ -255,6 +257,8 @@ int idxd_wq_disable(struct idxd_wq *wq) return -ENXIO; } + if (reset_config) + idxd_wq_disable_cleanup(wq); wq->state = IDXD_WQ_DISABLED; dev_dbg(dev, "WQ %d disabled\n", wq->id); return 0; @@ -289,6 +293,7 @@ void idxd_wq_reset(struct idxd_wq *wq) operand = BIT(wq->id % 16) | ((wq->id / 16) << 16); idxd_cmd_exec(idxd, IDXD_CMD_RESET_WQ, operand, NULL); + idxd_wq_disable_cleanup(wq); wq->state = IDXD_WQ_DISABLED; } @@ -337,7 +342,7 @@ int idxd_wq_set_pasid(struct idxd_wq *wq, int pasid) unsigned int offset; unsigned long flags; - rc = idxd_wq_disable(wq); + rc = idxd_wq_disable(wq, false); if (rc < 0) return rc; @@ -364,7 +369,7 @@ int idxd_wq_disable_pasid(struct idxd_wq *wq) unsigned int offset; unsigned long flags; - rc = idxd_wq_disable(wq); + rc = idxd_wq_disable(wq, false); if (rc < 0) return rc; @@ -383,11 +388,11 @@ int idxd_wq_disable_pasid(struct idxd_wq *wq) return 0; } -void idxd_wq_disable_cleanup(struct idxd_wq *wq) +static void idxd_wq_disable_cleanup(struct idxd_wq *wq) { struct idxd_device *idxd = wq->idxd; - lockdep_assert_held(&idxd->dev_lock); + lockdep_assert_held(&wq->wq_lock); memset(wq->wqcfg, 0, idxd->wqcfg_size); wq->type = IDXD_WQT_NONE; wq->size = 0; @@ -548,22 +553,6 @@ int idxd_device_enable(struct idxd_device *idxd) return 0; } -void idxd_device_wqs_clear_state(struct idxd_device *idxd) -{ - int i; - - lockdep_assert_held(&idxd->dev_lock); - - for (i = 0; i < idxd->max_wqs; i++) { - struct idxd_wq *wq = idxd->wqs[i]; - - if (wq->state == IDXD_WQ_ENABLED) { - idxd_wq_disable_cleanup(wq); - wq->state = IDXD_WQ_DISABLED; - } - } -} - int idxd_device_disable(struct idxd_device *idxd) { struct device *dev = &idxd->pdev->dev; @@ -585,7 +574,7 @@ int idxd_device_disable(struct idxd_device *idxd) } spin_lock_irqsave(&idxd->dev_lock, flags); - idxd_device_wqs_clear_state(idxd); + idxd_device_clear_state(idxd); idxd->state = IDXD_DEV_CONF_READY; spin_unlock_irqrestore(&idxd->dev_lock, flags); return 0; @@ -597,7 +586,7 @@ void idxd_device_reset(struct idxd_device *idxd) idxd_cmd_exec(idxd, IDXD_CMD_RESET_DEVICE, 0, NULL); spin_lock_irqsave(&idxd->dev_lock, flags); - idxd_device_wqs_clear_state(idxd); + idxd_device_clear_state(idxd); idxd->state = IDXD_DEV_CONF_READY; spin_unlock_irqrestore(&idxd->dev_lock, flags); } @@ -685,6 +674,59 @@ int idxd_device_release_int_handle(struct idxd_device *idxd, int handle, } /* Device configuration bits */ +static void idxd_engines_clear_state(struct idxd_device *idxd) +{ + struct idxd_engine *engine; + int i; + + lockdep_assert_held(&idxd->dev_lock); + for (i = 0; i < idxd->max_engines; i++) { + engine = idxd->engines[i]; + engine->group = NULL; + } +} + +static void idxd_groups_clear_state(struct idxd_device *idxd) +{ + struct idxd_group *group; + int i; + + lockdep_assert_held(&idxd->dev_lock); + for (i = 0; i < idxd->max_groups; i++) { + group = idxd->groups[i]; + memset(&group->grpcfg, 0, sizeof(group->grpcfg)); + group->num_engines = 0; + group->num_wqs = 0; + group->use_token_limit = false; + group->tokens_allowed = 0; + group->tokens_reserved = 0; + group->tc_a = -1; + group->tc_b = -1; + } +} + +static void idxd_device_wqs_clear_state(struct idxd_device *idxd) +{ + int i; + + lockdep_assert_held(&idxd->dev_lock); + for (i = 0; i < idxd->max_wqs; i++) { + struct idxd_wq *wq = idxd->wqs[i]; + + if (wq->state == IDXD_WQ_ENABLED) { + idxd_wq_disable_cleanup(wq); + wq->state = IDXD_WQ_DISABLED; + } + } +} + +void idxd_device_clear_state(struct idxd_device *idxd) +{ + idxd_groups_clear_state(idxd); + idxd_engines_clear_state(idxd); + idxd_device_wqs_clear_state(idxd); +} + void idxd_msix_perm_setup(struct idxd_device *idxd) { union msix_perm mperm; diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h index 26482c7d4c3a..1f0991dec679 100644 --- a/drivers/dma/idxd/idxd.h +++ b/drivers/dma/idxd/idxd.h @@ -420,9 +420,8 @@ int idxd_device_init_reset(struct idxd_device *idxd); int idxd_device_enable(struct idxd_device *idxd); int idxd_device_disable(struct idxd_device *idxd); void idxd_device_reset(struct idxd_device *idxd); -void idxd_device_cleanup(struct idxd_device *idxd); +void idxd_device_clear_state(struct idxd_device *idxd); int idxd_device_config(struct idxd_device *idxd); -void idxd_device_wqs_clear_state(struct idxd_device *idxd); void idxd_device_drain_pasid(struct idxd_device *idxd, int pasid); int idxd_device_load_config(struct idxd_device *idxd); int idxd_device_request_int_handle(struct idxd_device *idxd, int idx, int *handle, @@ -435,12 +434,11 @@ void idxd_wqs_unmap_portal(struct idxd_device *idxd); int idxd_wq_alloc_resources(struct idxd_wq *wq); void idxd_wq_free_resources(struct idxd_wq *wq); int idxd_wq_enable(struct idxd_wq *wq); -int idxd_wq_disable(struct idxd_wq *wq); +int idxd_wq_disable(struct idxd_wq *wq, bool reset_config); void idxd_wq_drain(struct idxd_wq *wq); void idxd_wq_reset(struct idxd_wq *wq); int idxd_wq_map_portal(struct idxd_wq *wq); void idxd_wq_unmap_portal(struct idxd_wq *wq); -void idxd_wq_disable_cleanup(struct idxd_wq *wq); int idxd_wq_set_pasid(struct idxd_wq *wq, int pasid); int idxd_wq_disable_pasid(struct idxd_wq *wq); void idxd_wq_quiesce(struct idxd_wq *wq); diff --git a/drivers/dma/idxd/irq.c b/drivers/dma/idxd/irq.c index ae68e1e5487a..7a2cf0512501 100644 --- a/drivers/dma/idxd/irq.c +++ b/drivers/dma/idxd/irq.c @@ -59,7 +59,7 @@ static void idxd_device_reinit(struct work_struct *work) return; out: - idxd_device_wqs_clear_state(idxd); + idxd_device_clear_state(idxd); } static void idxd_device_fault_work(struct work_struct *work) @@ -192,7 +192,7 @@ static int process_misc_interrupts(struct idxd_device *idxd, u32 cause) spin_lock_bh(&idxd->dev_lock); idxd_wqs_quiesce(idxd); idxd_wqs_unmap_portal(idxd); - idxd_device_wqs_clear_state(idxd); + idxd_device_clear_state(idxd); dev_err(&idxd->pdev->dev, "idxd halted, need %s.\n", gensts.reset_type == IDXD_DEVICE_RESET_FLR ? diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c index 0460d58e3941..71cd73fefec6 100644 --- a/drivers/dma/idxd/sysfs.c +++ b/drivers/dma/idxd/sysfs.c @@ -129,7 +129,7 @@ static int enable_wq(struct idxd_wq *wq) rc = idxd_wq_map_portal(wq); if (rc < 0) { dev_warn(dev, "wq portal mapping failed: %d\n", rc); - rc = idxd_wq_disable(wq); + rc = idxd_wq_disable(wq, false); if (rc < 0) dev_warn(dev, "IDXD wq disable failed\n"); mutex_unlock(&wq->wq_lock); @@ -262,8 +262,6 @@ static void disable_wq(struct idxd_wq *wq) static int idxd_config_bus_remove(struct device *dev) { - int rc; - dev_dbg(dev, "%s called for %s\n", __func__, dev_name(dev)); /* disable workqueue here */ @@ -288,22 +286,12 @@ static int idxd_config_bus_remove(struct device *dev) } idxd_unregister_dma_device(idxd); - rc = idxd_device_disable(idxd); - if (test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags)) { - for (i = 0; i < idxd->max_wqs; i++) { - struct idxd_wq *wq = idxd->wqs[i]; - - mutex_lock(&wq->wq_lock); - idxd_wq_disable_cleanup(wq); - mutex_unlock(&wq->wq_lock); - } - } + idxd_device_disable(idxd); + if (test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags)) + idxd_device_reset(idxd); module_put(THIS_MODULE); - if (rc < 0) - dev_warn(dev, "Device disable failed\n"); - else - dev_info(dev, "Device %s disabled\n", dev_name(dev)); + dev_info(dev, "Device %s disabled\n", dev_name(dev)); } return 0; From e753a64bee753136087dfd70b37fdd199e942ea9 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Thu, 3 Jun 2021 14:57:35 -0700 Subject: [PATCH 007/696] dmaengine: idxd: Add wq occupancy information to sysfs attribute Add occupancy information to wq sysfs attribute. Attribute will show wq occupancy data if "WQ Occupancy Support" field in WQCAP is 1. It displays the number of entries currently in this WQ. This is provided as an estimate and should not be relied on to determine whether there is space in the WQ. The data is to provide information to user apps for flow control. Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/162275745546.1857062.8765615879420582018.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul --- .../ABI/stable/sysfs-driver-dma-idxd | 7 +++++++ drivers/dma/idxd/registers.h | 3 +++ drivers/dma/idxd/sysfs.c | 19 +++++++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/Documentation/ABI/stable/sysfs-driver-dma-idxd b/Documentation/ABI/stable/sysfs-driver-dma-idxd index d431e2d00472..adb0c93e8dfc 100644 --- a/Documentation/ABI/stable/sysfs-driver-dma-idxd +++ b/Documentation/ABI/stable/sysfs-driver-dma-idxd @@ -211,6 +211,13 @@ Contact: dmaengine@vger.kernel.org Description: Indicate whether ATS disable is turned on for the workqueue. 0 indicates ATS is on, and 1 indicates ATS is off for the workqueue. +What: /sys/bus/dsa/devices/wq./occupancy +Date May 25, 2021 +KernelVersion: 5.14.0 +Contact: dmaengine@vger.kernel.org +Description: Show the current number of entries in this WQ if WQ Occupancy + Support bit WQ capabilities is 1. + What: /sys/bus/dsa/devices/engine./group_id Date: Oct 25, 2019 KernelVersion: 5.6.0 diff --git a/drivers/dma/idxd/registers.h b/drivers/dma/idxd/registers.h index c970c3f025f0..7343a8f48819 100644 --- a/drivers/dma/idxd/registers.h +++ b/drivers/dma/idxd/registers.h @@ -349,6 +349,9 @@ union wqcfg { } __packed; #define WQCFG_PASID_IDX 2 +#define WQCFG_OCCUP_IDX 6 + +#define WQCFG_OCCUP_MASK 0xffff /* * This macro calculates the offset into the WQCFG register diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c index 71cd73fefec6..a193de32536d 100644 --- a/drivers/dma/idxd/sysfs.c +++ b/drivers/dma/idxd/sysfs.c @@ -1246,6 +1246,24 @@ static ssize_t wq_ats_disable_store(struct device *dev, struct device_attribute static struct device_attribute dev_attr_wq_ats_disable = __ATTR(ats_disable, 0644, wq_ats_disable_show, wq_ats_disable_store); +static ssize_t wq_occupancy_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct idxd_wq *wq = confdev_to_wq(dev); + struct idxd_device *idxd = wq->idxd; + u32 occup, offset; + + if (!idxd->hw.wq_cap.occupancy) + return -EOPNOTSUPP; + + offset = WQCFG_OFFSET(idxd, wq->id, WQCFG_OCCUP_IDX); + occup = ioread32(idxd->reg_base + offset) & WQCFG_OCCUP_MASK; + + return sysfs_emit(buf, "%u\n", occup); +} + +static struct device_attribute dev_attr_wq_occupancy = + __ATTR(occupancy, 0444, wq_occupancy_show, NULL); + static struct attribute *idxd_wq_attributes[] = { &dev_attr_wq_clients.attr, &dev_attr_wq_state.attr, @@ -1261,6 +1279,7 @@ static struct attribute *idxd_wq_attributes[] = { &dev_attr_wq_max_transfer_size.attr, &dev_attr_wq_max_batch_size.attr, &dev_attr_wq_ats_disable.attr, + &dev_attr_wq_occupancy.attr, NULL, }; From 53499d1fc11267e078557fc68ce943c1eb3b7a37 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Thu, 3 Jun 2021 11:01:37 -0700 Subject: [PATCH 008/696] dmaengine: idxd: have command status always set The cached command status is only set when the write back status is is passed in. Move the variable set outside of the check so it is always set. Fixes: 0d5c10b4c84d ("dmaengine: idxd: add work queue drain support") Reported-by: Ramesh Thomas Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/162274329740.1822314.3443875665504707588.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/device.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c index 928c2c8817f0..c8cf1de72176 100644 --- a/drivers/dma/idxd/device.c +++ b/drivers/dma/idxd/device.c @@ -486,6 +486,7 @@ static void idxd_cmd_exec(struct idxd_device *idxd, int cmd_code, u32 operand, union idxd_command_reg cmd; DECLARE_COMPLETION_ONSTACK(done); unsigned long flags; + u32 stat; if (idxd_device_is_halted(idxd)) { dev_warn(&idxd->pdev->dev, "Device is HALTED!\n"); @@ -518,11 +519,11 @@ static void idxd_cmd_exec(struct idxd_device *idxd, int cmd_code, u32 operand, */ spin_unlock_irqrestore(&idxd->cmd_lock, flags); wait_for_completion(&done); + stat = ioread32(idxd->reg_base + IDXD_CMDSTS_OFFSET); spin_lock_irqsave(&idxd->cmd_lock, flags); - if (status) { - *status = ioread32(idxd->reg_base + IDXD_CMDSTS_OFFSET); - idxd->cmd_status = *status & GENMASK(7, 0); - } + if (status) + *status = stat; + idxd->cmd_status = stat & GENMASK(7, 0); __clear_bit(IDXD_FLAG_CMD_RUNNING, &idxd->flags); /* Wake up other pending commands */ From ac24a2dc06cd773895d2fba0378c2538b8176565 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Thu, 24 Jun 2021 12:08:21 -0700 Subject: [PATCH 009/696] dmaengine: idxd: add missing percpu ref put on failure When enqcmds() fails, exit path is missing a percpu_ref_put(). This can cause failure on shutdown path when the driver is attempting to quiesce the wq. Add missing percpu_ref_put() call on the error exit path. Fixes: 93a40a6d7428 ("dmaengine: idxd: add percpu_ref to descriptor submission path") Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/162456170168.1121236.7240941044089212312.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/submit.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/dma/idxd/submit.c b/drivers/dma/idxd/submit.c index 19afb62abaff..b0f1ddf75d31 100644 --- a/drivers/dma/idxd/submit.c +++ b/drivers/dma/idxd/submit.c @@ -118,8 +118,10 @@ int idxd_submit_desc(struct idxd_wq *wq, struct idxd_desc *desc) * device is not accepting descriptor at all. */ rc = enqcmds(portal, desc->hw); - if (rc < 0) + if (rc < 0) { + percpu_ref_put(&wq->wq_active); return rc; + } } percpu_ref_put(&wq->wq_active); From 6cfd9e62e3297993f9f9d2d15f3acb14a0e8abbf Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Thu, 24 Jun 2021 13:39:33 -0700 Subject: [PATCH 010/696] dmaengine: idxd: assign MSIX vectors to each WQ rather than roundrobin IOPS increased when changing MSIX vector to per WQ from roundrobin. Allows descriptor to be completed by the submitter improves caching locality. Suggested-by: Konstantin Ananyev Signed-off-by: Dave Jiang Acked-by: Konstantin Ananyev Link: https://lore.kernel.org/r/162456717326.1130457.15258077196523268356.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/idxd.h | 2 -- drivers/dma/idxd/submit.c | 36 ++++++++---------------------------- 2 files changed, 8 insertions(+), 30 deletions(-) diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h index 1f0991dec679..edfa81f0fe18 100644 --- a/drivers/dma/idxd/idxd.h +++ b/drivers/dma/idxd/idxd.h @@ -153,7 +153,6 @@ struct idxd_wq { enum idxd_wq_state state; unsigned long flags; union wqcfg *wqcfg; - u32 vec_ptr; /* interrupt steering */ struct dsa_hw_desc **hw_descs; int num_descs; union { @@ -290,7 +289,6 @@ struct idxd_desc { struct list_head list; int id; int cpu; - unsigned int vector; struct idxd_wq *wq; }; diff --git a/drivers/dma/idxd/submit.c b/drivers/dma/idxd/submit.c index b0f1ddf75d31..425eeea9577b 100644 --- a/drivers/dma/idxd/submit.c +++ b/drivers/dma/idxd/submit.c @@ -22,22 +22,13 @@ static struct idxd_desc *__get_desc(struct idxd_wq *wq, int idx, int cpu) desc->hw->pasid = idxd->pasid; /* - * Descriptor completion vectors are 1...N for MSIX. We will round - * robin through the N vectors. + * On host, MSIX vecotr 0 is used for misc interrupt. Therefore when we match + * vector 1:1 to the WQ id, we need to add 1 */ - wq->vec_ptr = (wq->vec_ptr % idxd->num_wq_irqs) + 1; - if (!idxd->int_handles) { - desc->hw->int_handle = wq->vec_ptr; - } else { - desc->vector = wq->vec_ptr; - /* - * int_handles are only for descriptor completion. However for device - * MSIX enumeration, vec 0 is used for misc interrupts. Therefore even - * though we are rotating through 1...N for descriptor interrupts, we - * need to acqurie the int_handles from 0..N-1. - */ - desc->hw->int_handle = idxd->int_handles[desc->vector - 1]; - } + if (!idxd->int_handles) + desc->hw->int_handle = wq->id + 1; + else + desc->hw->int_handle = idxd->int_handles[wq->id]; return desc; } @@ -130,19 +121,8 @@ int idxd_submit_desc(struct idxd_wq *wq, struct idxd_desc *desc) * Pending the descriptor to the lockless list for the irq_entry * that we designated the descriptor to. */ - if (desc->hw->flags & IDXD_OP_FLAG_RCI) { - int vec; - - /* - * If the driver is on host kernel, it would be the value - * assigned to interrupt handle, which is index for MSIX - * vector. If it's guest then can't use the int_handle since - * that is the index to IMS for the entire device. The guest - * device local index will be used. - */ - vec = !idxd->int_handles ? desc->hw->int_handle : desc->vector; - llist_add(&desc->llnode, &idxd->irq_entries[vec].pending_llist); - } + if (desc->hw->flags & IDXD_OP_FLAG_RCI) + llist_add(&desc->llnode, &idxd->irq_entries[wq->id + 1].pending_llist); return 0; } From b2296eeac91555bd13f774efa7ab7d4b12fb71ef Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 25 Jun 2021 10:38:10 +0200 Subject: [PATCH 011/696] dmaengine: idxd: depends on !UML Now that UML has PCI support, this driver must depend also on !UML since it pokes at X86_64 architecture internals that don't exist on ARCH=um. Reported-by: kernel test robot Signed-off-by: Johannes Berg Acked-by: Dave Jiang Acked-By: Anton Ivanov Link: https://lore.kernel.org/r/20210625103810.fe877ae0aef4.If240438e3f50ae226f3f755fc46ea498c6858393@changeid Signed-off-by: Vinod Koul --- drivers/dma/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 39b5b46e880f..f450e4231db7 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -279,7 +279,7 @@ config INTEL_IDMA64 config INTEL_IDXD tristate "Intel Data Accelerators support" - depends on PCI && X86_64 + depends on PCI && X86_64 && !UML depends on PCI_MSI depends on SBITMAP select DMA_ENGINE From 4faee8b65ec32346f8096e64c5fa1d5a73121742 Mon Sep 17 00:00:00 2001 From: Zou Wei Date: Tue, 4 May 2021 10:22:57 +0800 Subject: [PATCH 012/696] dmaengine: sprd: Add missing MODULE_DEVICE_TABLE This patch adds missing MODULE_DEVICE_TABLE definition which generates correct modalias for automatic loading of this driver when it is built as an external module. Reported-by: Hulk Robot Signed-off-by: Zou Wei Reviewed-by: Baolin Wang Link: https://lore.kernel.org/r/1620094977-70146-1-git-send-email-zou_wei@huawei.com Signed-off-by: Vinod Koul --- drivers/dma/sprd-dma.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/dma/sprd-dma.c b/drivers/dma/sprd-dma.c index 0ef5ca81ba4d..4357d2395e6b 100644 --- a/drivers/dma/sprd-dma.c +++ b/drivers/dma/sprd-dma.c @@ -1265,6 +1265,7 @@ static const struct of_device_id sprd_dma_match[] = { { .compatible = "sprd,sc9860-dma", }, {}, }; +MODULE_DEVICE_TABLE(of, sprd_dma_match); static int __maybe_unused sprd_dma_runtime_suspend(struct device *dev) { From 7ed012969bbcdbd7aef5778a061681e6cbc4b402 Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Wed, 14 Jul 2021 17:01:59 +0200 Subject: [PATCH 013/696] Compiler Attributes: fix __has_attribute(__no_sanitize_coverage__) for GCC 4 Fix __has_attribute(__no_sanitize_coverage__) for GCC 4 by defining __GCC4_has_attribute___no_sanitize_coverage__. Fixes: 540540d06e9d ("kcov: add __no_sanitize_coverage to fix noinstr for all architectures") Reported-by: Geert Uytterhoeven Signed-off-by: Marco Elver Signed-off-by: Miguel Ojeda --- include/linux/compiler_attributes.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/compiler_attributes.h b/include/linux/compiler_attributes.h index 183ddd5fd072..7b1fa5c30169 100644 --- a/include/linux/compiler_attributes.h +++ b/include/linux/compiler_attributes.h @@ -36,6 +36,7 @@ # define __GCC4_has_attribute___nonstring__ 0 # define __GCC4_has_attribute___no_sanitize_address__ (__GNUC_MINOR__ >= 8) # define __GCC4_has_attribute___no_sanitize_undefined__ (__GNUC_MINOR__ >= 9) +# define __GCC4_has_attribute___no_sanitize_coverage__ 0 # define __GCC4_has_attribute___fallthrough__ 0 #endif From 333ff32d54cdefc2e479892e7f15ac91e026b57d Mon Sep 17 00:00:00 2001 From: Lars Poeschel Date: Wed, 14 Jul 2021 13:02:28 +0200 Subject: [PATCH 014/696] auxdisplay: hd44780: Fix oops on module unloading Fixes: 718e05ed92ec ("auxdisplay: Introduce hd44780_common.[ch]") Cc: stable@vger.kernel.org Link: https://lore.kernel.org/lkml/CAHp75VfKyqy+vM0XkP9Yb+znGOTVT4zYCRY3A3nQ7C3WNUVN0g@mail.gmail.com/ Reported-By: Andy Shevchenko Signed-off-by: Lars Poeschel Tested-by: Andy Shevchenko [added Link, Fixes, Cc stable tags, edited message] Signed-off-by: Miguel Ojeda --- drivers/auxdisplay/hd44780.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/auxdisplay/hd44780.c b/drivers/auxdisplay/hd44780.c index 2e5e7c993933..8b2a0eb3f32a 100644 --- a/drivers/auxdisplay/hd44780.c +++ b/drivers/auxdisplay/hd44780.c @@ -323,8 +323,8 @@ static int hd44780_remove(struct platform_device *pdev) { struct charlcd *lcd = platform_get_drvdata(pdev); - kfree(lcd->drvdata); charlcd_unregister(lcd); + kfree(lcd->drvdata); kfree(lcd); return 0; From ac8c8fa0a8c3a7bc0a9a9cc44ab3650d98662754 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 15 Jul 2021 17:41:52 +0300 Subject: [PATCH 015/696] auxdisplay: charlcd: Drop unneeded initializers and switch to C99 style For structure initializers the fields are 0 (or NULL) by default, so there is no need to fill them explicitly. Besides that, much easier to read when initializers use C99 style. Hence, convert to C99 style as well. Signed-off-by: Andy Shevchenko Acked-by: Willy Tarreau Signed-off-by: Miguel Ojeda --- drivers/auxdisplay/charlcd.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/auxdisplay/charlcd.c b/drivers/auxdisplay/charlcd.c index 24fd6f369ebe..304accde365c 100644 --- a/drivers/auxdisplay/charlcd.c +++ b/drivers/auxdisplay/charlcd.c @@ -637,9 +637,7 @@ static int panel_notify_sys(struct notifier_block *this, unsigned long code, } static struct notifier_block panel_notifier = { - panel_notify_sys, - NULL, - 0 + .notifier_call = panel_notify_sys, }; int charlcd_register(struct charlcd *lcd) From f885afe28d20b66341a8f55b10367312c1d6b686 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 16 Jun 2021 17:15:48 +0300 Subject: [PATCH 016/696] auxdisplay: ks0108: Switch to use module_parport_driver() Switch to use module_parport_driver() to reduce boilerplate code. Signed-off-by: Andy Shevchenko Signed-off-by: Miguel Ojeda --- drivers/auxdisplay/ks0108.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/drivers/auxdisplay/ks0108.c b/drivers/auxdisplay/ks0108.c index 03c95ad4216c..da9abfbb6d33 100644 --- a/drivers/auxdisplay/ks0108.c +++ b/drivers/auxdisplay/ks0108.c @@ -167,19 +167,7 @@ static struct parport_driver ks0108_parport_driver = { .detach = ks0108_parport_detach, .devmodel = true, }; - -static int __init ks0108_init(void) -{ - return parport_register_driver(&ks0108_parport_driver); -} - -static void __exit ks0108_exit(void) -{ - parport_unregister_driver(&ks0108_parport_driver); -} - -module_init(ks0108_init); -module_exit(ks0108_exit); +module_parport_driver(ks0108_parport_driver); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Miguel Ojeda "); From 24ebc044c72ee6e88dc902a0041bac672f012537 Mon Sep 17 00:00:00 2001 From: Jinchao Wang Date: Sat, 26 Jun 2021 18:15:38 +0800 Subject: [PATCH 017/696] auxdisplay: Replace symbolic permissions with octal permissions Resolves the checkpatch warning. Signed-off-by: Jinchao Wang [edited wording] Signed-off-by: Miguel Ojeda --- drivers/auxdisplay/cfag12864b.c | 2 +- drivers/auxdisplay/ks0108.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/auxdisplay/cfag12864b.c b/drivers/auxdisplay/cfag12864b.c index fd430e6866a1..6526aa51fb1d 100644 --- a/drivers/auxdisplay/cfag12864b.c +++ b/drivers/auxdisplay/cfag12864b.c @@ -33,7 +33,7 @@ */ static unsigned int cfag12864b_rate = CONFIG_CFAG12864B_RATE; -module_param(cfag12864b_rate, uint, S_IRUGO); +module_param(cfag12864b_rate, uint, 0444); MODULE_PARM_DESC(cfag12864b_rate, "Refresh rate (hertz)"); diff --git a/drivers/auxdisplay/ks0108.c b/drivers/auxdisplay/ks0108.c index da9abfbb6d33..e871b94a1911 100644 --- a/drivers/auxdisplay/ks0108.c +++ b/drivers/auxdisplay/ks0108.c @@ -28,11 +28,11 @@ */ static unsigned int ks0108_port = CONFIG_KS0108_PORT; -module_param(ks0108_port, uint, S_IRUGO); +module_param(ks0108_port, uint, 0444); MODULE_PARM_DESC(ks0108_port, "Parallel port where the LCD is connected"); static unsigned int ks0108_delay = CONFIG_KS0108_DELAY; -module_param(ks0108_delay, uint, S_IRUGO); +module_param(ks0108_delay, uint, 0444); MODULE_PARM_DESC(ks0108_delay, "Delay between each control writing (microseconds)"); /* From 4c5afb74d9450edc2e2e37243b469cc278b120d4 Mon Sep 17 00:00:00 2001 From: Reiner Huober Date: Tue, 6 Jul 2021 15:02:52 +0200 Subject: [PATCH 018/696] module: combine constructors in module linker script The constructor code for modules must be aware of init code inside different sections. Newer GCC compilers write constructors in more than one section, e.g. ".ctors.65435". These must be combined into a single ".ctors" section. In the module loader, only the ".ctors" section is searched and the constructors therein are initialized, when CONFIG_CONSTRUCTORS=y is set. Other constructors are ignored. This change combines all ".ctors.*" and the ".ctors" section, if any, in .ko into a single ."ctors" section. For code coverage in GCC, this is necessary to show the code coverage for modules, since code coverage uses such constructors when initializing a module in newer version of GCC. Signed-off-by: Reiner Huober Signed-off-by: Jessica Yu --- scripts/module.lds.S | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/module.lds.S b/scripts/module.lds.S index 04c5685c25cf..1d0e1e4dc3d2 100644 --- a/scripts/module.lds.S +++ b/scripts/module.lds.S @@ -24,6 +24,7 @@ SECTIONS { __kcrctab 0 : { *(SORT(___kcrctab+*)) } __kcrctab_gpl 0 : { *(SORT(___kcrctab_gpl+*)) } + .ctors 0 : ALIGN(8) { *(SORT(.ctors.*)) *(.ctors) } .init_array 0 : ALIGN(8) { *(SORT(.init_array.*)) *(.init_array) } __jump_table 0 : ALIGN(8) { KEEP(*(__jump_table)) } From 9aa75914e5fcb39e79fc6de9e44cd12943732c38 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 14 Jul 2021 12:11:02 -0700 Subject: [PATCH 019/696] Input: ixp4xx-beeper - delete driver The NSLU2 has been migrated to devicetree and there we use the gpio-beeper.c driver instead, the boardfile will be deleted for kernel v5.15 so drop this custom and now unneeded driver. Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20210714115028.916360-1-linus.walleij@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/misc/Kconfig | 12 -- drivers/input/misc/Makefile | 1 - drivers/input/misc/ixp4xx-beeper.c | 183 ----------------------------- 3 files changed, 196 deletions(-) delete mode 100644 drivers/input/misc/ixp4xx-beeper.c diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 498cde376981..ae01507b7afd 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -309,18 +309,6 @@ config INPUT_GPIO_VIBRA To compile this driver as a module, choose M here: the module will be called gpio-vibra. -config INPUT_IXP4XX_BEEPER - tristate "IXP4XX Beeper support" - depends on ARCH_IXP4XX - help - If you say yes here, you can connect a beeper to the - ixp4xx gpio pins. This is used by the LinkSys NSLU2. - - If unsure, say Y. - - To compile this driver as a module, choose M here: the - module will be called ixp4xx-beeper. - config INPUT_COBALT_BTNS tristate "Cobalt button interface" depends on MIPS_COBALT diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index f593beed7e05..2a0943507467 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -44,7 +44,6 @@ obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o obj-$(CONFIG_INPUT_IMS_PCU) += ims-pcu.o obj-$(CONFIG_INPUT_IQS269A) += iqs269a.o obj-$(CONFIG_INPUT_IQS626A) += iqs626a.o -obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o obj-$(CONFIG_INPUT_KXTJ9) += kxtj9.o obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o diff --git a/drivers/input/misc/ixp4xx-beeper.c b/drivers/input/misc/ixp4xx-beeper.c deleted file mode 100644 index 05018d0c97c7..000000000000 --- a/drivers/input/misc/ixp4xx-beeper.c +++ /dev/null @@ -1,183 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Generic IXP4xx beeper driver - * - * Copyright (C) 2005 Tower Technologies - * - * based on nslu2-io.c - * Copyright (C) 2004 Karen Spearel - * - * Author: Alessandro Zummo - * Maintainers: http://www.nslu2-linux.org/ - */ - -#include -#include -#include -#include -#include -#include -#include - -MODULE_AUTHOR("Alessandro Zummo "); -MODULE_DESCRIPTION("ixp4xx beeper driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:ixp4xx-beeper"); - -static DEFINE_SPINLOCK(beep_lock); - -static int ixp4xx_timer2_irq; - -static void ixp4xx_spkr_control(unsigned int pin, unsigned int count) -{ - unsigned long flags; - - spin_lock_irqsave(&beep_lock, flags); - - if (count) { - gpio_direction_output(pin, 0); - *IXP4XX_OSRT2 = (count & ~IXP4XX_OST_RELOAD_MASK) | IXP4XX_OST_ENABLE; - } else { - gpio_direction_output(pin, 1); - gpio_direction_input(pin); - *IXP4XX_OSRT2 = 0; - } - - spin_unlock_irqrestore(&beep_lock, flags); -} - -static int ixp4xx_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) -{ - unsigned int pin = (unsigned int) input_get_drvdata(dev); - unsigned int count = 0; - - if (type != EV_SND) - return -1; - - switch (code) { - case SND_BELL: - if (value) - value = 1000; - case SND_TONE: - break; - default: - return -1; - } - - if (value > 20 && value < 32767) - count = (ixp4xx_timer_freq / (value * 4)) - 1; - - ixp4xx_spkr_control(pin, count); - - return 0; -} - -static irqreturn_t ixp4xx_spkr_interrupt(int irq, void *dev_id) -{ - unsigned int pin = (unsigned int) dev_id; - - /* clear interrupt */ - *IXP4XX_OSST = IXP4XX_OSST_TIMER_2_PEND; - - /* flip the beeper output */ - gpio_set_value(pin, !gpio_get_value(pin)); - - return IRQ_HANDLED; -} - -static int ixp4xx_spkr_probe(struct platform_device *dev) -{ - struct input_dev *input_dev; - int irq; - int err; - - input_dev = input_allocate_device(); - if (!input_dev) - return -ENOMEM; - - input_set_drvdata(input_dev, (void *) dev->id); - - input_dev->name = "ixp4xx beeper"; - input_dev->phys = "ixp4xx/gpio"; - input_dev->id.bustype = BUS_HOST; - input_dev->id.vendor = 0x001f; - input_dev->id.product = 0x0001; - input_dev->id.version = 0x0100; - input_dev->dev.parent = &dev->dev; - - input_dev->evbit[0] = BIT_MASK(EV_SND); - input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE); - input_dev->event = ixp4xx_spkr_event; - - irq = platform_get_irq(dev, 0); - if (irq < 0) { - err = irq; - goto err_free_device; - } - - err = gpio_request(dev->id, "ixp4-beeper"); - if (err) - goto err_free_device; - - err = request_irq(irq, &ixp4xx_spkr_interrupt, - IRQF_NO_SUSPEND, "ixp4xx-beeper", - (void *) dev->id); - if (err) - goto err_free_gpio; - ixp4xx_timer2_irq = irq; - - err = input_register_device(input_dev); - if (err) - goto err_free_irq; - - platform_set_drvdata(dev, input_dev); - - return 0; - - err_free_irq: - free_irq(irq, (void *)dev->id); - err_free_gpio: - gpio_free(dev->id); - err_free_device: - input_free_device(input_dev); - - return err; -} - -static int ixp4xx_spkr_remove(struct platform_device *dev) -{ - struct input_dev *input_dev = platform_get_drvdata(dev); - unsigned int pin = (unsigned int) input_get_drvdata(input_dev); - - input_unregister_device(input_dev); - - /* turn the speaker off */ - disable_irq(ixp4xx_timer2_irq); - ixp4xx_spkr_control(pin, 0); - - free_irq(ixp4xx_timer2_irq, (void *)dev->id); - gpio_free(dev->id); - - return 0; -} - -static void ixp4xx_spkr_shutdown(struct platform_device *dev) -{ - struct input_dev *input_dev = platform_get_drvdata(dev); - unsigned int pin = (unsigned int) input_get_drvdata(input_dev); - - /* turn off the speaker */ - disable_irq(ixp4xx_timer2_irq); - ixp4xx_spkr_control(pin, 0); -} - -static struct platform_driver ixp4xx_spkr_platform_driver = { - .driver = { - .name = "ixp4xx-beeper", - }, - .probe = ixp4xx_spkr_probe, - .remove = ixp4xx_spkr_remove, - .shutdown = ixp4xx_spkr_shutdown, -}; -module_platform_driver(ixp4xx_spkr_platform_driver); - From 81c7c0a350bfe9306ad9fb10356534ede8f4ab31 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 19 Jul 2021 14:34:40 -0700 Subject: [PATCH 020/696] Input: serio - make write method mandatory Given that all serio drivers except one implement write() method let's make it mandatory to avoid testing for its presence whenever we attempt to use it. Link: https://lore.kernel.org/r/YFgUxG/TljMuVeQ3@google.com Signed-off-by: Dmitry Torokhov --- drivers/input/serio/ams_delta_serio.c | 6 ++++++ drivers/input/serio/serio.c | 5 +++++ include/linux/serio.h | 5 +---- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/input/serio/ams_delta_serio.c b/drivers/input/serio/ams_delta_serio.c index 1c0be299f179..a1c314897951 100644 --- a/drivers/input/serio/ams_delta_serio.c +++ b/drivers/input/serio/ams_delta_serio.c @@ -89,6 +89,11 @@ static irqreturn_t ams_delta_serio_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +static int ams_delta_serio_write(struct serio *serio, u8 data) +{ + return -EINVAL; +} + static int ams_delta_serio_open(struct serio *serio) { struct ams_delta_serio *priv = serio->port_data; @@ -157,6 +162,7 @@ static int ams_delta_serio_init(struct platform_device *pdev) priv->serio = serio; serio->id.type = SERIO_8042; + serio->write = ams_delta_serio_write; serio->open = ams_delta_serio_open; serio->close = ams_delta_serio_close; strlcpy(serio->name, "AMS DELTA keyboard adapter", sizeof(serio->name)); diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 29f491082926..8d229a11bb6b 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -694,6 +694,11 @@ EXPORT_SYMBOL(serio_reconnect); */ void __serio_register_port(struct serio *serio, struct module *owner) { + if (!serio->write) { + pr_err("%s: refusing to register %s without write method\n", + __func__, serio->name); + return; + } serio_init_port(serio); serio_queue_event(serio, owner, SERIO_REGISTER_PORT); } diff --git a/include/linux/serio.h b/include/linux/serio.h index 6c27d413da92..075f1b8d76fa 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -121,10 +121,7 @@ void serio_unregister_driver(struct serio_driver *drv); static inline int serio_write(struct serio *serio, unsigned char data) { - if (serio->write) - return serio->write(serio, data); - else - return -1; + return serio->write(serio, data); } static inline void serio_drv_write_wakeup(struct serio *serio) From 133b6558c75566bf692460fd1a09b3b795ef2c1a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 19 Jul 2021 14:56:57 -0700 Subject: [PATCH 021/696] Input: parkbd - switch to use module_parport_driver() Switch to use module_parport_driver() to reduce boilerplate code. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210616140432.39406-1-andriy.shevchenko@linux.intel.com Signed-off-by: Dmitry Torokhov --- drivers/input/serio/parkbd.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/drivers/input/serio/parkbd.c b/drivers/input/serio/parkbd.c index 3ac57a91ede4..51b68501896c 100644 --- a/drivers/input/serio/parkbd.c +++ b/drivers/input/serio/parkbd.c @@ -220,16 +220,4 @@ static struct parport_driver parkbd_parport_driver = { .detach = parkbd_detach, .devmodel = true, }; - -static int __init parkbd_init(void) -{ - return parport_register_driver(&parkbd_parport_driver); -} - -static void __exit parkbd_exit(void) -{ - parport_unregister_driver(&parkbd_parport_driver); -} - -module_init(parkbd_init); -module_exit(parkbd_exit); +module_parport_driver(parkbd_parport_driver); From 49c4959f04b587c8909b33adca4066995c768d60 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Wed, 14 Jul 2021 14:57:19 -0700 Subject: [PATCH 022/696] dmaengine: idxd: fix sequence for pci driver remove() and shutdown() ->shutdown() call should only be responsible for quiescing the device. Currently it is doing PCI device tear down. This causes issue when things like MMIO mapping is removed while idxd_unregister_devices() will trigger removal of idxd device sub-driver and still initiates MMIO writes to the device. Another issue is with the unregistering of idxd 'struct device', the memory context gets freed. So the teardown calls are accessing freed memory and can cause kernel oops. Move all the teardown bits that doesn't belong in shutdown to ->remove() call. Move unregistering of the idxd conf_dev 'struct device' to after doing all the teardown to free all the memory that's no longer needed. Fixes: 47c16ac27d4c ("dmaengine: idxd: fix idxd conf_dev 'struct device' lifetime") Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/162629983901.395844.17964803190905549615.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/init.c | 26 +++++++++++++++++--------- drivers/dma/idxd/sysfs.c | 2 -- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c index 7eac0d167bde..75ac6a4bc9d1 100644 --- a/drivers/dma/idxd/init.c +++ b/drivers/dma/idxd/init.c @@ -754,32 +754,40 @@ static void idxd_shutdown(struct pci_dev *pdev) for (i = 0; i < msixcnt; i++) { irq_entry = &idxd->irq_entries[i]; synchronize_irq(irq_entry->vector); - free_irq(irq_entry->vector, irq_entry); if (i == 0) continue; idxd_flush_pending_llist(irq_entry); idxd_flush_work_list(irq_entry); } - - idxd_msix_perm_clear(idxd); - idxd_release_int_handles(idxd); - pci_free_irq_vectors(pdev); - pci_iounmap(pdev, idxd->reg_base); - pci_disable_device(pdev); - destroy_workqueue(idxd->wq); + flush_workqueue(idxd->wq); } static void idxd_remove(struct pci_dev *pdev) { struct idxd_device *idxd = pci_get_drvdata(pdev); + struct idxd_irq_entry *irq_entry; + int msixcnt = pci_msix_vec_count(pdev); + int i; dev_dbg(&pdev->dev, "%s called\n", __func__); idxd_shutdown(pdev); if (device_pasid_enabled(idxd)) idxd_disable_system_pasid(idxd); idxd_unregister_devices(idxd); - perfmon_pmu_remove(idxd); + + for (i = 0; i < msixcnt; i++) { + irq_entry = &idxd->irq_entries[i]; + free_irq(irq_entry->vector, irq_entry); + } + idxd_msix_perm_clear(idxd); + idxd_release_int_handles(idxd); + pci_free_irq_vectors(pdev); + pci_iounmap(pdev, idxd->reg_base); iommu_dev_disable_feature(&pdev->dev, IOMMU_DEV_FEAT_SVA); + pci_disable_device(pdev); + destroy_workqueue(idxd->wq); + perfmon_pmu_remove(idxd); + device_unregister(&idxd->conf_dev); } static struct pci_driver idxd_pci_driver = { diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c index a193de32536d..33c27df40f1e 100644 --- a/drivers/dma/idxd/sysfs.c +++ b/drivers/dma/idxd/sysfs.c @@ -1751,8 +1751,6 @@ void idxd_unregister_devices(struct idxd_device *idxd) device_unregister(&group->conf_dev); } - - device_unregister(&idxd->conf_dev); } int idxd_register_bus_type(void) From 3ecfc9135e6c82183d121c5578ed5d6f07a53ec8 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Thu, 15 Jul 2021 11:43:09 -0700 Subject: [PATCH 023/696] dmaengine: idxd: add driver register helper Add helper functions for dsa-driver registration similar to other bus-types. In particular, do not require dsa-drivers to open-code the bus, owner, and mod_name fields. Let registration and unregistration operate on the 'struct idxd_device_driver' instead of the raw / embedded 'struct device_driver'. Reviewed-by: Dan Williams Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/162637458949.744545.14996726325385482050.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/idxd.h | 7 +++++++ drivers/dma/idxd/init.c | 17 +++++++++++++++++ drivers/dma/idxd/sysfs.c | 7 ++----- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h index d875b3d41ed2..8db19b899709 100644 --- a/drivers/dma/idxd/idxd.h +++ b/drivers/dma/idxd/idxd.h @@ -402,6 +402,13 @@ static inline int idxd_wq_refcount(struct idxd_wq *wq) return wq->client_count; }; +int __must_check __idxd_driver_register(struct idxd_device_driver *idxd_drv, + struct module *module, const char *mod_name); +#define idxd_driver_register(driver) \ + __idxd_driver_register(driver, THIS_MODULE, KBUILD_MODNAME) + +void idxd_driver_unregister(struct idxd_device_driver *idxd_drv); + int idxd_register_bus_type(void); void idxd_unregister_bus_type(void); int idxd_register_devices(struct idxd_device *idxd); diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c index 75ac6a4bc9d1..b15817751d5f 100644 --- a/drivers/dma/idxd/init.c +++ b/drivers/dma/idxd/init.c @@ -855,3 +855,20 @@ static void __exit idxd_exit_module(void) perfmon_exit(); } module_exit(idxd_exit_module); + +int __idxd_driver_register(struct idxd_device_driver *idxd_drv, struct module *owner, + const char *mod_name) +{ + struct device_driver *drv = &idxd_drv->drv; + + drv->bus = &dsa_bus_type; + drv->owner = owner; + drv->mod_name = mod_name; + + return driver_register(drv); +} + +void idxd_driver_unregister(struct idxd_device_driver *idxd_drv) +{ + driver_unregister(&idxd_drv->drv); +} diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c index 33c27df40f1e..bf229b12d527 100644 --- a/drivers/dma/idxd/sysfs.c +++ b/drivers/dma/idxd/sysfs.c @@ -313,21 +313,18 @@ struct bus_type dsa_bus_type = { static struct idxd_device_driver dsa_drv = { .drv = { .name = "dsa", - .bus = &dsa_bus_type, - .owner = THIS_MODULE, - .mod_name = KBUILD_MODNAME, }, }; /* IDXD generic driver setup */ int idxd_register_driver(void) { - return driver_register(&dsa_drv.drv); + return idxd_driver_register(&dsa_drv); } void idxd_unregister_driver(void) { - driver_unregister(&dsa_drv.drv); + idxd_driver_unregister(&dsa_drv); } /* IDXD engine attributes */ From da5a11d75d6837c9c5ef40810f66ce9d2db6ca5e Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Thu, 15 Jul 2021 11:43:15 -0700 Subject: [PATCH 024/696] dmaengine: idxd: add driver name Add name field in idxd_device_driver so we don't have to touch the 'struct device_driver' during declaration. Reviewed-by: Dan Williams Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/162637459517.744545.7572915135318813722.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/idxd.h | 1 + drivers/dma/idxd/init.c | 1 + drivers/dma/idxd/sysfs.c | 4 +--- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h index 8db19b899709..e8721ff028c2 100644 --- a/drivers/dma/idxd/idxd.h +++ b/drivers/dma/idxd/idxd.h @@ -34,6 +34,7 @@ enum idxd_type { #define IDXD_PMU_EVENT_MAX 64 struct idxd_device_driver { + const char *name; struct device_driver drv; }; diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c index b15817751d5f..6403d55c7ff7 100644 --- a/drivers/dma/idxd/init.c +++ b/drivers/dma/idxd/init.c @@ -861,6 +861,7 @@ int __idxd_driver_register(struct idxd_device_driver *idxd_drv, struct module *o { struct device_driver *drv = &idxd_drv->drv; + drv->name = idxd_drv->name; drv->bus = &dsa_bus_type; drv->owner = owner; drv->mod_name = mod_name; diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c index bf229b12d527..60779f57c118 100644 --- a/drivers/dma/idxd/sysfs.c +++ b/drivers/dma/idxd/sysfs.c @@ -311,9 +311,7 @@ struct bus_type dsa_bus_type = { }; static struct idxd_device_driver dsa_drv = { - .drv = { - .name = "dsa", - }, + .name = "dsa", }; /* IDXD generic driver setup */ From 700af3a0a26cbac87e4a0ae1dfa79597d0056d5f Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Thu, 15 Jul 2021 11:43:20 -0700 Subject: [PATCH 025/696] dmaengine: idxd: add 'struct idxd_dev' as wrapper for conf_dev Add a 'struct idxd_dev' that wraps the 'struct device' for idxd conf_dev that registers with the dsa bus. This is introduced in order to deal with multiple different types of 'devices' that are registered on the dsa_bus when the compat driver needs to route them to the correct driver to attach. The bind() call now can determine the type of device and then do the appropriate driver matching. Reviewed-by Dan Williams Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/162637460065.744545.584492831446090984.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/cdev.c | 11 +- drivers/dma/idxd/dma.c | 4 +- drivers/dma/idxd/idxd.h | 82 ++++++++++++-- drivers/dma/idxd/init.c | 98 +++++++++------- drivers/dma/idxd/irq.c | 2 +- drivers/dma/idxd/sysfs.c | 239 ++++++++++++++++++--------------------- 6 files changed, 251 insertions(+), 185 deletions(-) diff --git a/drivers/dma/idxd/cdev.c b/drivers/dma/idxd/cdev.c index e9def577c697..18a003b93812 100644 --- a/drivers/dma/idxd/cdev.c +++ b/drivers/dma/idxd/cdev.c @@ -41,7 +41,7 @@ struct idxd_user_context { static void idxd_cdev_dev_release(struct device *dev) { - struct idxd_cdev *idxd_cdev = container_of(dev, struct idxd_cdev, dev); + struct idxd_cdev *idxd_cdev = dev_to_cdev(dev); struct idxd_cdev_context *cdev_ctx; struct idxd_wq *wq = idxd_cdev->wq; @@ -256,9 +256,10 @@ int idxd_wq_add_cdev(struct idxd_wq *wq) if (!idxd_cdev) return -ENOMEM; + idxd_cdev->idxd_dev.type = IDXD_DEV_CDEV; idxd_cdev->wq = wq; cdev = &idxd_cdev->cdev; - dev = &idxd_cdev->dev; + dev = cdev_dev(idxd_cdev); cdev_ctx = &ictx[wq->idxd->data->type]; minor = ida_simple_get(&cdev_ctx->minor_ida, 0, MINORMASK, GFP_KERNEL); if (minor < 0) { @@ -268,7 +269,7 @@ int idxd_wq_add_cdev(struct idxd_wq *wq) idxd_cdev->minor = minor; device_initialize(dev); - dev->parent = &wq->conf_dev; + dev->parent = wq_confdev(wq); dev->bus = &dsa_bus_type; dev->type = &idxd_cdev_device_type; dev->devt = MKDEV(MAJOR(cdev_ctx->devt), minor); @@ -299,8 +300,8 @@ void idxd_wq_del_cdev(struct idxd_wq *wq) idxd_cdev = wq->idxd_cdev; wq->idxd_cdev = NULL; - cdev_device_del(&idxd_cdev->cdev, &idxd_cdev->dev); - put_device(&idxd_cdev->dev); + cdev_device_del(&idxd_cdev->cdev, cdev_dev(idxd_cdev)); + put_device(cdev_dev(idxd_cdev)); } int idxd_cdev_register(void) diff --git a/drivers/dma/idxd/dma.c b/drivers/dma/idxd/dma.c index 77439b645044..2e52f9a50519 100644 --- a/drivers/dma/idxd/dma.c +++ b/drivers/dma/idxd/dma.c @@ -245,7 +245,7 @@ int idxd_register_dma_channel(struct idxd_wq *wq) wq->idxd_chan = idxd_chan; idxd_chan->wq = wq; - get_device(&wq->conf_dev); + get_device(wq_confdev(wq)); return 0; } @@ -260,5 +260,5 @@ void idxd_unregister_dma_channel(struct idxd_wq *wq) list_del(&chan->device_node); kfree(wq->idxd_chan); wq->idxd_chan = NULL; - put_device(&wq->conf_dev); + put_device(wq_confdev(wq)); } diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h index e8721ff028c2..ae60fcc7b625 100644 --- a/drivers/dma/idxd/idxd.h +++ b/drivers/dma/idxd/idxd.h @@ -17,8 +17,24 @@ extern struct kmem_cache *idxd_desc_pool; -struct idxd_device; struct idxd_wq; +struct idxd_dev; + +enum idxd_dev_type { + IDXD_DEV_NONE = -1, + IDXD_DEV_DSA = 0, + IDXD_DEV_IAX, + IDXD_DEV_WQ, + IDXD_DEV_GROUP, + IDXD_DEV_ENGINE, + IDXD_DEV_CDEV, + IDXD_DEV_MAX_TYPE, +}; + +struct idxd_dev { + struct device conf_dev; + enum idxd_dev_type type; +}; #define IDXD_REG_TIMEOUT 50 #define IDXD_DRAIN_TIMEOUT 5000 @@ -52,7 +68,7 @@ struct idxd_irq_entry { }; struct idxd_group { - struct device conf_dev; + struct idxd_dev idxd_dev; struct idxd_device *idxd; struct grpcfg grpcfg; int id; @@ -111,7 +127,7 @@ enum idxd_wq_type { struct idxd_cdev { struct idxd_wq *wq; struct cdev cdev; - struct device dev; + struct idxd_dev idxd_dev; int minor; }; @@ -139,7 +155,7 @@ struct idxd_wq { void __iomem *portal; struct percpu_ref wq_active; struct completion wq_dead; - struct device conf_dev; + struct idxd_dev idxd_dev; struct idxd_cdev *idxd_cdev; struct wait_queue_head err_queue; struct idxd_device *idxd; @@ -174,7 +190,7 @@ struct idxd_wq { }; struct idxd_engine { - struct device conf_dev; + struct idxd_dev idxd_dev; int id; struct idxd_group *group; struct idxd_device *idxd; @@ -218,7 +234,7 @@ struct idxd_driver_data { }; struct idxd_device { - struct device conf_dev; + struct idxd_dev idxd_dev; struct idxd_driver_data *data; struct list_head list; struct idxd_hw hw; @@ -301,8 +317,58 @@ enum idxd_completion_status { IDXD_COMP_DESC_ABORT = 0xff, }; -#define confdev_to_idxd(dev) container_of(dev, struct idxd_device, conf_dev) -#define confdev_to_wq(dev) container_of(dev, struct idxd_wq, conf_dev) +#define idxd_confdev(idxd) &idxd->idxd_dev.conf_dev +#define wq_confdev(wq) &wq->idxd_dev.conf_dev +#define engine_confdev(engine) &engine->idxd_dev.conf_dev +#define group_confdev(group) &group->idxd_dev.conf_dev +#define cdev_dev(cdev) &cdev->idxd_dev.conf_dev + +#define confdev_to_idxd_dev(dev) container_of(dev, struct idxd_dev, conf_dev) + +static inline struct idxd_device *confdev_to_idxd(struct device *dev) +{ + struct idxd_dev *idxd_dev = confdev_to_idxd_dev(dev); + + return container_of(idxd_dev, struct idxd_device, idxd_dev); +} + +static inline struct idxd_wq *confdev_to_wq(struct device *dev) +{ + struct idxd_dev *idxd_dev = confdev_to_idxd_dev(dev); + + return container_of(idxd_dev, struct idxd_wq, idxd_dev); +} + +static inline struct idxd_engine *confdev_to_engine(struct device *dev) +{ + struct idxd_dev *idxd_dev = confdev_to_idxd_dev(dev); + + return container_of(idxd_dev, struct idxd_engine, idxd_dev); +} + +static inline struct idxd_group *confdev_to_group(struct device *dev) +{ + struct idxd_dev *idxd_dev = confdev_to_idxd_dev(dev); + + return container_of(idxd_dev, struct idxd_group, idxd_dev); +} + +static inline struct idxd_cdev *dev_to_cdev(struct device *dev) +{ + struct idxd_dev *idxd_dev = confdev_to_idxd_dev(dev); + + return container_of(idxd_dev, struct idxd_cdev, idxd_dev); +} + +static inline void idxd_dev_set_type(struct idxd_dev *idev, int type) +{ + if (type >= IDXD_DEV_MAX_TYPE) { + idev->type = IDXD_DEV_NONE; + return; + } + + idev->type = type; +} extern struct bus_type dsa_bus_type; extern struct bus_type iax_bus_type; diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c index 6403d55c7ff7..f500076882d2 100644 --- a/drivers/dma/idxd/init.c +++ b/drivers/dma/idxd/init.c @@ -200,6 +200,7 @@ static int idxd_setup_wqs(struct idxd_device *idxd) { struct device *dev = &idxd->pdev->dev; struct idxd_wq *wq; + struct device *conf_dev; int i, rc; idxd->wqs = kcalloc_node(idxd->max_wqs, sizeof(struct idxd_wq *), @@ -214,15 +215,17 @@ static int idxd_setup_wqs(struct idxd_device *idxd) goto err; } + idxd_dev_set_type(&wq->idxd_dev, IDXD_DEV_WQ); + conf_dev = wq_confdev(wq); wq->id = i; wq->idxd = idxd; - device_initialize(&wq->conf_dev); - wq->conf_dev.parent = &idxd->conf_dev; - wq->conf_dev.bus = &dsa_bus_type; - wq->conf_dev.type = &idxd_wq_device_type; - rc = dev_set_name(&wq->conf_dev, "wq%d.%d", idxd->id, wq->id); + device_initialize(wq_confdev(wq)); + conf_dev->parent = idxd_confdev(idxd); + conf_dev->bus = &dsa_bus_type; + conf_dev->type = &idxd_wq_device_type; + rc = dev_set_name(conf_dev, "wq%d.%d", idxd->id, wq->id); if (rc < 0) { - put_device(&wq->conf_dev); + put_device(conf_dev); goto err; } @@ -233,7 +236,7 @@ static int idxd_setup_wqs(struct idxd_device *idxd) wq->max_batch_size = idxd->max_batch_size; wq->wqcfg = kzalloc_node(idxd->wqcfg_size, GFP_KERNEL, dev_to_node(dev)); if (!wq->wqcfg) { - put_device(&wq->conf_dev); + put_device(conf_dev); rc = -ENOMEM; goto err; } @@ -243,8 +246,11 @@ static int idxd_setup_wqs(struct idxd_device *idxd) return 0; err: - while (--i >= 0) - put_device(&idxd->wqs[i]->conf_dev); + while (--i >= 0) { + wq = idxd->wqs[i]; + conf_dev = wq_confdev(wq); + put_device(conf_dev); + } return rc; } @@ -252,6 +258,7 @@ static int idxd_setup_engines(struct idxd_device *idxd) { struct idxd_engine *engine; struct device *dev = &idxd->pdev->dev; + struct device *conf_dev; int i, rc; idxd->engines = kcalloc_node(idxd->max_engines, sizeof(struct idxd_engine *), @@ -266,15 +273,17 @@ static int idxd_setup_engines(struct idxd_device *idxd) goto err; } + idxd_dev_set_type(&engine->idxd_dev, IDXD_DEV_ENGINE); + conf_dev = engine_confdev(engine); engine->id = i; engine->idxd = idxd; - device_initialize(&engine->conf_dev); - engine->conf_dev.parent = &idxd->conf_dev; - engine->conf_dev.bus = &dsa_bus_type; - engine->conf_dev.type = &idxd_engine_device_type; - rc = dev_set_name(&engine->conf_dev, "engine%d.%d", idxd->id, engine->id); + device_initialize(conf_dev); + conf_dev->parent = idxd_confdev(idxd); + conf_dev->bus = &dsa_bus_type; + conf_dev->type = &idxd_engine_device_type; + rc = dev_set_name(conf_dev, "engine%d.%d", idxd->id, engine->id); if (rc < 0) { - put_device(&engine->conf_dev); + put_device(conf_dev); goto err; } @@ -284,14 +293,18 @@ static int idxd_setup_engines(struct idxd_device *idxd) return 0; err: - while (--i >= 0) - put_device(&idxd->engines[i]->conf_dev); + while (--i >= 0) { + engine = idxd->engines[i]; + conf_dev = engine_confdev(engine); + put_device(conf_dev); + } return rc; } static int idxd_setup_groups(struct idxd_device *idxd) { struct device *dev = &idxd->pdev->dev; + struct device *conf_dev; struct idxd_group *group; int i, rc; @@ -307,15 +320,17 @@ static int idxd_setup_groups(struct idxd_device *idxd) goto err; } + idxd_dev_set_type(&group->idxd_dev, IDXD_DEV_GROUP); + conf_dev = group_confdev(group); group->id = i; group->idxd = idxd; - device_initialize(&group->conf_dev); - group->conf_dev.parent = &idxd->conf_dev; - group->conf_dev.bus = &dsa_bus_type; - group->conf_dev.type = &idxd_group_device_type; - rc = dev_set_name(&group->conf_dev, "group%d.%d", idxd->id, group->id); + device_initialize(conf_dev); + conf_dev->parent = idxd_confdev(idxd); + conf_dev->bus = &dsa_bus_type; + conf_dev->type = &idxd_group_device_type; + rc = dev_set_name(conf_dev, "group%d.%d", idxd->id, group->id); if (rc < 0) { - put_device(&group->conf_dev); + put_device(conf_dev); goto err; } @@ -327,8 +342,10 @@ static int idxd_setup_groups(struct idxd_device *idxd) return 0; err: - while (--i >= 0) - put_device(&idxd->groups[i]->conf_dev); + while (--i >= 0) { + group = idxd->groups[i]; + put_device(group_confdev(group)); + } return rc; } @@ -337,11 +354,11 @@ static void idxd_cleanup_internals(struct idxd_device *idxd) int i; for (i = 0; i < idxd->max_groups; i++) - put_device(&idxd->groups[i]->conf_dev); + put_device(group_confdev(idxd->groups[i])); for (i = 0; i < idxd->max_engines; i++) - put_device(&idxd->engines[i]->conf_dev); + put_device(engine_confdev(idxd->engines[i])); for (i = 0; i < idxd->max_wqs; i++) - put_device(&idxd->wqs[i]->conf_dev); + put_device(wq_confdev(idxd->wqs[i])); destroy_workqueue(idxd->wq); } @@ -381,13 +398,13 @@ static int idxd_setup_internals(struct idxd_device *idxd) err_wkq_create: for (i = 0; i < idxd->max_groups; i++) - put_device(&idxd->groups[i]->conf_dev); + put_device(group_confdev(idxd->groups[i])); err_group: for (i = 0; i < idxd->max_engines; i++) - put_device(&idxd->engines[i]->conf_dev); + put_device(engine_confdev(idxd->engines[i])); err_engine: for (i = 0; i < idxd->max_wqs; i++) - put_device(&idxd->wqs[i]->conf_dev); + put_device(wq_confdev(idxd->wqs[i])); err_wqs: kfree(idxd->int_handles); return rc; @@ -469,6 +486,7 @@ static void idxd_read_caps(struct idxd_device *idxd) static struct idxd_device *idxd_alloc(struct pci_dev *pdev, struct idxd_driver_data *data) { struct device *dev = &pdev->dev; + struct device *conf_dev; struct idxd_device *idxd; int rc; @@ -476,19 +494,21 @@ static struct idxd_device *idxd_alloc(struct pci_dev *pdev, struct idxd_driver_d if (!idxd) return NULL; + conf_dev = idxd_confdev(idxd); idxd->pdev = pdev; idxd->data = data; + idxd_dev_set_type(&idxd->idxd_dev, idxd->data->type); idxd->id = ida_alloc(&idxd_ida, GFP_KERNEL); if (idxd->id < 0) return NULL; - device_initialize(&idxd->conf_dev); - idxd->conf_dev.parent = dev; - idxd->conf_dev.bus = &dsa_bus_type; - idxd->conf_dev.type = idxd->data->dev_type; - rc = dev_set_name(&idxd->conf_dev, "%s%d", idxd->data->name_prefix, idxd->id); + device_initialize(conf_dev); + conf_dev->parent = dev; + conf_dev->bus = &dsa_bus_type; + conf_dev->type = idxd->data->dev_type; + rc = dev_set_name(conf_dev, "%s%d", idxd->data->name_prefix, idxd->id); if (rc < 0) { - put_device(&idxd->conf_dev); + put_device(conf_dev); return NULL; } @@ -674,7 +694,7 @@ static int idxd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) err: pci_iounmap(pdev, idxd->reg_base); err_iomap: - put_device(&idxd->conf_dev); + put_device(idxd_confdev(idxd)); err_idxd_alloc: pci_disable_device(pdev); return rc; @@ -787,7 +807,7 @@ static void idxd_remove(struct pci_dev *pdev) pci_disable_device(pdev); destroy_workqueue(idxd->wq); perfmon_pmu_remove(idxd); - device_unregister(&idxd->conf_dev); + device_unregister(idxd_confdev(idxd)); } static struct pci_driver idxd_pci_driver = { diff --git a/drivers/dma/idxd/irq.c b/drivers/dma/idxd/irq.c index 2924819ca8f3..be65d55e1fc4 100644 --- a/drivers/dma/idxd/irq.c +++ b/drivers/dma/idxd/irq.c @@ -51,7 +51,7 @@ static void idxd_device_reinit(struct work_struct *work) rc = idxd_wq_enable(wq); if (rc < 0) { dev_warn(dev, "Unable to re-enable wq %s\n", - dev_name(&wq->conf_dev)); + dev_name(wq_confdev(wq))); } } } diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c index 60779f57c118..f603b11141c4 100644 --- a/drivers/dma/idxd/sysfs.c +++ b/drivers/dma/idxd/sysfs.c @@ -164,7 +164,7 @@ static int enable_wq(struct idxd_wq *wq) } mutex_unlock(&wq->wq_lock); - dev_info(dev, "wq %s enabled\n", dev_name(&wq->conf_dev)); + dev_info(dev, "wq %s enabled\n", dev_name(wq_confdev(wq))); return 0; } @@ -230,7 +230,7 @@ static void disable_wq(struct idxd_wq *wq) struct device *dev = &idxd->pdev->dev; mutex_lock(&wq->wq_lock); - dev_dbg(dev, "%s removing WQ %s\n", __func__, dev_name(&wq->conf_dev)); + dev_dbg(dev, "%s removing WQ %s\n", __func__, dev_name(wq_confdev(wq))); if (wq->state == IDXD_WQ_DISABLED) { mutex_unlock(&wq->wq_lock); return; @@ -257,7 +257,7 @@ static void disable_wq(struct idxd_wq *wq) wq->client_count = 0; mutex_unlock(&wq->wq_lock); - dev_info(dev, "wq %s disabled\n", dev_name(&wq->conf_dev)); + dev_info(dev, "wq %s disabled\n", dev_name(wq_confdev(wq))); } static int idxd_config_bus_remove(struct device *dev) @@ -274,15 +274,15 @@ static int idxd_config_bus_remove(struct device *dev) int i; dev_dbg(dev, "%s removing dev %s\n", __func__, - dev_name(&idxd->conf_dev)); + dev_name(idxd_confdev(idxd))); for (i = 0; i < idxd->max_wqs; i++) { struct idxd_wq *wq = idxd->wqs[i]; if (wq->state == IDXD_WQ_DISABLED) continue; dev_warn(dev, "Active wq %d on disable %s.\n", i, - dev_name(&idxd->conf_dev)); - device_release_driver(&wq->conf_dev); + dev_name(wq_confdev(wq))); + device_release_driver(wq_confdev(wq)); } idxd_unregister_dma_device(idxd); @@ -329,8 +329,7 @@ void idxd_unregister_driver(void) static ssize_t engine_group_id_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_engine *engine = - container_of(dev, struct idxd_engine, conf_dev); + struct idxd_engine *engine = confdev_to_engine(dev); if (engine->group) return sysfs_emit(buf, "%d\n", engine->group->id); @@ -342,8 +341,7 @@ static ssize_t engine_group_id_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct idxd_engine *engine = - container_of(dev, struct idxd_engine, conf_dev); + struct idxd_engine *engine = confdev_to_engine(dev); struct idxd_device *idxd = engine->idxd; long id; int rc; @@ -397,7 +395,7 @@ static const struct attribute_group *idxd_engine_attribute_groups[] = { static void idxd_conf_engine_release(struct device *dev) { - struct idxd_engine *engine = container_of(dev, struct idxd_engine, conf_dev); + struct idxd_engine *engine = confdev_to_engine(dev); kfree(engine); } @@ -427,8 +425,7 @@ static ssize_t group_tokens_reserved_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_group *group = - container_of(dev, struct idxd_group, conf_dev); + struct idxd_group *group = confdev_to_group(dev); return sysfs_emit(buf, "%u\n", group->tokens_reserved); } @@ -437,8 +434,7 @@ static ssize_t group_tokens_reserved_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct idxd_group *group = - container_of(dev, struct idxd_group, conf_dev); + struct idxd_group *group = confdev_to_group(dev); struct idxd_device *idxd = group->idxd; unsigned long val; int rc; @@ -475,8 +471,7 @@ static ssize_t group_tokens_allowed_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_group *group = - container_of(dev, struct idxd_group, conf_dev); + struct idxd_group *group = confdev_to_group(dev); return sysfs_emit(buf, "%u\n", group->tokens_allowed); } @@ -485,8 +480,7 @@ static ssize_t group_tokens_allowed_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct idxd_group *group = - container_of(dev, struct idxd_group, conf_dev); + struct idxd_group *group = confdev_to_group(dev); struct idxd_device *idxd = group->idxd; unsigned long val; int rc; @@ -520,8 +514,7 @@ static ssize_t group_use_token_limit_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_group *group = - container_of(dev, struct idxd_group, conf_dev); + struct idxd_group *group = confdev_to_group(dev); return sysfs_emit(buf, "%u\n", group->use_token_limit); } @@ -530,8 +523,7 @@ static ssize_t group_use_token_limit_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct idxd_group *group = - container_of(dev, struct idxd_group, conf_dev); + struct idxd_group *group = confdev_to_group(dev); struct idxd_device *idxd = group->idxd; unsigned long val; int rc; @@ -563,8 +555,7 @@ static struct device_attribute dev_attr_group_use_token_limit = static ssize_t group_engines_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_group *group = - container_of(dev, struct idxd_group, conf_dev); + struct idxd_group *group = confdev_to_group(dev); int i, rc = 0; struct idxd_device *idxd = group->idxd; @@ -592,8 +583,7 @@ static struct device_attribute dev_attr_group_engines = static ssize_t group_work_queues_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_group *group = - container_of(dev, struct idxd_group, conf_dev); + struct idxd_group *group = confdev_to_group(dev); int i, rc = 0; struct idxd_device *idxd = group->idxd; @@ -622,8 +612,7 @@ static ssize_t group_traffic_class_a_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_group *group = - container_of(dev, struct idxd_group, conf_dev); + struct idxd_group *group = confdev_to_group(dev); return sysfs_emit(buf, "%d\n", group->tc_a); } @@ -632,8 +621,7 @@ static ssize_t group_traffic_class_a_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct idxd_group *group = - container_of(dev, struct idxd_group, conf_dev); + struct idxd_group *group = confdev_to_group(dev); struct idxd_device *idxd = group->idxd; long val; int rc; @@ -663,8 +651,7 @@ static ssize_t group_traffic_class_b_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_group *group = - container_of(dev, struct idxd_group, conf_dev); + struct idxd_group *group = confdev_to_group(dev); return sysfs_emit(buf, "%d\n", group->tc_b); } @@ -673,8 +660,7 @@ static ssize_t group_traffic_class_b_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct idxd_group *group = - container_of(dev, struct idxd_group, conf_dev); + struct idxd_group *group = confdev_to_group(dev); struct idxd_device *idxd = group->idxd; long val; int rc; @@ -722,7 +708,7 @@ static const struct attribute_group *idxd_group_attribute_groups[] = { static void idxd_conf_group_release(struct device *dev) { - struct idxd_group *group = container_of(dev, struct idxd_group, conf_dev); + struct idxd_group *group = confdev_to_group(dev); kfree(group); } @@ -737,7 +723,7 @@ struct device_type idxd_group_device_type = { static ssize_t wq_clients_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev); + struct idxd_wq *wq = confdev_to_wq(dev); return sysfs_emit(buf, "%d\n", wq->client_count); } @@ -748,7 +734,7 @@ static struct device_attribute dev_attr_wq_clients = static ssize_t wq_state_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev); + struct idxd_wq *wq = confdev_to_wq(dev); switch (wq->state) { case IDXD_WQ_DISABLED: @@ -766,7 +752,7 @@ static struct device_attribute dev_attr_wq_state = static ssize_t wq_group_id_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev); + struct idxd_wq *wq = confdev_to_wq(dev); if (wq->group) return sysfs_emit(buf, "%u\n", wq->group->id); @@ -778,7 +764,7 @@ static ssize_t wq_group_id_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev); + struct idxd_wq *wq = confdev_to_wq(dev); struct idxd_device *idxd = wq->idxd; long id; int rc; @@ -821,7 +807,7 @@ static struct device_attribute dev_attr_wq_group_id = static ssize_t wq_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev); + struct idxd_wq *wq = confdev_to_wq(dev); return sysfs_emit(buf, "%s\n", wq_dedicated(wq) ? "dedicated" : "shared"); } @@ -830,7 +816,7 @@ static ssize_t wq_mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev); + struct idxd_wq *wq = confdev_to_wq(dev); struct idxd_device *idxd = wq->idxd; if (!test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags)) @@ -857,7 +843,7 @@ static struct device_attribute dev_attr_wq_mode = static ssize_t wq_size_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev); + struct idxd_wq *wq = confdev_to_wq(dev); return sysfs_emit(buf, "%u\n", wq->size); } @@ -880,7 +866,7 @@ static ssize_t wq_size_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev); + struct idxd_wq *wq = confdev_to_wq(dev); unsigned long size; struct idxd_device *idxd = wq->idxd; int rc; @@ -908,7 +894,7 @@ static struct device_attribute dev_attr_wq_size = static ssize_t wq_priority_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev); + struct idxd_wq *wq = confdev_to_wq(dev); return sysfs_emit(buf, "%u\n", wq->priority); } @@ -917,7 +903,7 @@ static ssize_t wq_priority_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev); + struct idxd_wq *wq = confdev_to_wq(dev); unsigned long prio; struct idxd_device *idxd = wq->idxd; int rc; @@ -945,7 +931,7 @@ static struct device_attribute dev_attr_wq_priority = static ssize_t wq_block_on_fault_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev); + struct idxd_wq *wq = confdev_to_wq(dev); return sysfs_emit(buf, "%u\n", test_bit(WQ_FLAG_BLOCK_ON_FAULT, &wq->flags)); } @@ -954,7 +940,7 @@ static ssize_t wq_block_on_fault_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev); + struct idxd_wq *wq = confdev_to_wq(dev); struct idxd_device *idxd = wq->idxd; bool bof; int rc; @@ -984,7 +970,7 @@ static struct device_attribute dev_attr_wq_block_on_fault = static ssize_t wq_threshold_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev); + struct idxd_wq *wq = confdev_to_wq(dev); return sysfs_emit(buf, "%u\n", wq->threshold); } @@ -993,7 +979,7 @@ static ssize_t wq_threshold_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev); + struct idxd_wq *wq = confdev_to_wq(dev); struct idxd_device *idxd = wq->idxd; unsigned int val; int rc; @@ -1025,7 +1011,7 @@ static struct device_attribute dev_attr_wq_threshold = static ssize_t wq_type_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev); + struct idxd_wq *wq = confdev_to_wq(dev); switch (wq->type) { case IDXD_WQT_KERNEL: @@ -1044,7 +1030,7 @@ static ssize_t wq_type_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev); + struct idxd_wq *wq = confdev_to_wq(dev); enum idxd_wq_type old_type; if (wq->state != IDXD_WQ_DISABLED) @@ -1073,7 +1059,7 @@ static struct device_attribute dev_attr_wq_type = static ssize_t wq_name_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev); + struct idxd_wq *wq = confdev_to_wq(dev); return sysfs_emit(buf, "%s\n", wq->name); } @@ -1082,7 +1068,7 @@ static ssize_t wq_name_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev); + struct idxd_wq *wq = confdev_to_wq(dev); if (wq->state != IDXD_WQ_DISABLED) return -EPERM; @@ -1109,7 +1095,7 @@ static struct device_attribute dev_attr_wq_name = static ssize_t wq_cdev_minor_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev); + struct idxd_wq *wq = confdev_to_wq(dev); int minor = -1; mutex_lock(&wq->wq_lock); @@ -1143,7 +1129,7 @@ static int __get_sysfs_u64(const char *buf, u64 *val) static ssize_t wq_max_transfer_size_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev); + struct idxd_wq *wq = confdev_to_wq(dev); return sysfs_emit(buf, "%llu\n", wq->max_xfer_bytes); } @@ -1151,7 +1137,7 @@ static ssize_t wq_max_transfer_size_show(struct device *dev, struct device_attri static ssize_t wq_max_transfer_size_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev); + struct idxd_wq *wq = confdev_to_wq(dev); struct idxd_device *idxd = wq->idxd; u64 xfer_size; int rc; @@ -1177,7 +1163,7 @@ static struct device_attribute dev_attr_wq_max_transfer_size = static ssize_t wq_max_batch_size_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev); + struct idxd_wq *wq = confdev_to_wq(dev); return sysfs_emit(buf, "%u\n", wq->max_batch_size); } @@ -1185,7 +1171,7 @@ static ssize_t wq_max_batch_size_show(struct device *dev, struct device_attribut static ssize_t wq_max_batch_size_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev); + struct idxd_wq *wq = confdev_to_wq(dev); struct idxd_device *idxd = wq->idxd; u64 batch_size; int rc; @@ -1210,7 +1196,7 @@ static struct device_attribute dev_attr_wq_max_batch_size = static ssize_t wq_ats_disable_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev); + struct idxd_wq *wq = confdev_to_wq(dev); return sysfs_emit(buf, "%u\n", wq->ats_dis); } @@ -1218,7 +1204,7 @@ static ssize_t wq_ats_disable_show(struct device *dev, struct device_attribute * static ssize_t wq_ats_disable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev); + struct idxd_wq *wq = confdev_to_wq(dev); struct idxd_device *idxd = wq->idxd; bool ats_dis; int rc; @@ -1289,7 +1275,7 @@ static const struct attribute_group *idxd_wq_attribute_groups[] = { static void idxd_conf_wq_release(struct device *dev) { - struct idxd_wq *wq = container_of(dev, struct idxd_wq, conf_dev); + struct idxd_wq *wq = confdev_to_wq(dev); kfree(wq->wqcfg); kfree(wq); @@ -1305,8 +1291,7 @@ struct device_type idxd_wq_device_type = { static ssize_t version_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_device *idxd = - container_of(dev, struct idxd_device, conf_dev); + struct idxd_device *idxd = confdev_to_idxd(dev); return sysfs_emit(buf, "%#x\n", idxd->hw.version); } @@ -1316,8 +1301,7 @@ static ssize_t max_work_queues_size_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_device *idxd = - container_of(dev, struct idxd_device, conf_dev); + struct idxd_device *idxd = confdev_to_idxd(dev); return sysfs_emit(buf, "%u\n", idxd->max_wq_size); } @@ -1326,8 +1310,7 @@ static DEVICE_ATTR_RO(max_work_queues_size); static ssize_t max_groups_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_device *idxd = - container_of(dev, struct idxd_device, conf_dev); + struct idxd_device *idxd = confdev_to_idxd(dev); return sysfs_emit(buf, "%u\n", idxd->max_groups); } @@ -1336,8 +1319,7 @@ static DEVICE_ATTR_RO(max_groups); static ssize_t max_work_queues_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_device *idxd = - container_of(dev, struct idxd_device, conf_dev); + struct idxd_device *idxd = confdev_to_idxd(dev); return sysfs_emit(buf, "%u\n", idxd->max_wqs); } @@ -1346,8 +1328,7 @@ static DEVICE_ATTR_RO(max_work_queues); static ssize_t max_engines_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_device *idxd = - container_of(dev, struct idxd_device, conf_dev); + struct idxd_device *idxd = confdev_to_idxd(dev); return sysfs_emit(buf, "%u\n", idxd->max_engines); } @@ -1356,8 +1337,7 @@ static DEVICE_ATTR_RO(max_engines); static ssize_t numa_node_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_device *idxd = - container_of(dev, struct idxd_device, conf_dev); + struct idxd_device *idxd = confdev_to_idxd(dev); return sysfs_emit(buf, "%d\n", dev_to_node(&idxd->pdev->dev)); } @@ -1366,8 +1346,7 @@ static DEVICE_ATTR_RO(numa_node); static ssize_t max_batch_size_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_device *idxd = - container_of(dev, struct idxd_device, conf_dev); + struct idxd_device *idxd = confdev_to_idxd(dev); return sysfs_emit(buf, "%u\n", idxd->max_batch_size); } @@ -1377,8 +1356,7 @@ static ssize_t max_transfer_size_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_device *idxd = - container_of(dev, struct idxd_device, conf_dev); + struct idxd_device *idxd = confdev_to_idxd(dev); return sysfs_emit(buf, "%llu\n", idxd->max_xfer_bytes); } @@ -1387,8 +1365,7 @@ static DEVICE_ATTR_RO(max_transfer_size); static ssize_t op_cap_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_device *idxd = - container_of(dev, struct idxd_device, conf_dev); + struct idxd_device *idxd = confdev_to_idxd(dev); int i, rc = 0; for (i = 0; i < 4; i++) @@ -1403,8 +1380,7 @@ static DEVICE_ATTR_RO(op_cap); static ssize_t gen_cap_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_device *idxd = - container_of(dev, struct idxd_device, conf_dev); + struct idxd_device *idxd = confdev_to_idxd(dev); return sysfs_emit(buf, "%#llx\n", idxd->hw.gen_cap.bits); } @@ -1413,8 +1389,7 @@ static DEVICE_ATTR_RO(gen_cap); static ssize_t configurable_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_device *idxd = - container_of(dev, struct idxd_device, conf_dev); + struct idxd_device *idxd = confdev_to_idxd(dev); return sysfs_emit(buf, "%u\n", test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags)); } @@ -1423,8 +1398,7 @@ static DEVICE_ATTR_RO(configurable); static ssize_t clients_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_device *idxd = - container_of(dev, struct idxd_device, conf_dev); + struct idxd_device *idxd = confdev_to_idxd(dev); unsigned long flags; int count = 0, i; @@ -1443,8 +1417,7 @@ static DEVICE_ATTR_RO(clients); static ssize_t pasid_enabled_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_device *idxd = - container_of(dev, struct idxd_device, conf_dev); + struct idxd_device *idxd = confdev_to_idxd(dev); return sysfs_emit(buf, "%u\n", device_pasid_enabled(idxd)); } @@ -1453,8 +1426,7 @@ static DEVICE_ATTR_RO(pasid_enabled); static ssize_t state_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_device *idxd = - container_of(dev, struct idxd_device, conf_dev); + struct idxd_device *idxd = confdev_to_idxd(dev); switch (idxd->state) { case IDXD_DEV_DISABLED: @@ -1473,8 +1445,7 @@ static DEVICE_ATTR_RO(state); static ssize_t errors_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_device *idxd = - container_of(dev, struct idxd_device, conf_dev); + struct idxd_device *idxd = confdev_to_idxd(dev); int i, out = 0; unsigned long flags; @@ -1491,8 +1462,7 @@ static DEVICE_ATTR_RO(errors); static ssize_t max_tokens_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_device *idxd = - container_of(dev, struct idxd_device, conf_dev); + struct idxd_device *idxd = confdev_to_idxd(dev); return sysfs_emit(buf, "%u\n", idxd->max_tokens); } @@ -1501,8 +1471,7 @@ static DEVICE_ATTR_RO(max_tokens); static ssize_t token_limit_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_device *idxd = - container_of(dev, struct idxd_device, conf_dev); + struct idxd_device *idxd = confdev_to_idxd(dev); return sysfs_emit(buf, "%u\n", idxd->token_limit); } @@ -1511,8 +1480,7 @@ static ssize_t token_limit_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct idxd_device *idxd = - container_of(dev, struct idxd_device, conf_dev); + struct idxd_device *idxd = confdev_to_idxd(dev); unsigned long val; int rc; @@ -1540,8 +1508,7 @@ static DEVICE_ATTR_RW(token_limit); static ssize_t cdev_major_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_device *idxd = - container_of(dev, struct idxd_device, conf_dev); + struct idxd_device *idxd = confdev_to_idxd(dev); return sysfs_emit(buf, "%u\n", idxd->major); } @@ -1550,7 +1517,7 @@ static DEVICE_ATTR_RO(cdev_major); static ssize_t cmd_status_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct idxd_device *idxd = container_of(dev, struct idxd_device, conf_dev); + struct idxd_device *idxd = confdev_to_idxd(dev); return sysfs_emit(buf, "%#x\n", idxd->cmd_status); } @@ -1590,7 +1557,7 @@ static const struct attribute_group *idxd_attribute_groups[] = { static void idxd_conf_device_release(struct device *dev) { - struct idxd_device *idxd = container_of(dev, struct idxd_device, conf_dev); + struct idxd_device *idxd = confdev_to_idxd(dev); kfree(idxd->groups); kfree(idxd->wqs); @@ -1615,12 +1582,12 @@ struct device_type iax_device_type = { static int idxd_register_engine_devices(struct idxd_device *idxd) { + struct idxd_engine *engine; int i, j, rc; for (i = 0; i < idxd->max_engines; i++) { - struct idxd_engine *engine = idxd->engines[i]; - - rc = device_add(&engine->conf_dev); + engine = idxd->engines[i]; + rc = device_add(engine_confdev(engine)); if (rc < 0) goto cleanup; } @@ -1629,22 +1596,26 @@ static int idxd_register_engine_devices(struct idxd_device *idxd) cleanup: j = i - 1; - for (; i < idxd->max_engines; i++) - put_device(&idxd->engines[i]->conf_dev); + for (; i < idxd->max_engines; i++) { + engine = idxd->engines[i]; + put_device(engine_confdev(engine)); + } - while (j--) - device_unregister(&idxd->engines[j]->conf_dev); + while (j--) { + engine = idxd->engines[j]; + device_unregister(engine_confdev(engine)); + } return rc; } static int idxd_register_group_devices(struct idxd_device *idxd) { + struct idxd_group *group; int i, j, rc; for (i = 0; i < idxd->max_groups; i++) { - struct idxd_group *group = idxd->groups[i]; - - rc = device_add(&group->conf_dev); + group = idxd->groups[i]; + rc = device_add(group_confdev(group)); if (rc < 0) goto cleanup; } @@ -1653,22 +1624,26 @@ static int idxd_register_group_devices(struct idxd_device *idxd) cleanup: j = i - 1; - for (; i < idxd->max_groups; i++) - put_device(&idxd->groups[i]->conf_dev); + for (; i < idxd->max_groups; i++) { + group = idxd->groups[i]; + put_device(group_confdev(group)); + } - while (j--) - device_unregister(&idxd->groups[j]->conf_dev); + while (j--) { + group = idxd->groups[j]; + device_unregister(group_confdev(group)); + } return rc; } static int idxd_register_wq_devices(struct idxd_device *idxd) { + struct idxd_wq *wq; int i, rc, j; for (i = 0; i < idxd->max_wqs; i++) { - struct idxd_wq *wq = idxd->wqs[i]; - - rc = device_add(&wq->conf_dev); + wq = idxd->wqs[i]; + rc = device_add(wq_confdev(wq)); if (rc < 0) goto cleanup; } @@ -1677,11 +1652,15 @@ static int idxd_register_wq_devices(struct idxd_device *idxd) cleanup: j = i - 1; - for (; i < idxd->max_wqs; i++) - put_device(&idxd->wqs[i]->conf_dev); + for (; i < idxd->max_wqs; i++) { + wq = idxd->wqs[i]; + put_device(wq_confdev(wq)); + } - while (j--) - device_unregister(&idxd->wqs[j]->conf_dev); + while (j--) { + wq = idxd->wqs[j]; + device_unregister(wq_confdev(wq)); + } return rc; } @@ -1690,7 +1669,7 @@ int idxd_register_devices(struct idxd_device *idxd) struct device *dev = &idxd->pdev->dev; int rc, i; - rc = device_add(&idxd->conf_dev); + rc = device_add(idxd_confdev(idxd)); if (rc < 0) return rc; @@ -1716,12 +1695,12 @@ int idxd_register_devices(struct idxd_device *idxd) err_group: for (i = 0; i < idxd->max_engines; i++) - device_unregister(&idxd->engines[i]->conf_dev); + device_unregister(engine_confdev(idxd->engines[i])); err_engine: for (i = 0; i < idxd->max_wqs; i++) - device_unregister(&idxd->wqs[i]->conf_dev); + device_unregister(wq_confdev(idxd->wqs[i])); err_wq: - device_del(&idxd->conf_dev); + device_del(idxd_confdev(idxd)); return rc; } @@ -1732,19 +1711,19 @@ void idxd_unregister_devices(struct idxd_device *idxd) for (i = 0; i < idxd->max_wqs; i++) { struct idxd_wq *wq = idxd->wqs[i]; - device_unregister(&wq->conf_dev); + device_unregister(wq_confdev(wq)); } for (i = 0; i < idxd->max_engines; i++) { struct idxd_engine *engine = idxd->engines[i]; - device_unregister(&engine->conf_dev); + device_unregister(engine_confdev(engine)); } for (i = 0; i < idxd->max_groups; i++) { struct idxd_group *group = idxd->groups[i]; - device_unregister(&group->conf_dev); + device_unregister(group_confdev(group)); } } From f52058ae11523304a337de249c4c07ba5076f288 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Thu, 15 Jul 2021 11:43:26 -0700 Subject: [PATCH 026/696] dmaengine: idxd: remove IDXD_DEV_CONF_READY The IDXD_DEV_CONF_READY state flag is no longer needed. The current implementation uses this flag to stop the device from doing configuration until the pci driver probe has completed. With the driver architecture going towards multiple sub-driver attached to the dsa_bus, this is no longer feasible. The sub-drivers will be allowed to probe and return with failure when they are not ready to complete the probe rather than using a state flag to gate the probing. There is no expectation that the devices auto-attach to a driver. Userspace configuration is expected to setup the device before enabling. Reviewed-by: Dan Williams Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/162637460633.744545.8902095097471365420.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/device.c | 4 ++-- drivers/dma/idxd/idxd.h | 1 - drivers/dma/idxd/init.c | 2 -- drivers/dma/idxd/sysfs.c | 14 -------------- 4 files changed, 2 insertions(+), 19 deletions(-) diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c index c8cf1de72176..4a2af9799239 100644 --- a/drivers/dma/idxd/device.c +++ b/drivers/dma/idxd/device.c @@ -576,7 +576,7 @@ int idxd_device_disable(struct idxd_device *idxd) spin_lock_irqsave(&idxd->dev_lock, flags); idxd_device_clear_state(idxd); - idxd->state = IDXD_DEV_CONF_READY; + idxd->state = IDXD_DEV_DISABLED; spin_unlock_irqrestore(&idxd->dev_lock, flags); return 0; } @@ -588,7 +588,7 @@ void idxd_device_reset(struct idxd_device *idxd) idxd_cmd_exec(idxd, IDXD_CMD_RESET_DEVICE, 0, NULL); spin_lock_irqsave(&idxd->dev_lock, flags); idxd_device_clear_state(idxd); - idxd->state = IDXD_DEV_CONF_READY; + idxd->state = IDXD_DEV_DISABLED; spin_unlock_irqrestore(&idxd->dev_lock, flags); } diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h index ae60fcc7b625..9fc1a88f336d 100644 --- a/drivers/dma/idxd/idxd.h +++ b/drivers/dma/idxd/idxd.h @@ -210,7 +210,6 @@ struct idxd_hw { enum idxd_device_state { IDXD_DEV_HALTED = -1, IDXD_DEV_DISABLED = 0, - IDXD_DEV_CONF_READY, IDXD_DEV_ENABLED, }; diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c index f500076882d2..c22225b14c5d 100644 --- a/drivers/dma/idxd/init.c +++ b/drivers/dma/idxd/init.c @@ -682,8 +682,6 @@ static int idxd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_dev_register; } - idxd->state = IDXD_DEV_CONF_READY; - dev_info(&pdev->dev, "Intel(R) Accelerator Device (v%x)\n", idxd->hw.version); diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c index f603b11141c4..2a978055e22b 100644 --- a/drivers/dma/idxd/sysfs.c +++ b/drivers/dma/idxd/sysfs.c @@ -22,17 +22,9 @@ static int idxd_config_bus_match(struct device *dev, int matched = 0; if (is_idxd_dev(dev)) { - struct idxd_device *idxd = confdev_to_idxd(dev); - - if (idxd->state != IDXD_DEV_CONF_READY) - return 0; matched = 1; } else if (is_idxd_wq_dev(dev)) { struct idxd_wq *wq = confdev_to_wq(dev); - struct idxd_device *idxd = wq->idxd; - - if (idxd->state < IDXD_DEV_CONF_READY) - return 0; if (wq->state != IDXD_WQ_DISABLED) { dev_dbg(dev, "%s not disabled\n", dev_name(dev)); @@ -179,11 +171,6 @@ static int idxd_config_bus_probe(struct device *dev) if (is_idxd_dev(dev)) { struct idxd_device *idxd = confdev_to_idxd(dev); - if (idxd->state != IDXD_DEV_CONF_READY) { - dev_warn(dev, "Device not ready for config\n"); - return -EBUSY; - } - if (!try_module_get(THIS_MODULE)) return -ENXIO; @@ -1430,7 +1417,6 @@ static ssize_t state_show(struct device *dev, switch (idxd->state) { case IDXD_DEV_DISABLED: - case IDXD_DEV_CONF_READY: return sysfs_emit(buf, "disabled\n"); case IDXD_DEV_ENABLED: return sysfs_emit(buf, "enabled\n"); From 1f2bb40337f0df1d9af80793e9fdacff7706e654 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Thu, 15 Jul 2021 11:43:31 -0700 Subject: [PATCH 027/696] dmaengine: idxd: move wq_enable() to device.c Move the wq_enable() function to device.c in preparation of setting up the idxd internal sub-driver framework. No logic changes. Reviewed-by: Dan Williams Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/162637461176.744545.3806109011554118998.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/device.c | 124 ++++++++++++++++++++++++++++++++++++++ drivers/dma/idxd/idxd.h | 1 + drivers/dma/idxd/sysfs.c | 124 +------------------------------------- 3 files changed, 126 insertions(+), 123 deletions(-) diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c index 4a2af9799239..b1c509bcfa31 100644 --- a/drivers/dma/idxd/device.c +++ b/drivers/dma/idxd/device.c @@ -1129,3 +1129,127 @@ int idxd_device_load_config(struct idxd_device *idxd) return 0; } + +static int __drv_enable_wq(struct idxd_wq *wq) +{ + struct idxd_device *idxd = wq->idxd; + struct device *dev = &idxd->pdev->dev; + unsigned long flags; + int rc = -ENXIO; + + lockdep_assert_held(&wq->wq_lock); + + if (idxd->state != IDXD_DEV_ENABLED) + goto err; + + if (wq->state != IDXD_WQ_DISABLED) { + dev_dbg(dev, "wq %d already enabled.\n", wq->id); + rc = -EBUSY; + goto err; + } + + if (!wq->group) { + dev_dbg(dev, "wq %d not attached to group.\n", wq->id); + goto err; + } + + if (strlen(wq->name) == 0) { + dev_dbg(dev, "wq %d name not set.\n", wq->id); + goto err; + } + + /* Shared WQ checks */ + if (wq_shared(wq)) { + if (!device_swq_supported(idxd)) { + dev_dbg(dev, "PASID not enabled and shared wq.\n"); + goto err; + } + /* + * Shared wq with the threshold set to 0 means the user + * did not set the threshold or transitioned from a + * dedicated wq but did not set threshold. A value + * of 0 would effectively disable the shared wq. The + * driver does not allow a value of 0 to be set for + * threshold via sysfs. + */ + if (wq->threshold == 0) { + dev_dbg(dev, "Shared wq and threshold 0.\n"); + goto err; + } + } + + rc = idxd_wq_alloc_resources(wq); + if (rc < 0) { + dev_dbg(dev, "wq resource alloc failed\n"); + goto err; + } + + spin_lock_irqsave(&idxd->dev_lock, flags); + if (test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags)) + rc = idxd_device_config(idxd); + spin_unlock_irqrestore(&idxd->dev_lock, flags); + if (rc < 0) { + dev_dbg(dev, "Writing wq %d config failed: %d\n", wq->id, rc); + goto err; + } + + rc = idxd_wq_enable(wq); + if (rc < 0) { + dev_dbg(dev, "wq %d enabling failed: %d\n", wq->id, rc); + goto err; + } + + rc = idxd_wq_map_portal(wq); + if (rc < 0) { + dev_dbg(dev, "wq %d portal mapping failed: %d\n", wq->id, rc); + goto err_map_portal; + } + + wq->client_count = 0; + + if (wq->type == IDXD_WQT_KERNEL) { + rc = idxd_wq_init_percpu_ref(wq); + if (rc < 0) { + dev_dbg(dev, "wq %d percpu_ref setup failed\n", wq->id); + goto err_cpu_ref; + } + } + + if (is_idxd_wq_dmaengine(wq)) { + rc = idxd_register_dma_channel(wq); + if (rc < 0) { + dev_dbg(dev, "wq %d DMA channel register failed\n", wq->id); + goto err_client; + } + } else if (is_idxd_wq_cdev(wq)) { + rc = idxd_wq_add_cdev(wq); + if (rc < 0) { + dev_dbg(dev, "wq %d cdev creation failed\n", wq->id); + goto err_client; + } + } + + dev_info(dev, "wq %s enabled\n", dev_name(wq_confdev(wq))); + return 0; + +err_client: + idxd_wq_quiesce(wq); +err_cpu_ref: + idxd_wq_unmap_portal(wq); +err_map_portal: + rc = idxd_wq_disable(wq, false); + if (rc < 0) + dev_dbg(dev, "wq %s disable failed\n", dev_name(wq_confdev(wq))); +err: + return rc; +} + +int drv_enable_wq(struct idxd_wq *wq) +{ + int rc; + + mutex_lock(&wq->wq_lock); + rc = __drv_enable_wq(wq); + mutex_unlock(&wq->wq_lock); + return rc; +} diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h index 9fc1a88f336d..551a61fa1aff 100644 --- a/drivers/dma/idxd/idxd.h +++ b/drivers/dma/idxd/idxd.h @@ -495,6 +495,7 @@ void idxd_mask_msix_vector(struct idxd_device *idxd, int vec_id); void idxd_unmask_msix_vector(struct idxd_device *idxd, int vec_id); /* device control */ +int drv_enable_wq(struct idxd_wq *wq); int idxd_device_init_reset(struct idxd_device *idxd); int idxd_device_enable(struct idxd_device *idxd); int idxd_device_disable(struct idxd_device *idxd); diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c index 2a978055e22b..3e8cc07ebcdc 100644 --- a/drivers/dma/idxd/sysfs.c +++ b/drivers/dma/idxd/sysfs.c @@ -39,128 +39,6 @@ static int idxd_config_bus_match(struct device *dev, return matched; } -static int enable_wq(struct idxd_wq *wq) -{ - struct idxd_device *idxd = wq->idxd; - struct device *dev = &idxd->pdev->dev; - unsigned long flags; - int rc; - - mutex_lock(&wq->wq_lock); - - if (idxd->state != IDXD_DEV_ENABLED) { - mutex_unlock(&wq->wq_lock); - dev_warn(dev, "Enabling while device not enabled.\n"); - return -EPERM; - } - - if (wq->state != IDXD_WQ_DISABLED) { - mutex_unlock(&wq->wq_lock); - dev_warn(dev, "WQ %d already enabled.\n", wq->id); - return -EBUSY; - } - - if (!wq->group) { - mutex_unlock(&wq->wq_lock); - dev_warn(dev, "WQ not attached to group.\n"); - return -EINVAL; - } - - if (strlen(wq->name) == 0) { - mutex_unlock(&wq->wq_lock); - dev_warn(dev, "WQ name not set.\n"); - return -EINVAL; - } - - /* Shared WQ checks */ - if (wq_shared(wq)) { - if (!device_swq_supported(idxd)) { - dev_warn(dev, "PASID not enabled and shared WQ.\n"); - mutex_unlock(&wq->wq_lock); - return -ENXIO; - } - /* - * Shared wq with the threshold set to 0 means the user - * did not set the threshold or transitioned from a - * dedicated wq but did not set threshold. A value - * of 0 would effectively disable the shared wq. The - * driver does not allow a value of 0 to be set for - * threshold via sysfs. - */ - if (wq->threshold == 0) { - dev_warn(dev, "Shared WQ and threshold 0.\n"); - mutex_unlock(&wq->wq_lock); - return -EINVAL; - } - } - - rc = idxd_wq_alloc_resources(wq); - if (rc < 0) { - mutex_unlock(&wq->wq_lock); - dev_warn(dev, "WQ resource alloc failed\n"); - return rc; - } - - spin_lock_irqsave(&idxd->dev_lock, flags); - if (test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags)) - rc = idxd_device_config(idxd); - spin_unlock_irqrestore(&idxd->dev_lock, flags); - if (rc < 0) { - mutex_unlock(&wq->wq_lock); - dev_warn(dev, "Writing WQ %d config failed: %d\n", wq->id, rc); - return rc; - } - - rc = idxd_wq_enable(wq); - if (rc < 0) { - mutex_unlock(&wq->wq_lock); - dev_warn(dev, "WQ %d enabling failed: %d\n", wq->id, rc); - return rc; - } - - rc = idxd_wq_map_portal(wq); - if (rc < 0) { - dev_warn(dev, "wq portal mapping failed: %d\n", rc); - rc = idxd_wq_disable(wq, false); - if (rc < 0) - dev_warn(dev, "IDXD wq disable failed\n"); - mutex_unlock(&wq->wq_lock); - return rc; - } - - wq->client_count = 0; - - if (wq->type == IDXD_WQT_KERNEL) { - rc = idxd_wq_init_percpu_ref(wq); - if (rc < 0) { - dev_dbg(dev, "percpu_ref setup failed\n"); - mutex_unlock(&wq->wq_lock); - return rc; - } - } - - if (is_idxd_wq_dmaengine(wq)) { - rc = idxd_register_dma_channel(wq); - if (rc < 0) { - dev_dbg(dev, "DMA channel register failed\n"); - mutex_unlock(&wq->wq_lock); - return rc; - } - } else if (is_idxd_wq_cdev(wq)) { - rc = idxd_wq_add_cdev(wq); - if (rc < 0) { - dev_dbg(dev, "Cdev creation failed\n"); - mutex_unlock(&wq->wq_lock); - return rc; - } - } - - mutex_unlock(&wq->wq_lock); - dev_info(dev, "wq %s enabled\n", dev_name(wq_confdev(wq))); - - return 0; -} - static int idxd_config_bus_probe(struct device *dev) { int rc = 0; @@ -205,7 +83,7 @@ static int idxd_config_bus_probe(struct device *dev) } else if (is_idxd_wq_dev(dev)) { struct idxd_wq *wq = confdev_to_wq(dev); - return enable_wq(wq); + return drv_enable_wq(wq); } return -ENODEV; From 69e4f8be596d897679e44e86a323629537c02975 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Thu, 15 Jul 2021 11:43:37 -0700 Subject: [PATCH 028/696] dmaengine: idxd: move wq_disable() to device.c Move the wq_disable() function to device.c in preparation of setting up the idxd internal sub-driver framework. No logic changes. Reviewed-by: Dan Williams Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/162637461775.744545.9644048686618957886.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/device.c | 37 +++++++++++++++++++++++++++++++++++++ drivers/dma/idxd/idxd.h | 1 + drivers/dma/idxd/sysfs.c | 38 +------------------------------------- 3 files changed, 39 insertions(+), 37 deletions(-) diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c index b1c509bcfa31..8d8e249931a9 100644 --- a/drivers/dma/idxd/device.c +++ b/drivers/dma/idxd/device.c @@ -1253,3 +1253,40 @@ int drv_enable_wq(struct idxd_wq *wq) mutex_unlock(&wq->wq_lock); return rc; } + +static void __drv_disable_wq(struct idxd_wq *wq) +{ + struct idxd_device *idxd = wq->idxd; + struct device *dev = &idxd->pdev->dev; + + lockdep_assert_held(&wq->wq_lock); + + if (wq->type == IDXD_WQT_KERNEL) + idxd_wq_quiesce(wq); + + if (is_idxd_wq_dmaengine(wq)) + idxd_unregister_dma_channel(wq); + else if (is_idxd_wq_cdev(wq)) + idxd_wq_del_cdev(wq); + + if (idxd_wq_refcount(wq)) + dev_warn(dev, "Clients has claim on wq %d: %d\n", + wq->id, idxd_wq_refcount(wq)); + + idxd_wq_unmap_portal(wq); + + idxd_wq_drain(wq); + idxd_wq_reset(wq); + + idxd_wq_free_resources(wq); + wq->client_count = 0; + + dev_info(dev, "wq %s disabled\n", dev_name(wq_confdev(wq))); +} + +void drv_disable_wq(struct idxd_wq *wq) +{ + mutex_lock(&wq->wq_lock); + __drv_disable_wq(wq); + mutex_unlock(&wq->wq_lock); +} diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h index 551a61fa1aff..e96ddbfc4569 100644 --- a/drivers/dma/idxd/idxd.h +++ b/drivers/dma/idxd/idxd.h @@ -496,6 +496,7 @@ void idxd_unmask_msix_vector(struct idxd_device *idxd, int vec_id); /* device control */ int drv_enable_wq(struct idxd_wq *wq); +void drv_disable_wq(struct idxd_wq *wq); int idxd_device_init_reset(struct idxd_device *idxd); int idxd_device_enable(struct idxd_device *idxd); int idxd_device_disable(struct idxd_device *idxd); diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c index 3e8cc07ebcdc..9967fad58a01 100644 --- a/drivers/dma/idxd/sysfs.c +++ b/drivers/dma/idxd/sysfs.c @@ -89,42 +89,6 @@ static int idxd_config_bus_probe(struct device *dev) return -ENODEV; } -static void disable_wq(struct idxd_wq *wq) -{ - struct idxd_device *idxd = wq->idxd; - struct device *dev = &idxd->pdev->dev; - - mutex_lock(&wq->wq_lock); - dev_dbg(dev, "%s removing WQ %s\n", __func__, dev_name(wq_confdev(wq))); - if (wq->state == IDXD_WQ_DISABLED) { - mutex_unlock(&wq->wq_lock); - return; - } - - if (wq->type == IDXD_WQT_KERNEL) - idxd_wq_quiesce(wq); - - if (is_idxd_wq_dmaengine(wq)) - idxd_unregister_dma_channel(wq); - else if (is_idxd_wq_cdev(wq)) - idxd_wq_del_cdev(wq); - - if (idxd_wq_refcount(wq)) - dev_warn(dev, "Clients has claim on wq %d: %d\n", - wq->id, idxd_wq_refcount(wq)); - - idxd_wq_unmap_portal(wq); - - idxd_wq_drain(wq); - idxd_wq_reset(wq); - - idxd_wq_free_resources(wq); - wq->client_count = 0; - mutex_unlock(&wq->wq_lock); - - dev_info(dev, "wq %s disabled\n", dev_name(wq_confdev(wq))); -} - static int idxd_config_bus_remove(struct device *dev) { dev_dbg(dev, "%s called for %s\n", __func__, dev_name(dev)); @@ -133,7 +97,7 @@ static int idxd_config_bus_remove(struct device *dev) if (is_idxd_wq_dev(dev)) { struct idxd_wq *wq = confdev_to_wq(dev); - disable_wq(wq); + drv_disable_wq(wq); } else if (is_idxd_dev(dev)) { struct idxd_device *idxd = confdev_to_idxd(dev); int i; From 3a5cc01647f07431b342e9703cda0542457ec467 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Thu, 15 Jul 2021 11:43:43 -0700 Subject: [PATCH 029/696] dmaengine: idxd: remove bus shutdown Remove ->shutdown() function for the dsa bus as it does not do anything and is not necessary. Reviewed-by: Dan Williams Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/162637462319.744545.10383189484257042066.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/sysfs.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c index 9967fad58a01..c3c869d8119a 100644 --- a/drivers/dma/idxd/sysfs.c +++ b/drivers/dma/idxd/sysfs.c @@ -126,17 +126,11 @@ static int idxd_config_bus_remove(struct device *dev) return 0; } -static void idxd_config_bus_shutdown(struct device *dev) -{ - dev_dbg(dev, "%s called\n", __func__); -} - struct bus_type dsa_bus_type = { .name = "dsa", .match = idxd_config_bus_match, .probe = idxd_config_bus_probe, .remove = idxd_config_bus_remove, - .shutdown = idxd_config_bus_shutdown, }; static struct idxd_device_driver dsa_drv = { From 1c264299431e9a105f3974ad49b6bccc3f03540f Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Thu, 15 Jul 2021 11:43:49 -0700 Subject: [PATCH 030/696] dmaengine: idxd: remove iax_bus_type prototype Remove unused iax_bus_type prototype declaration. Should have been removed when iax_bus_type was removed. Reviewed-by: Dan Williams Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/162637462909.744545.7106049898386277608.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/idxd.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h index e96ddbfc4569..4c3d3eb94450 100644 --- a/drivers/dma/idxd/idxd.h +++ b/drivers/dma/idxd/idxd.h @@ -370,7 +370,6 @@ static inline void idxd_dev_set_type(struct idxd_dev *idev, int type) } extern struct bus_type dsa_bus_type; -extern struct bus_type iax_bus_type; extern bool support_enqcmd; extern struct ida idxd_ida; From fcc2281b142bf14e3534d6b1150991194f8d1d44 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Thu, 15 Jul 2021 11:43:55 -0700 Subject: [PATCH 031/696] dmaengine: idxd: fix bus_probe() and bus_remove() for dsa_bus Current implementation have put all the code that should be in a driver probe/remove in the bus probe/remove function. Add ->probe() and ->remove() support for the dsa_drv and move all those code out of bus probe/remove. The change does not split out the distinction between device sub-driver and wq sub-driver. It only cleans up the bus calls. The split out will be addressed in follow on patches. Reviewed-by: Dan Williams Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/162637463586.744545.5806250155539938643.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/idxd.h | 24 +++++---- drivers/dma/idxd/sysfs.c | 112 ++++++++++++++++++++------------------- 2 files changed, 71 insertions(+), 65 deletions(-) diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h index 4c3d3eb94450..493958ecc208 100644 --- a/drivers/dma/idxd/idxd.h +++ b/drivers/dma/idxd/idxd.h @@ -51,6 +51,8 @@ enum idxd_type { struct idxd_device_driver { const char *name; + int (*probe)(struct idxd_dev *idxd_dev); + void (*remove)(struct idxd_dev *idxd_dev); struct device_driver drv; }; @@ -323,19 +325,21 @@ enum idxd_completion_status { #define cdev_dev(cdev) &cdev->idxd_dev.conf_dev #define confdev_to_idxd_dev(dev) container_of(dev, struct idxd_dev, conf_dev) +#define idxd_dev_to_idxd(idxd_dev) container_of(idxd_dev, struct idxd_device, idxd_dev) +#define idxd_dev_to_wq(idxd_dev) container_of(idxd_dev, struct idxd_wq, idxd_dev) static inline struct idxd_device *confdev_to_idxd(struct device *dev) { struct idxd_dev *idxd_dev = confdev_to_idxd_dev(dev); - return container_of(idxd_dev, struct idxd_device, idxd_dev); + return idxd_dev_to_idxd(idxd_dev); } static inline struct idxd_wq *confdev_to_wq(struct device *dev) { struct idxd_dev *idxd_dev = confdev_to_idxd_dev(dev); - return container_of(idxd_dev, struct idxd_wq, idxd_dev); + return idxd_dev_to_wq(idxd_dev); } static inline struct idxd_engine *confdev_to_engine(struct device *dev) @@ -379,24 +383,24 @@ extern struct device_type idxd_wq_device_type; extern struct device_type idxd_engine_device_type; extern struct device_type idxd_group_device_type; -static inline bool is_dsa_dev(struct device *dev) +static inline bool is_dsa_dev(struct idxd_dev *idxd_dev) { - return dev->type == &dsa_device_type; + return idxd_dev->type == IDXD_DEV_DSA; } -static inline bool is_iax_dev(struct device *dev) +static inline bool is_iax_dev(struct idxd_dev *idxd_dev) { - return dev->type == &iax_device_type; + return idxd_dev->type == IDXD_DEV_IAX; } -static inline bool is_idxd_dev(struct device *dev) +static inline bool is_idxd_dev(struct idxd_dev *idxd_dev) { - return is_dsa_dev(dev) || is_iax_dev(dev); + return is_dsa_dev(idxd_dev) || is_iax_dev(idxd_dev); } -static inline bool is_idxd_wq_dev(struct device *dev) +static inline bool is_idxd_wq_dev(struct idxd_dev *idxd_dev) { - return dev->type == &idxd_wq_device_type; + return idxd_dev->type == IDXD_DEV_WQ; } static inline bool is_idxd_wq_dmaengine(struct idxd_wq *wq) diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c index c3c869d8119a..f82416eec926 100644 --- a/drivers/dma/idxd/sysfs.c +++ b/drivers/dma/idxd/sysfs.c @@ -19,69 +19,80 @@ static char *idxd_wq_type_names[] = { static int idxd_config_bus_match(struct device *dev, struct device_driver *drv) { - int matched = 0; + struct idxd_dev *idxd_dev = confdev_to_idxd_dev(dev); - if (is_idxd_dev(dev)) { - matched = 1; - } else if (is_idxd_wq_dev(dev)) { - struct idxd_wq *wq = confdev_to_wq(dev); - - if (wq->state != IDXD_WQ_DISABLED) { - dev_dbg(dev, "%s not disabled\n", dev_name(dev)); - return 0; - } - matched = 1; - } - - if (matched) - dev_dbg(dev, "%s matched\n", dev_name(dev)); - - return matched; + return (is_idxd_dev(idxd_dev) || is_idxd_wq_dev(idxd_dev)); } static int idxd_config_bus_probe(struct device *dev) { - int rc = 0; + struct idxd_device_driver *idxd_drv = + container_of(dev->driver, struct idxd_device_driver, drv); + struct idxd_dev *idxd_dev = confdev_to_idxd_dev(dev); + + return idxd_drv->probe(idxd_dev); +} + +static int idxd_config_bus_remove(struct device *dev) +{ + struct idxd_device_driver *idxd_drv = + container_of(dev->driver, struct idxd_device_driver, drv); + struct idxd_dev *idxd_dev = confdev_to_idxd_dev(dev); + + idxd_drv->remove(idxd_dev); + return 0; +} + +struct bus_type dsa_bus_type = { + .name = "dsa", + .match = idxd_config_bus_match, + .probe = idxd_config_bus_probe, + .remove = idxd_config_bus_remove, +}; + +static int idxd_dsa_drv_probe(struct idxd_dev *idxd_dev) +{ + struct device *dev = &idxd_dev->conf_dev; unsigned long flags; + int rc; - dev_dbg(dev, "%s called\n", __func__); + if (is_idxd_dev(idxd_dev)) { + struct idxd_device *idxd = idxd_dev_to_idxd(idxd_dev); - if (is_idxd_dev(dev)) { - struct idxd_device *idxd = confdev_to_idxd(dev); - - if (!try_module_get(THIS_MODULE)) + if (idxd->state != IDXD_DEV_DISABLED) return -ENXIO; - /* Perform IDXD configuration and enabling */ + /* Device configuration */ spin_lock_irqsave(&idxd->dev_lock, flags); if (test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags)) rc = idxd_device_config(idxd); spin_unlock_irqrestore(&idxd->dev_lock, flags); if (rc < 0) { - module_put(THIS_MODULE); - dev_warn(dev, "Device config failed: %d\n", rc); + dev_dbg(dev, "Device config failed: %d\n", rc); return rc; } - /* start device */ + /* Start device */ rc = idxd_device_enable(idxd); if (rc < 0) { - module_put(THIS_MODULE); dev_warn(dev, "Device enable failed: %d\n", rc); return rc; } - dev_info(dev, "Device %s enabled\n", dev_name(dev)); - + /* Setup DMA device without channels */ rc = idxd_register_dma_device(idxd); if (rc < 0) { - module_put(THIS_MODULE); dev_dbg(dev, "Failed to register dmaengine device\n"); + idxd_device_disable(idxd); return rc; } + + dev_info(dev, "Device %s enabled\n", dev_name(dev)); return 0; - } else if (is_idxd_wq_dev(dev)) { - struct idxd_wq *wq = confdev_to_wq(dev); + } + + if (is_idxd_wq_dev(idxd_dev)) { + struct idxd_wq *wq = idxd_dev_to_wq(idxd_dev); return drv_enable_wq(wq); } @@ -89,21 +100,14 @@ static int idxd_config_bus_probe(struct device *dev) return -ENODEV; } -static int idxd_config_bus_remove(struct device *dev) +static void idxd_dsa_drv_remove(struct idxd_dev *idxd_dev) { - dev_dbg(dev, "%s called for %s\n", __func__, dev_name(dev)); + struct device *dev = &idxd_dev->conf_dev; - /* disable workqueue here */ - if (is_idxd_wq_dev(dev)) { - struct idxd_wq *wq = confdev_to_wq(dev); - - drv_disable_wq(wq); - } else if (is_idxd_dev(dev)) { - struct idxd_device *idxd = confdev_to_idxd(dev); + if (is_idxd_dev(idxd_dev)) { + struct idxd_device *idxd = idxd_dev_to_idxd(idxd_dev); int i; - dev_dbg(dev, "%s removing dev %s\n", __func__, - dev_name(idxd_confdev(idxd))); for (i = 0; i < idxd->max_wqs; i++) { struct idxd_wq *wq = idxd->wqs[i]; @@ -118,23 +122,21 @@ static int idxd_config_bus_remove(struct device *dev) idxd_device_disable(idxd); if (test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags)) idxd_device_reset(idxd); - module_put(THIS_MODULE); - - dev_info(dev, "Device %s disabled\n", dev_name(dev)); + return; } - return 0; -} + if (is_idxd_wq_dev(idxd_dev)) { + struct idxd_wq *wq = idxd_dev_to_wq(idxd_dev); -struct bus_type dsa_bus_type = { - .name = "dsa", - .match = idxd_config_bus_match, - .probe = idxd_config_bus_probe, - .remove = idxd_config_bus_remove, -}; + drv_disable_wq(wq); + return; + } +} static struct idxd_device_driver dsa_drv = { .name = "dsa", + .probe = idxd_dsa_drv_probe, + .remove = idxd_dsa_drv_remove, }; /* IDXD generic driver setup */ From bd42805b5da33b9c75f3ce0ae9d6ff0ec3f2cd6b Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Thu, 15 Jul 2021 11:44:01 -0700 Subject: [PATCH 032/696] dmaengine: idxd: move probe() bits for idxd 'struct device' to device.c Move the code related to a ->probe() function for the idxd 'struct device' to device.c to prep for the idxd device sub-driver in device.c. Reviewed-by: Dan Williams Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/162637464189.744545.17423830646786162194.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/device.c | 37 ++++++++++++++++++++++++++++++++++++ drivers/dma/idxd/idxd.h | 1 + drivers/dma/idxd/sysfs.c | 40 ++------------------------------------- 3 files changed, 40 insertions(+), 38 deletions(-) diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c index 8d8e249931a9..b9aa209efee4 100644 --- a/drivers/dma/idxd/device.c +++ b/drivers/dma/idxd/device.c @@ -1290,3 +1290,40 @@ void drv_disable_wq(struct idxd_wq *wq) __drv_disable_wq(wq); mutex_unlock(&wq->wq_lock); } + +int idxd_device_drv_probe(struct idxd_dev *idxd_dev) +{ + struct idxd_device *idxd = idxd_dev_to_idxd(idxd_dev); + unsigned long flags; + int rc = 0; + + /* + * Device should be in disabled state for the idxd_drv to load. If it's in + * enabled state, then the device was altered outside of driver's control. + * If the state is in halted state, then we don't want to proceed. + */ + if (idxd->state != IDXD_DEV_DISABLED) + return -ENXIO; + + /* Device configuration */ + spin_lock_irqsave(&idxd->dev_lock, flags); + if (test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags)) + rc = idxd_device_config(idxd); + spin_unlock_irqrestore(&idxd->dev_lock, flags); + if (rc < 0) + return -ENXIO; + + /* Start device */ + rc = idxd_device_enable(idxd); + if (rc < 0) + return rc; + + /* Setup DMA device without channels */ + rc = idxd_register_dma_device(idxd); + if (rc < 0) { + idxd_device_disable(idxd); + return rc; + } + + return 0; +} diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h index 493958ecc208..dbbd36feb462 100644 --- a/drivers/dma/idxd/idxd.h +++ b/drivers/dma/idxd/idxd.h @@ -498,6 +498,7 @@ void idxd_mask_msix_vector(struct idxd_device *idxd, int vec_id); void idxd_unmask_msix_vector(struct idxd_device *idxd, int vec_id); /* device control */ +int idxd_device_drv_probe(struct idxd_dev *idxd_dev); int drv_enable_wq(struct idxd_wq *wq); void drv_disable_wq(struct idxd_wq *wq); int idxd_device_init_reset(struct idxd_device *idxd); diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c index f82416eec926..221a61e3bb9c 100644 --- a/drivers/dma/idxd/sysfs.c +++ b/drivers/dma/idxd/sysfs.c @@ -52,44 +52,8 @@ struct bus_type dsa_bus_type = { static int idxd_dsa_drv_probe(struct idxd_dev *idxd_dev) { - struct device *dev = &idxd_dev->conf_dev; - unsigned long flags; - int rc; - - if (is_idxd_dev(idxd_dev)) { - struct idxd_device *idxd = idxd_dev_to_idxd(idxd_dev); - - if (idxd->state != IDXD_DEV_DISABLED) - return -ENXIO; - - /* Device configuration */ - spin_lock_irqsave(&idxd->dev_lock, flags); - if (test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags)) - rc = idxd_device_config(idxd); - spin_unlock_irqrestore(&idxd->dev_lock, flags); - if (rc < 0) { - dev_dbg(dev, "Device config failed: %d\n", rc); - return rc; - } - - /* Start device */ - rc = idxd_device_enable(idxd); - if (rc < 0) { - dev_warn(dev, "Device enable failed: %d\n", rc); - return rc; - } - - /* Setup DMA device without channels */ - rc = idxd_register_dma_device(idxd); - if (rc < 0) { - dev_dbg(dev, "Failed to register dmaengine device\n"); - idxd_device_disable(idxd); - return rc; - } - - dev_info(dev, "Device %s enabled\n", dev_name(dev)); - return 0; - } + if (is_idxd_dev(idxd_dev)) + return idxd_device_drv_probe(idxd_dev); if (is_idxd_wq_dev(idxd_dev)) { struct idxd_wq *wq = idxd_dev_to_wq(idxd_dev); From 745e92a6d816277fcbd231bda5ad2d882b22fe52 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Thu, 15 Jul 2021 11:44:07 -0700 Subject: [PATCH 033/696] dmaengine: idxd: idxd: move remove() bits for idxd 'struct device' to device.c Move the code related to a ->remove() function for the idxd 'struct device' to device.c to prep for the idxd device sub-driver in device.c. Reviewed-by: Dan Williams Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/162637464768.744545.15797285510999151668.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/device.c | 22 ++++++++++++++++++++++ drivers/dma/idxd/idxd.h | 1 + drivers/dma/idxd/sysfs.c | 20 +------------------- 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c index b9aa209efee4..d5a0b6fff3b9 100644 --- a/drivers/dma/idxd/device.c +++ b/drivers/dma/idxd/device.c @@ -1327,3 +1327,25 @@ int idxd_device_drv_probe(struct idxd_dev *idxd_dev) return 0; } + +void idxd_device_drv_remove(struct idxd_dev *idxd_dev) +{ + struct device *dev = &idxd_dev->conf_dev; + struct idxd_device *idxd = idxd_dev_to_idxd(idxd_dev); + int i; + + for (i = 0; i < idxd->max_wqs; i++) { + struct idxd_wq *wq = idxd->wqs[i]; + struct device *wq_dev = wq_confdev(wq); + + if (wq->state == IDXD_WQ_DISABLED) + continue; + dev_warn(dev, "Active wq %d on disable %s.\n", i, dev_name(wq_dev)); + device_release_driver(wq_dev); + } + + idxd_unregister_dma_device(idxd); + idxd_device_disable(idxd); + if (test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags)) + idxd_device_reset(idxd); +} diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h index dbbd36feb462..1c8abba13470 100644 --- a/drivers/dma/idxd/idxd.h +++ b/drivers/dma/idxd/idxd.h @@ -499,6 +499,7 @@ void idxd_unmask_msix_vector(struct idxd_device *idxd, int vec_id); /* device control */ int idxd_device_drv_probe(struct idxd_dev *idxd_dev); +void idxd_device_drv_remove(struct idxd_dev *idxd_dev); int drv_enable_wq(struct idxd_wq *wq); void drv_disable_wq(struct idxd_wq *wq); int idxd_device_init_reset(struct idxd_device *idxd); diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c index 221a61e3bb9c..abea8aca6799 100644 --- a/drivers/dma/idxd/sysfs.c +++ b/drivers/dma/idxd/sysfs.c @@ -66,26 +66,8 @@ static int idxd_dsa_drv_probe(struct idxd_dev *idxd_dev) static void idxd_dsa_drv_remove(struct idxd_dev *idxd_dev) { - struct device *dev = &idxd_dev->conf_dev; - if (is_idxd_dev(idxd_dev)) { - struct idxd_device *idxd = idxd_dev_to_idxd(idxd_dev); - int i; - - for (i = 0; i < idxd->max_wqs; i++) { - struct idxd_wq *wq = idxd->wqs[i]; - - if (wq->state == IDXD_WQ_DISABLED) - continue; - dev_warn(dev, "Active wq %d on disable %s.\n", i, - dev_name(wq_confdev(wq))); - device_release_driver(wq_confdev(wq)); - } - - idxd_unregister_dma_device(idxd); - idxd_device_disable(idxd); - if (test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags)) - idxd_device_reset(idxd); + idxd_device_drv_remove(idxd_dev); return; } From c05257b5600bb35a580ecdb25695efff26326d59 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Thu, 15 Jul 2021 11:44:13 -0700 Subject: [PATCH 034/696] dmanegine: idxd: open code the dsa_drv registration Don't need a wrapper to register the driver. Just do it directly. Reviewed-by: Dan Williams Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/162637465319.744545.16325178432532362906.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/idxd.h | 2 ++ drivers/dma/idxd/init.c | 10 +++++----- drivers/dma/idxd/sysfs.c | 13 +------------ 3 files changed, 8 insertions(+), 17 deletions(-) diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h index 1c8abba13470..7fc26b7727c0 100644 --- a/drivers/dma/idxd/idxd.h +++ b/drivers/dma/idxd/idxd.h @@ -56,6 +56,8 @@ struct idxd_device_driver { struct device_driver drv; }; +extern struct idxd_device_driver dsa_drv; + struct idxd_irq_entry { struct idxd_device *idxd; int id; diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c index c22225b14c5d..5b628e6c04bf 100644 --- a/drivers/dma/idxd/init.c +++ b/drivers/dma/idxd/init.c @@ -840,9 +840,9 @@ static int __init idxd_init_module(void) if (err < 0) return err; - err = idxd_register_driver(); + err = idxd_driver_register(&dsa_drv); if (err < 0) - goto err_idxd_driver_register; + goto err_dsa_driver_register; err = idxd_cdev_register(); if (err) @@ -857,8 +857,8 @@ static int __init idxd_init_module(void) err_pci_register: idxd_cdev_remove(); err_cdev_register: - idxd_unregister_driver(); -err_idxd_driver_register: + idxd_driver_unregister(&dsa_drv); +err_dsa_driver_register: idxd_unregister_bus_type(); return err; } @@ -866,7 +866,7 @@ module_init(idxd_init_module); static void __exit idxd_exit_module(void) { - idxd_unregister_driver(); + idxd_driver_unregister(&dsa_drv); pci_unregister_driver(&idxd_pci_driver); idxd_cdev_remove(); idxd_unregister_bus_type(); diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c index abea8aca6799..9f2d06c2aa98 100644 --- a/drivers/dma/idxd/sysfs.c +++ b/drivers/dma/idxd/sysfs.c @@ -79,23 +79,12 @@ static void idxd_dsa_drv_remove(struct idxd_dev *idxd_dev) } } -static struct idxd_device_driver dsa_drv = { +struct idxd_device_driver dsa_drv = { .name = "dsa", .probe = idxd_dsa_drv_probe, .remove = idxd_dsa_drv_remove, }; -/* IDXD generic driver setup */ -int idxd_register_driver(void) -{ - return idxd_driver_register(&dsa_drv); -} - -void idxd_unregister_driver(void) -{ - idxd_driver_unregister(&dsa_drv); -} - /* IDXD engine attributes */ static ssize_t engine_group_id_show(struct device *dev, struct device_attribute *attr, char *buf) From 5fee6567ec387088ec965ee60c63051bbe102cac Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Thu, 15 Jul 2021 11:44:18 -0700 Subject: [PATCH 035/696] dmaengine: idxd: add type to driver in order to allow device matching Add an array of support device types to the idxd_device_driver definition in order to enable simple matching of device type to a given driver. The deprecated / omnibus dsa_drv driver specifies IDXD_DEV_NONE as its only role is to service legacy userspace (old accel-config) directed bind requests and route them to them the proper driver. It need not attach to a device when the bus is autoprobed. The accel-config tooling is being updated to drop its dependency on this deprecated bind scheme. Reviewed-by: Dan Willliams Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/162637465882.744545.17456174666211577867.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/idxd.h | 1 + drivers/dma/idxd/init.c | 5 +++++ drivers/dma/idxd/sysfs.c | 16 +++++++++++++++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h index 7fc26b7727c0..4bb5a65ec237 100644 --- a/drivers/dma/idxd/idxd.h +++ b/drivers/dma/idxd/idxd.h @@ -51,6 +51,7 @@ enum idxd_type { struct idxd_device_driver { const char *name; + enum idxd_dev_type *type; int (*probe)(struct idxd_dev *idxd_dev); void (*remove)(struct idxd_dev *idxd_dev); struct device_driver drv; diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c index 5b628e6c04bf..544ff7137292 100644 --- a/drivers/dma/idxd/init.c +++ b/drivers/dma/idxd/init.c @@ -879,6 +879,11 @@ int __idxd_driver_register(struct idxd_device_driver *idxd_drv, struct module *o { struct device_driver *drv = &idxd_drv->drv; + if (!idxd_drv->type) { + pr_debug("driver type not set (%ps)\n", __builtin_return_address(0)); + return -EINVAL; + } + drv->name = idxd_drv->name; drv->bus = &dsa_bus_type; drv->owner = owner; diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c index 9f2d06c2aa98..8d48903df131 100644 --- a/drivers/dma/idxd/sysfs.c +++ b/drivers/dma/idxd/sysfs.c @@ -19,9 +19,18 @@ static char *idxd_wq_type_names[] = { static int idxd_config_bus_match(struct device *dev, struct device_driver *drv) { + struct idxd_device_driver *idxd_drv = + container_of(drv, struct idxd_device_driver, drv); struct idxd_dev *idxd_dev = confdev_to_idxd_dev(dev); + int i = 0; - return (is_idxd_dev(idxd_dev) || is_idxd_wq_dev(idxd_dev)); + while (idxd_drv->type[i] != IDXD_DEV_NONE) { + if (idxd_dev->type == idxd_drv->type[i]) + return 1; + i++; + } + + return 0; } static int idxd_config_bus_probe(struct device *dev) @@ -79,10 +88,15 @@ static void idxd_dsa_drv_remove(struct idxd_dev *idxd_dev) } } +static enum idxd_dev_type dev_types[] = { + IDXD_DEV_NONE, +}; + struct idxd_device_driver dsa_drv = { .name = "dsa", .probe = idxd_dsa_drv_probe, .remove = idxd_dsa_drv_remove, + .type = dev_types, }; /* IDXD engine attributes */ From 034b3290ba257f1a3c8730f3fba72e11645e7b50 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Thu, 15 Jul 2021 11:44:24 -0700 Subject: [PATCH 036/696] dmaengine: idxd: create idxd_device sub-driver The original architecture of /sys/bus/dsa invented a scheme whereby a single entry in the list of bus drivers, /sys/bus/drivers/dsa, handled all device types and internally routed them to different drivers. Those internal drivers were invisible to userspace. Now, as /sys/bus/dsa wants to grow support for alternate drivers for a given device, for example vfio-mdev instead of kernel-internal-dmaengine, a proper bus device-driver model is needed. The first step in that process is separating the existing omnibus/implicit "dsa" driver into proper individual drivers registered on /sys/bus/dsa. Establish the idxd_drv driver that control the enabling and disabling of the accelerator device. Reviewed-by: Dan Williams Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/162637466439.744545.15210886092627144577.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/device.c | 13 +++++++++++++ drivers/dma/idxd/idxd.h | 3 +++ drivers/dma/idxd/init.c | 7 +++++++ 3 files changed, 23 insertions(+) diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c index d5a0b6fff3b9..12ae3f1639f1 100644 --- a/drivers/dma/idxd/device.c +++ b/drivers/dma/idxd/device.c @@ -1349,3 +1349,16 @@ void idxd_device_drv_remove(struct idxd_dev *idxd_dev) if (test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags)) idxd_device_reset(idxd); } + +static enum idxd_dev_type dev_types[] = { + IDXD_DEV_DSA, + IDXD_DEV_IAX, + IDXD_DEV_NONE, +}; + +struct idxd_device_driver idxd_drv = { + .type = dev_types, + .probe = idxd_device_drv_probe, + .remove = idxd_device_drv_remove, + .name = "idxd", +}; diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h index 4bb5a65ec237..a356d227f755 100644 --- a/drivers/dma/idxd/idxd.h +++ b/drivers/dma/idxd/idxd.h @@ -58,6 +58,7 @@ struct idxd_device_driver { }; extern struct idxd_device_driver dsa_drv; +extern struct idxd_device_driver idxd_drv; struct idxd_irq_entry { struct idxd_device *idxd; @@ -501,6 +502,8 @@ void idxd_mask_msix_vector(struct idxd_device *idxd, int vec_id); void idxd_unmask_msix_vector(struct idxd_device *idxd, int vec_id); /* device control */ +int idxd_register_idxd_drv(void); +void idxd_unregister_idxd_drv(void); int idxd_device_drv_probe(struct idxd_dev *idxd_dev); void idxd_device_drv_remove(struct idxd_dev *idxd_dev); int drv_enable_wq(struct idxd_wq *wq); diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c index 544ff7137292..c19b03c17ab9 100644 --- a/drivers/dma/idxd/init.c +++ b/drivers/dma/idxd/init.c @@ -840,6 +840,10 @@ static int __init idxd_init_module(void) if (err < 0) return err; + err = idxd_driver_register(&idxd_drv); + if (err < 0) + goto err_idxd_driver_register; + err = idxd_driver_register(&dsa_drv); if (err < 0) goto err_dsa_driver_register; @@ -859,6 +863,8 @@ err_pci_register: err_cdev_register: idxd_driver_unregister(&dsa_drv); err_dsa_driver_register: + idxd_driver_unregister(&idxd_drv); +err_idxd_driver_register: idxd_unregister_bus_type(); return err; } @@ -866,6 +872,7 @@ module_init(idxd_init_module); static void __exit idxd_exit_module(void) { + idxd_driver_unregister(&idxd_drv); idxd_driver_unregister(&dsa_drv); pci_unregister_driver(&idxd_pci_driver); idxd_cdev_remove(); From 0cda4f6986a3824cac500f66326ff267bf37110f Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Thu, 15 Jul 2021 11:44:30 -0700 Subject: [PATCH 037/696] dmaengine: idxd: create dmaengine driver for wq 'device' The original architecture of /sys/bus/dsa invented a scheme whereby a single entry in the list of bus drivers, /sys/bus/drivers/dsa, handled all device types and internally routed them to different drivers. Those internal drivers were invisible to userspace. Now, as /sys/bus/dsa wants to grow support for alternate drivers for a given device, for example vfio-mdev instead of kernel-internal-dmaengine, a proper bus device-driver model is needed. The first step in that process is separating the existing omnibus/implicit "dsa" driver into proper individual drivers registered on /sys/bus/dsa. Establish the idxd_dmaengine_drv driver that controls the enabling and disabling of the wq and also register and unregister the dma channel. idxd_wq_alloc_resources() and idxd_wq_free_resources() also get moved to the dmaengine driver. The resources (dma descriptors allocation and setup) are only used by the dmaengine driver and should only happen when it loads. The char dev driver (cdev) related bits are left in the __drv_enable_wq() and __drv_disable_wq() calls to be moved when we split out the char dev driver just like how the dmaengine driver is split out. WQ autoload support is not expected currently. With the amount of configuration needed for the device, the wq is always expected to be enabled by a tool (or via sysfs) rather than auto enabled at driver load. Reviewed-by: Dan Williams Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/162637467033.744545.12330636655625405394.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/device.c | 40 +++----------------- drivers/dma/idxd/dma.c | 77 +++++++++++++++++++++++++++++++++++++++ drivers/dma/idxd/idxd.h | 3 ++ drivers/dma/idxd/init.c | 7 ++++ 4 files changed, 92 insertions(+), 35 deletions(-) diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c index 12ae3f1639f1..4dcc9431ae3d 100644 --- a/drivers/dma/idxd/device.c +++ b/drivers/dma/idxd/device.c @@ -1130,7 +1130,7 @@ int idxd_device_load_config(struct idxd_device *idxd) return 0; } -static int __drv_enable_wq(struct idxd_wq *wq) +int __drv_enable_wq(struct idxd_wq *wq) { struct idxd_device *idxd = wq->idxd; struct device *dev = &idxd->pdev->dev; @@ -1178,12 +1178,7 @@ static int __drv_enable_wq(struct idxd_wq *wq) } } - rc = idxd_wq_alloc_resources(wq); - if (rc < 0) { - dev_dbg(dev, "wq resource alloc failed\n"); - goto err; - } - + rc = 0; spin_lock_irqsave(&idxd->dev_lock, flags); if (test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags)) rc = idxd_device_config(idxd); @@ -1207,21 +1202,7 @@ static int __drv_enable_wq(struct idxd_wq *wq) wq->client_count = 0; - if (wq->type == IDXD_WQT_KERNEL) { - rc = idxd_wq_init_percpu_ref(wq); - if (rc < 0) { - dev_dbg(dev, "wq %d percpu_ref setup failed\n", wq->id); - goto err_cpu_ref; - } - } - - if (is_idxd_wq_dmaengine(wq)) { - rc = idxd_register_dma_channel(wq); - if (rc < 0) { - dev_dbg(dev, "wq %d DMA channel register failed\n", wq->id); - goto err_client; - } - } else if (is_idxd_wq_cdev(wq)) { + if (is_idxd_wq_cdev(wq)) { rc = idxd_wq_add_cdev(wq); if (rc < 0) { dev_dbg(dev, "wq %d cdev creation failed\n", wq->id); @@ -1229,12 +1210,9 @@ static int __drv_enable_wq(struct idxd_wq *wq) } } - dev_info(dev, "wq %s enabled\n", dev_name(wq_confdev(wq))); return 0; err_client: - idxd_wq_quiesce(wq); -err_cpu_ref: idxd_wq_unmap_portal(wq); err_map_portal: rc = idxd_wq_disable(wq, false); @@ -1254,19 +1232,14 @@ int drv_enable_wq(struct idxd_wq *wq) return rc; } -static void __drv_disable_wq(struct idxd_wq *wq) +void __drv_disable_wq(struct idxd_wq *wq) { struct idxd_device *idxd = wq->idxd; struct device *dev = &idxd->pdev->dev; lockdep_assert_held(&wq->wq_lock); - if (wq->type == IDXD_WQT_KERNEL) - idxd_wq_quiesce(wq); - - if (is_idxd_wq_dmaengine(wq)) - idxd_unregister_dma_channel(wq); - else if (is_idxd_wq_cdev(wq)) + if (is_idxd_wq_cdev(wq)) idxd_wq_del_cdev(wq); if (idxd_wq_refcount(wq)) @@ -1278,10 +1251,7 @@ static void __drv_disable_wq(struct idxd_wq *wq) idxd_wq_drain(wq); idxd_wq_reset(wq); - idxd_wq_free_resources(wq); wq->client_count = 0; - - dev_info(dev, "wq %s disabled\n", dev_name(wq_confdev(wq))); } void drv_disable_wq(struct idxd_wq *wq) diff --git a/drivers/dma/idxd/dma.c b/drivers/dma/idxd/dma.c index 2e52f9a50519..7e3281700183 100644 --- a/drivers/dma/idxd/dma.c +++ b/drivers/dma/idxd/dma.c @@ -262,3 +262,80 @@ void idxd_unregister_dma_channel(struct idxd_wq *wq) wq->idxd_chan = NULL; put_device(wq_confdev(wq)); } + +static int idxd_dmaengine_drv_probe(struct idxd_dev *idxd_dev) +{ + struct device *dev = &idxd_dev->conf_dev; + struct idxd_wq *wq = idxd_dev_to_wq(idxd_dev); + struct idxd_device *idxd = wq->idxd; + int rc; + + if (idxd->state != IDXD_DEV_ENABLED) + return -ENXIO; + + mutex_lock(&wq->wq_lock); + wq->type = IDXD_WQT_KERNEL; + rc = __drv_enable_wq(wq); + if (rc < 0) { + dev_dbg(dev, "Enable wq %d failed: %d\n", wq->id, rc); + rc = -ENXIO; + goto err; + } + + rc = idxd_wq_alloc_resources(wq); + if (rc < 0) { + dev_dbg(dev, "WQ resource alloc failed\n"); + goto err_res_alloc; + } + + rc = idxd_wq_init_percpu_ref(wq); + if (rc < 0) { + dev_dbg(dev, "percpu_ref setup failed\n"); + goto err_ref; + } + + rc = idxd_register_dma_channel(wq); + if (rc < 0) { + dev_dbg(dev, "Failed to register dma channel\n"); + goto err_dma; + } + + mutex_unlock(&wq->wq_lock); + return 0; + +err_dma: + idxd_wq_quiesce(wq); +err_ref: + idxd_wq_free_resources(wq); +err_res_alloc: + __drv_disable_wq(wq); +err: + wq->type = IDXD_WQT_NONE; + mutex_unlock(&wq->wq_lock); + return rc; +} + +static void idxd_dmaengine_drv_remove(struct idxd_dev *idxd_dev) +{ + struct idxd_wq *wq = idxd_dev_to_wq(idxd_dev); + + mutex_lock(&wq->wq_lock); + idxd_wq_quiesce(wq); + idxd_unregister_dma_channel(wq); + __drv_disable_wq(wq); + idxd_wq_free_resources(wq); + wq->type = IDXD_WQT_NONE; + mutex_unlock(&wq->wq_lock); +} + +static enum idxd_dev_type dev_types[] = { + IDXD_DEV_WQ, + IDXD_DEV_NONE, +}; + +struct idxd_device_driver idxd_dmaengine_drv = { + .probe = idxd_dmaengine_drv_probe, + .remove = idxd_dmaengine_drv_remove, + .name = "dmaengine", + .type = dev_types, +}; diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h index a356d227f755..a840c328bec9 100644 --- a/drivers/dma/idxd/idxd.h +++ b/drivers/dma/idxd/idxd.h @@ -59,6 +59,7 @@ struct idxd_device_driver { extern struct idxd_device_driver dsa_drv; extern struct idxd_device_driver idxd_drv; +extern struct idxd_device_driver idxd_dmaengine_drv; struct idxd_irq_entry { struct idxd_device *idxd; @@ -507,7 +508,9 @@ void idxd_unregister_idxd_drv(void); int idxd_device_drv_probe(struct idxd_dev *idxd_dev); void idxd_device_drv_remove(struct idxd_dev *idxd_dev); int drv_enable_wq(struct idxd_wq *wq); +int __drv_enable_wq(struct idxd_wq *wq); void drv_disable_wq(struct idxd_wq *wq); +void __drv_disable_wq(struct idxd_wq *wq); int idxd_device_init_reset(struct idxd_device *idxd); int idxd_device_enable(struct idxd_device *idxd); int idxd_device_disable(struct idxd_device *idxd); diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c index c19b03c17ab9..6f38128ce400 100644 --- a/drivers/dma/idxd/init.c +++ b/drivers/dma/idxd/init.c @@ -844,6 +844,10 @@ static int __init idxd_init_module(void) if (err < 0) goto err_idxd_driver_register; + err = idxd_driver_register(&idxd_dmaengine_drv); + if (err < 0) + goto err_idxd_dmaengine_driver_register; + err = idxd_driver_register(&dsa_drv); if (err < 0) goto err_dsa_driver_register; @@ -863,6 +867,8 @@ err_pci_register: err_cdev_register: idxd_driver_unregister(&dsa_drv); err_dsa_driver_register: + idxd_driver_unregister(&idxd_dmaengine_drv); +err_idxd_dmaengine_driver_register: idxd_driver_unregister(&idxd_drv); err_idxd_driver_register: idxd_unregister_bus_type(); @@ -872,6 +878,7 @@ module_init(idxd_init_module); static void __exit idxd_exit_module(void) { + idxd_driver_unregister(&idxd_dmaengine_drv); idxd_driver_unregister(&idxd_drv); idxd_driver_unregister(&dsa_drv); pci_unregister_driver(&idxd_pci_driver); From 448c3de8ac8353fc4447738ae3c56c4eb6c2131d Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Thu, 15 Jul 2021 11:44:35 -0700 Subject: [PATCH 038/696] dmaengine: idxd: create user driver for wq 'device' The original architecture of /sys/bus/dsa invented a scheme whereby a single entry in the list of bus drivers, /sys/bus/drivers/dsa, handled all device types and internally routed them to different drivers. Those internal drivers were invisible to userspace. Now, as /sys/bus/dsa wants to grow support for alternate drivers for a given device, for example vfio-mdev instead of kernel-internal-dmaengine, a proper bus device-driver model is needed. The first step in that process is separating the existing omnibus/implicit "dsa" driver into proper individual drivers registered on /sys/bus/dsa. Establish the idxd_user_drv driver that controls the enabling and disabling of the wq and also register and unregister a char device to allow user space to mmap the descriptor submission portal. The cdev related bits are moved to the cdev driver probe/remove and out of the drv_enabe/disable_wq() calls. These bits are exclusive to the cdev operation and not part of the generic enable/disable of the wq device. Reviewed-by: Dan Williams Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/162637467578.744545.10203997610072341376.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/cdev.c | 53 +++++++++++++++++++++++++++++++++++++++ drivers/dma/idxd/device.c | 14 ----------- drivers/dma/idxd/idxd.h | 1 + drivers/dma/idxd/init.c | 7 ++++++ 4 files changed, 61 insertions(+), 14 deletions(-) diff --git a/drivers/dma/idxd/cdev.c b/drivers/dma/idxd/cdev.c index 18a003b93812..b67bbf24242a 100644 --- a/drivers/dma/idxd/cdev.c +++ b/drivers/dma/idxd/cdev.c @@ -304,6 +304,59 @@ void idxd_wq_del_cdev(struct idxd_wq *wq) put_device(cdev_dev(idxd_cdev)); } +static int idxd_user_drv_probe(struct idxd_dev *idxd_dev) +{ + struct idxd_wq *wq = idxd_dev_to_wq(idxd_dev); + struct idxd_device *idxd = wq->idxd; + int rc; + + if (idxd->state != IDXD_DEV_ENABLED) + return -ENXIO; + + mutex_lock(&wq->wq_lock); + wq->type = IDXD_WQT_USER; + rc = __drv_enable_wq(wq); + if (rc < 0) + goto err; + + rc = idxd_wq_add_cdev(wq); + if (rc < 0) + goto err_cdev; + + mutex_unlock(&wq->wq_lock); + return 0; + +err_cdev: + __drv_disable_wq(wq); +err: + wq->type = IDXD_WQT_NONE; + mutex_unlock(&wq->wq_lock); + return rc; +} + +static void idxd_user_drv_remove(struct idxd_dev *idxd_dev) +{ + struct idxd_wq *wq = idxd_dev_to_wq(idxd_dev); + + mutex_lock(&wq->wq_lock); + idxd_wq_del_cdev(wq); + __drv_disable_wq(wq); + wq->type = IDXD_WQT_NONE; + mutex_unlock(&wq->wq_lock); +} + +static enum idxd_dev_type dev_types[] = { + IDXD_DEV_WQ, + IDXD_DEV_NONE, +}; + +struct idxd_device_driver idxd_user_drv = { + .probe = idxd_user_drv_probe, + .remove = idxd_user_drv_remove, + .name = "user", + .type = dev_types, +}; + int idxd_cdev_register(void) { int rc, i; diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c index 4dcc9431ae3d..9bbc28d9a9eb 100644 --- a/drivers/dma/idxd/device.c +++ b/drivers/dma/idxd/device.c @@ -1201,19 +1201,8 @@ int __drv_enable_wq(struct idxd_wq *wq) } wq->client_count = 0; - - if (is_idxd_wq_cdev(wq)) { - rc = idxd_wq_add_cdev(wq); - if (rc < 0) { - dev_dbg(dev, "wq %d cdev creation failed\n", wq->id); - goto err_client; - } - } - return 0; -err_client: - idxd_wq_unmap_portal(wq); err_map_portal: rc = idxd_wq_disable(wq, false); if (rc < 0) @@ -1239,9 +1228,6 @@ void __drv_disable_wq(struct idxd_wq *wq) lockdep_assert_held(&wq->wq_lock); - if (is_idxd_wq_cdev(wq)) - idxd_wq_del_cdev(wq); - if (idxd_wq_refcount(wq)) dev_warn(dev, "Clients has claim on wq %d: %d\n", wq->id, idxd_wq_refcount(wq)); diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h index a840c328bec9..bacec9b93a7e 100644 --- a/drivers/dma/idxd/idxd.h +++ b/drivers/dma/idxd/idxd.h @@ -60,6 +60,7 @@ struct idxd_device_driver { extern struct idxd_device_driver dsa_drv; extern struct idxd_device_driver idxd_drv; extern struct idxd_device_driver idxd_dmaengine_drv; +extern struct idxd_device_driver idxd_user_drv; struct idxd_irq_entry { struct idxd_device *idxd; diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c index 6f38128ce400..33a80f700ff8 100644 --- a/drivers/dma/idxd/init.c +++ b/drivers/dma/idxd/init.c @@ -848,6 +848,10 @@ static int __init idxd_init_module(void) if (err < 0) goto err_idxd_dmaengine_driver_register; + err = idxd_driver_register(&idxd_user_drv); + if (err < 0) + goto err_idxd_user_driver_register; + err = idxd_driver_register(&dsa_drv); if (err < 0) goto err_dsa_driver_register; @@ -867,6 +871,8 @@ err_pci_register: err_cdev_register: idxd_driver_unregister(&dsa_drv); err_dsa_driver_register: + idxd_driver_unregister(&idxd_user_drv); +err_idxd_user_driver_register: idxd_driver_unregister(&idxd_dmaengine_drv); err_idxd_dmaengine_driver_register: idxd_driver_unregister(&idxd_drv); @@ -878,6 +884,7 @@ module_init(idxd_init_module); static void __exit idxd_exit_module(void) { + idxd_driver_unregister(&idxd_user_drv); idxd_driver_unregister(&idxd_dmaengine_drv); idxd_driver_unregister(&idxd_drv); idxd_driver_unregister(&dsa_drv); From d9e5481fca74f870cf2fc2f90a0e77e85c0b5b86 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Thu, 15 Jul 2021 11:44:41 -0700 Subject: [PATCH 039/696] dmaengine: dsa: move dsa_bus_type out of idxd driver to standalone In preparation for dsa_drv compat support to be built-in, move the bus code to its own compilation unit. A follow-on patch adds the compat implementation. Recall that the compat implementation allows for the deprecated / omnibus dsa_drv binding scheme rather than the idiomatic organization of a full fledged bus driver per driver type. Reviewed-by: Dan Williams Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/162637468142.744545.2811632736881720857.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul --- drivers/dma/Kconfig | 4 ++ drivers/dma/Makefile | 2 +- drivers/dma/idxd/Makefile | 5 +++ drivers/dma/idxd/bus.c | 92 +++++++++++++++++++++++++++++++++++++++ drivers/dma/idxd/init.c | 30 +------------ drivers/dma/idxd/sysfs.c | 43 ------------------ 6 files changed, 103 insertions(+), 73 deletions(-) create mode 100644 drivers/dma/idxd/bus.c diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index f450e4231db7..d7101bff1772 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -277,6 +277,10 @@ config INTEL_IDMA64 Enable DMA support for Intel Low Power Subsystem such as found on Intel Skylake PCH. +config INTEL_IDXD_BUS + tristate + default INTEL_IDXD + config INTEL_IDXD tristate "Intel Data Accelerators support" depends on PCI && X86_64 && !UML diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index aa69094e3547..13b5258d04ea 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -41,7 +41,7 @@ obj-$(CONFIG_IMX_DMA) += imx-dma.o obj-$(CONFIG_IMX_SDMA) += imx-sdma.o obj-$(CONFIG_INTEL_IDMA64) += idma64.o obj-$(CONFIG_INTEL_IOATDMA) += ioat/ -obj-$(CONFIG_INTEL_IDXD) += idxd/ +obj-y += idxd/ obj-$(CONFIG_INTEL_IOP_ADMA) += iop-adma.o obj-$(CONFIG_K3_DMA) += k3dma.o obj-$(CONFIG_LPC18XX_DMAMUX) += lpc18xx-dmamux.o diff --git a/drivers/dma/idxd/Makefile b/drivers/dma/idxd/Makefile index 6d11558756f8..8c29ed4d48c3 100644 --- a/drivers/dma/idxd/Makefile +++ b/drivers/dma/idxd/Makefile @@ -1,4 +1,9 @@ +ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=IDXD + obj-$(CONFIG_INTEL_IDXD) += idxd.o idxd-y := init.o irq.o device.o sysfs.o submit.o dma.o cdev.o idxd-$(CONFIG_INTEL_IDXD_PERFMON) += perfmon.o + +obj-$(CONFIG_INTEL_IDXD_BUS) += idxd_bus.o +idxd_bus-y := bus.o diff --git a/drivers/dma/idxd/bus.c b/drivers/dma/idxd/bus.c new file mode 100644 index 000000000000..02837f0fb3e4 --- /dev/null +++ b/drivers/dma/idxd/bus.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2021 Intel Corporation. All rights rsvd. */ +#include +#include +#include +#include +#include "idxd.h" + + +int __idxd_driver_register(struct idxd_device_driver *idxd_drv, struct module *owner, + const char *mod_name) +{ + struct device_driver *drv = &idxd_drv->drv; + + if (!idxd_drv->type) { + pr_debug("driver type not set (%ps)\n", __builtin_return_address(0)); + return -EINVAL; + } + + drv->name = idxd_drv->name; + drv->bus = &dsa_bus_type; + drv->owner = owner; + drv->mod_name = mod_name; + + return driver_register(drv); +} +EXPORT_SYMBOL_GPL(__idxd_driver_register); + +void idxd_driver_unregister(struct idxd_device_driver *idxd_drv) +{ + driver_unregister(&idxd_drv->drv); +} +EXPORT_SYMBOL_GPL(idxd_driver_unregister); + +static int idxd_config_bus_match(struct device *dev, + struct device_driver *drv) +{ + struct idxd_device_driver *idxd_drv = + container_of(drv, struct idxd_device_driver, drv); + struct idxd_dev *idxd_dev = confdev_to_idxd_dev(dev); + int i = 0; + + while (idxd_drv->type[i] != IDXD_DEV_NONE) { + if (idxd_dev->type == idxd_drv->type[i]) + return 1; + i++; + } + + return 0; +} + +static int idxd_config_bus_probe(struct device *dev) +{ + struct idxd_device_driver *idxd_drv = + container_of(dev->driver, struct idxd_device_driver, drv); + struct idxd_dev *idxd_dev = confdev_to_idxd_dev(dev); + + return idxd_drv->probe(idxd_dev); +} + +static int idxd_config_bus_remove(struct device *dev) +{ + struct idxd_device_driver *idxd_drv = + container_of(dev->driver, struct idxd_device_driver, drv); + struct idxd_dev *idxd_dev = confdev_to_idxd_dev(dev); + + idxd_drv->remove(idxd_dev); + return 0; +} + +struct bus_type dsa_bus_type = { + .name = "dsa", + .match = idxd_config_bus_match, + .probe = idxd_config_bus_probe, + .remove = idxd_config_bus_remove, +}; +EXPORT_SYMBOL_GPL(dsa_bus_type); + +static int __init dsa_bus_init(void) +{ + return bus_register(&dsa_bus_type); +} +module_init(dsa_bus_init); + +static void __exit dsa_bus_exit(void) +{ + bus_unregister(&dsa_bus_type); +} +module_exit(dsa_bus_exit); + +MODULE_DESCRIPTION("IDXD driver dsa_bus_type driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c index 33a80f700ff8..9b797fcdfd7b 100644 --- a/drivers/dma/idxd/init.c +++ b/drivers/dma/idxd/init.c @@ -26,6 +26,7 @@ MODULE_VERSION(IDXD_DRIVER_VERSION); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Intel Corporation"); +MODULE_IMPORT_NS(IDXD); static bool sva = true; module_param(sva, bool, 0644); @@ -836,10 +837,6 @@ static int __init idxd_init_module(void) perfmon_init(); - err = idxd_register_bus_type(); - if (err < 0) - return err; - err = idxd_driver_register(&idxd_drv); if (err < 0) goto err_idxd_driver_register; @@ -877,7 +874,6 @@ err_idxd_user_driver_register: err_idxd_dmaengine_driver_register: idxd_driver_unregister(&idxd_drv); err_idxd_driver_register: - idxd_unregister_bus_type(); return err; } module_init(idxd_init_module); @@ -890,30 +886,6 @@ static void __exit idxd_exit_module(void) idxd_driver_unregister(&dsa_drv); pci_unregister_driver(&idxd_pci_driver); idxd_cdev_remove(); - idxd_unregister_bus_type(); perfmon_exit(); } module_exit(idxd_exit_module); - -int __idxd_driver_register(struct idxd_device_driver *idxd_drv, struct module *owner, - const char *mod_name) -{ - struct device_driver *drv = &idxd_drv->drv; - - if (!idxd_drv->type) { - pr_debug("driver type not set (%ps)\n", __builtin_return_address(0)); - return -EINVAL; - } - - drv->name = idxd_drv->name; - drv->bus = &dsa_bus_type; - drv->owner = owner; - drv->mod_name = mod_name; - - return driver_register(drv); -} - -void idxd_driver_unregister(struct idxd_device_driver *idxd_drv) -{ - driver_unregister(&idxd_drv->drv); -} diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c index 8d48903df131..633f4947ed32 100644 --- a/drivers/dma/idxd/sysfs.c +++ b/drivers/dma/idxd/sysfs.c @@ -16,49 +16,6 @@ static char *idxd_wq_type_names[] = { [IDXD_WQT_USER] = "user", }; -static int idxd_config_bus_match(struct device *dev, - struct device_driver *drv) -{ - struct idxd_device_driver *idxd_drv = - container_of(drv, struct idxd_device_driver, drv); - struct idxd_dev *idxd_dev = confdev_to_idxd_dev(dev); - int i = 0; - - while (idxd_drv->type[i] != IDXD_DEV_NONE) { - if (idxd_dev->type == idxd_drv->type[i]) - return 1; - i++; - } - - return 0; -} - -static int idxd_config_bus_probe(struct device *dev) -{ - struct idxd_device_driver *idxd_drv = - container_of(dev->driver, struct idxd_device_driver, drv); - struct idxd_dev *idxd_dev = confdev_to_idxd_dev(dev); - - return idxd_drv->probe(idxd_dev); -} - -static int idxd_config_bus_remove(struct device *dev) -{ - struct idxd_device_driver *idxd_drv = - container_of(dev->driver, struct idxd_device_driver, drv); - struct idxd_dev *idxd_dev = confdev_to_idxd_dev(dev); - - idxd_drv->remove(idxd_dev); - return 0; -} - -struct bus_type dsa_bus_type = { - .name = "dsa", - .match = idxd_config_bus_match, - .probe = idxd_config_bus_probe, - .remove = idxd_config_bus_remove, -}; - static int idxd_dsa_drv_probe(struct idxd_dev *idxd_dev) { if (is_idxd_dev(idxd_dev)) From 6e7f3ee97bbe2c7d7a53b7dbd7a08a579e03c8c9 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Thu, 15 Jul 2021 11:44:47 -0700 Subject: [PATCH 040/696] dmaengine: idxd: move dsa_drv support to compatible mode The original architecture of /sys/bus/dsa invented a scheme whereby a single entry in the list of bus drivers, /sys/bus/drivers/dsa, handled all device types and internally routed them to different different drivers. Those internal drivers were invisible to userspace. With the idxd driver transitioned to a proper bus device-driver model, the legacy behavior needs to be preserved due to it being exposed to user space via sysfs. Create a compat driver to provide the legacy behavior for /sys/bus/dsa/drivers/dsa. This should satisfy user tool accel-config v3.2 or ealier where this behavior is expected. If the distro has a newer accel-config then the legacy mode does not need to be enabled. When the compat driver binds the device (i.e. dsa0) to the dsa driver, it will be bound to the new idxd_drv. The wq device (i.e. wq0.0) will be bound to either the dmaengine_drv or the user_drv. The dsa_drv becomes a routing mechansim for the new drivers. It will not support additional external drivers that are implemented later. Reviewed-by: Dan Williams Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/162637468705.744545.4399080971745974435.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul --- drivers/dma/Kconfig | 17 ++++++ drivers/dma/idxd/Makefile | 3 + drivers/dma/idxd/cdev.c | 1 + drivers/dma/idxd/compat.c | 114 ++++++++++++++++++++++++++++++++++++++ drivers/dma/idxd/device.c | 1 + drivers/dma/idxd/dma.c | 1 + drivers/dma/idxd/idxd.h | 10 +++- drivers/dma/idxd/init.c | 7 --- drivers/dma/idxd/sysfs.c | 40 ------------- 9 files changed, 146 insertions(+), 48 deletions(-) create mode 100644 drivers/dma/idxd/compat.c diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index d7101bff1772..ceb41be0505e 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -295,6 +295,23 @@ config INTEL_IDXD If unsure, say N. +config INTEL_IDXD_COMPAT + bool "Legacy behavior for idxd driver" + depends on PCI && X86_64 + select INTEL_IDXD_BUS + help + Compatible driver to support old /sys/bus/dsa/drivers/dsa behavior. + The old behavior performed driver bind/unbind for device and wq + devices all under the dsa driver. The compat driver will emulate + the legacy behavior in order to allow existing support apps (i.e. + accel-config) to continue function. It is expected that accel-config + v3.2 and earlier will need the compat mode. A distro with later + accel-config version can disable this compat config. + + Say Y if you have old applications that require such behavior. + + If unsure, say N. + # Config symbol that collects all the dependencies that's necessary to # support shared virtual memory for the devices supported by idxd. config INTEL_IDXD_SVM diff --git a/drivers/dma/idxd/Makefile b/drivers/dma/idxd/Makefile index 8c29ed4d48c3..a1e9f2b3a37c 100644 --- a/drivers/dma/idxd/Makefile +++ b/drivers/dma/idxd/Makefile @@ -7,3 +7,6 @@ idxd-$(CONFIG_INTEL_IDXD_PERFMON) += perfmon.o obj-$(CONFIG_INTEL_IDXD_BUS) += idxd_bus.o idxd_bus-y := bus.o + +obj-$(CONFIG_INTEL_IDXD_COMPAT) += idxd_compat.o +idxd_compat-y := compat.o diff --git a/drivers/dma/idxd/cdev.c b/drivers/dma/idxd/cdev.c index b67bbf24242a..f6a4603517ba 100644 --- a/drivers/dma/idxd/cdev.c +++ b/drivers/dma/idxd/cdev.c @@ -356,6 +356,7 @@ struct idxd_device_driver idxd_user_drv = { .name = "user", .type = dev_types, }; +EXPORT_SYMBOL_GPL(idxd_user_drv); int idxd_cdev_register(void) { diff --git a/drivers/dma/idxd/compat.c b/drivers/dma/idxd/compat.c new file mode 100644 index 000000000000..d67746ee0c1a --- /dev/null +++ b/drivers/dma/idxd/compat.c @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2021 Intel Corporation. All rights rsvd. */ +#include +#include +#include +#include +#include +#include "idxd.h" + +extern int device_driver_attach(struct device_driver *drv, struct device *dev); +extern void device_driver_detach(struct device *dev); + +#define DRIVER_ATTR_IGNORE_LOCKDEP(_name, _mode, _show, _store) \ + struct driver_attribute driver_attr_##_name = \ + __ATTR_IGNORE_LOCKDEP(_name, _mode, _show, _store) + +static ssize_t unbind_store(struct device_driver *drv, const char *buf, size_t count) +{ + struct bus_type *bus = drv->bus; + struct device *dev; + int rc = -ENODEV; + + dev = bus_find_device_by_name(bus, NULL, buf); + if (dev && dev->driver) { + device_driver_detach(dev); + rc = count; + } + + return rc; +} +static DRIVER_ATTR_IGNORE_LOCKDEP(unbind, 0200, NULL, unbind_store); + +static ssize_t bind_store(struct device_driver *drv, const char *buf, size_t count) +{ + struct bus_type *bus = drv->bus; + struct device *dev; + struct device_driver *alt_drv; + int rc = -ENODEV; + struct idxd_dev *idxd_dev; + + dev = bus_find_device_by_name(bus, NULL, buf); + if (!dev || dev->driver || drv != &dsa_drv.drv) + return -ENODEV; + + idxd_dev = confdev_to_idxd_dev(dev); + if (is_idxd_dev(idxd_dev)) { + alt_drv = driver_find("idxd", bus); + if (!alt_drv) + return -ENODEV; + } else if (is_idxd_wq_dev(idxd_dev)) { + struct idxd_wq *wq = confdev_to_wq(dev); + + if (is_idxd_wq_kernel(wq)) { + alt_drv = driver_find("dmaengine", bus); + if (!alt_drv) + return -ENODEV; + } else if (is_idxd_wq_user(wq)) { + alt_drv = driver_find("user", bus); + if (!alt_drv) + return -ENODEV; + } else { + return -ENODEV; + } + } + + rc = device_driver_attach(alt_drv, dev); + if (rc < 0) + return rc; + + return count; +} +static DRIVER_ATTR_IGNORE_LOCKDEP(bind, 0200, NULL, bind_store); + +static struct attribute *dsa_drv_compat_attrs[] = { + &driver_attr_bind.attr, + &driver_attr_unbind.attr, + NULL, +}; + +static const struct attribute_group dsa_drv_compat_attr_group = { + .attrs = dsa_drv_compat_attrs, +}; + +static const struct attribute_group *dsa_drv_compat_groups[] = { + &dsa_drv_compat_attr_group, + NULL, +}; + +static int idxd_dsa_drv_probe(struct idxd_dev *idxd_dev) +{ + return -ENODEV; +} + +static void idxd_dsa_drv_remove(struct idxd_dev *idxd_dev) +{ +} + +static enum idxd_dev_type dev_types[] = { + IDXD_DEV_NONE, +}; + +struct idxd_device_driver dsa_drv = { + .name = "dsa", + .probe = idxd_dsa_drv_probe, + .remove = idxd_dsa_drv_remove, + .type = dev_types, + .drv = { + .suppress_bind_attrs = true, + .groups = dsa_drv_compat_groups, + }, +}; + +module_idxd_driver(dsa_drv); +MODULE_IMPORT_NS(IDXD); diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c index 9bbc28d9a9eb..99350ac9a292 100644 --- a/drivers/dma/idxd/device.c +++ b/drivers/dma/idxd/device.c @@ -1318,3 +1318,4 @@ struct idxd_device_driver idxd_drv = { .remove = idxd_device_drv_remove, .name = "idxd", }; +EXPORT_SYMBOL_GPL(idxd_drv); diff --git a/drivers/dma/idxd/dma.c b/drivers/dma/idxd/dma.c index 7e3281700183..2fd7ec29a08f 100644 --- a/drivers/dma/idxd/dma.c +++ b/drivers/dma/idxd/dma.c @@ -339,3 +339,4 @@ struct idxd_device_driver idxd_dmaengine_drv = { .name = "dmaengine", .type = dev_types, }; +EXPORT_SYMBOL_GPL(idxd_dmaengine_drv); diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h index bacec9b93a7e..d0874d8877d9 100644 --- a/drivers/dma/idxd/idxd.h +++ b/drivers/dma/idxd/idxd.h @@ -416,11 +416,16 @@ static inline bool is_idxd_wq_dmaengine(struct idxd_wq *wq) return false; } -static inline bool is_idxd_wq_cdev(struct idxd_wq *wq) +static inline bool is_idxd_wq_user(struct idxd_wq *wq) { return wq->type == IDXD_WQT_USER; } +static inline bool is_idxd_wq_kernel(struct idxd_wq *wq) +{ + return wq->type == IDXD_WQT_KERNEL; +} + static inline bool wq_dedicated(struct idxd_wq *wq) { return test_bit(WQ_FLAG_DEDICATED, &wq->flags); @@ -484,6 +489,9 @@ int __must_check __idxd_driver_register(struct idxd_device_driver *idxd_drv, void idxd_driver_unregister(struct idxd_device_driver *idxd_drv); +#define module_idxd_driver(__idxd_driver) \ + module_driver(__idxd_driver, idxd_driver_register, idxd_driver_unregister) + int idxd_register_bus_type(void); void idxd_unregister_bus_type(void); int idxd_register_devices(struct idxd_device *idxd); diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c index 9b797fcdfd7b..8db56f98059f 100644 --- a/drivers/dma/idxd/init.c +++ b/drivers/dma/idxd/init.c @@ -849,10 +849,6 @@ static int __init idxd_init_module(void) if (err < 0) goto err_idxd_user_driver_register; - err = idxd_driver_register(&dsa_drv); - if (err < 0) - goto err_dsa_driver_register; - err = idxd_cdev_register(); if (err) goto err_cdev_register; @@ -866,8 +862,6 @@ static int __init idxd_init_module(void) err_pci_register: idxd_cdev_remove(); err_cdev_register: - idxd_driver_unregister(&dsa_drv); -err_dsa_driver_register: idxd_driver_unregister(&idxd_user_drv); err_idxd_user_driver_register: idxd_driver_unregister(&idxd_dmaengine_drv); @@ -883,7 +877,6 @@ static void __exit idxd_exit_module(void) idxd_driver_unregister(&idxd_user_drv); idxd_driver_unregister(&idxd_dmaengine_drv); idxd_driver_unregister(&idxd_drv); - idxd_driver_unregister(&dsa_drv); pci_unregister_driver(&idxd_pci_driver); idxd_cdev_remove(); perfmon_exit(); diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c index 633f4947ed32..b883e9f16e7f 100644 --- a/drivers/dma/idxd/sysfs.c +++ b/drivers/dma/idxd/sysfs.c @@ -16,46 +16,6 @@ static char *idxd_wq_type_names[] = { [IDXD_WQT_USER] = "user", }; -static int idxd_dsa_drv_probe(struct idxd_dev *idxd_dev) -{ - if (is_idxd_dev(idxd_dev)) - return idxd_device_drv_probe(idxd_dev); - - if (is_idxd_wq_dev(idxd_dev)) { - struct idxd_wq *wq = idxd_dev_to_wq(idxd_dev); - - return drv_enable_wq(wq); - } - - return -ENODEV; -} - -static void idxd_dsa_drv_remove(struct idxd_dev *idxd_dev) -{ - if (is_idxd_dev(idxd_dev)) { - idxd_device_drv_remove(idxd_dev); - return; - } - - if (is_idxd_wq_dev(idxd_dev)) { - struct idxd_wq *wq = idxd_dev_to_wq(idxd_dev); - - drv_disable_wq(wq); - return; - } -} - -static enum idxd_dev_type dev_types[] = { - IDXD_DEV_NONE, -}; - -struct idxd_device_driver dsa_drv = { - .name = "dsa", - .probe = idxd_dsa_drv_probe, - .remove = idxd_dsa_drv_remove, - .type = dev_types, -}; - /* IDXD engine attributes */ static ssize_t engine_group_id_show(struct device *dev, struct device_attribute *attr, char *buf) From 0e96454ca26cc5c594ec792f7e5168cce726f7cf Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Wed, 14 Jul 2021 16:25:00 -0700 Subject: [PATCH 041/696] dmaengine: idxd: remove fault processing code Kernel memory are pinned and will not cause faults. Since the driver does not support interrupts for user descriptors, no fault errors are expected to come through the misc interrupt. Remove dead code. Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/162630502789.631986.10591230961790023856.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/irq.c | 95 ++---------------------------------------- 1 file changed, 4 insertions(+), 91 deletions(-) diff --git a/drivers/dma/idxd/irq.c b/drivers/dma/idxd/irq.c index be65d55e1fc4..e018459b534f 100644 --- a/drivers/dma/idxd/irq.c +++ b/drivers/dma/idxd/irq.c @@ -23,10 +23,8 @@ struct idxd_fault { }; static int irq_process_work_list(struct idxd_irq_entry *irq_entry, - enum irq_work_type wtype, int *processed, u64 data); static int irq_process_pending_llist(struct idxd_irq_entry *irq_entry, - enum irq_work_type wtype, int *processed, u64 data); static void idxd_device_reinit(struct work_struct *work) @@ -62,46 +60,6 @@ static void idxd_device_reinit(struct work_struct *work) idxd_device_clear_state(idxd); } -static void idxd_device_fault_work(struct work_struct *work) -{ - struct idxd_fault *fault = container_of(work, struct idxd_fault, work); - struct idxd_irq_entry *ie; - int i; - int processed; - int irqcnt = fault->idxd->num_wq_irqs + 1; - - for (i = 1; i < irqcnt; i++) { - ie = &fault->idxd->irq_entries[i]; - irq_process_work_list(ie, IRQ_WORK_PROCESS_FAULT, - &processed, fault->addr); - if (processed) - break; - - irq_process_pending_llist(ie, IRQ_WORK_PROCESS_FAULT, - &processed, fault->addr); - if (processed) - break; - } - - kfree(fault); -} - -static int idxd_device_schedule_fault_process(struct idxd_device *idxd, - u64 fault_addr) -{ - struct idxd_fault *fault; - - fault = kmalloc(sizeof(*fault), GFP_ATOMIC); - if (!fault) - return -ENOMEM; - - fault->addr = fault_addr; - fault->idxd = idxd; - INIT_WORK(&fault->work, idxd_device_fault_work); - queue_work(idxd->wq, &fault->work); - return 0; -} - static int process_misc_interrupts(struct idxd_device *idxd, u32 cause) { struct device *dev = &idxd->pdev->dev; @@ -168,15 +126,6 @@ static int process_misc_interrupts(struct idxd_device *idxd, u32 cause) if (!err) return 0; - /* - * This case should rarely happen and typically is due to software - * programming error by the driver. - */ - if (idxd->sw_err.valid && - idxd->sw_err.desc_valid && - idxd->sw_err.fault_addr) - idxd_device_schedule_fault_process(idxd, idxd->sw_err.fault_addr); - gensts.bits = ioread32(idxd->reg_base + IDXD_GENSTATS_OFFSET); if (gensts.state == IDXD_DEVICE_STATE_HALT) { idxd->state = IDXD_DEV_HALTED; @@ -228,43 +177,19 @@ irqreturn_t idxd_misc_thread(int vec, void *data) return IRQ_HANDLED; } -static inline bool match_fault(struct idxd_desc *desc, u64 fault_addr) -{ - /* - * Completion address can be bad as well. Check fault address match for descriptor - * and completion address. - */ - if ((u64)desc->hw == fault_addr || (u64)desc->completion == fault_addr) { - struct idxd_device *idxd = desc->wq->idxd; - struct device *dev = &idxd->pdev->dev; - - dev_warn(dev, "desc with fault address: %#llx\n", fault_addr); - return true; - } - - return false; -} - static int irq_process_pending_llist(struct idxd_irq_entry *irq_entry, - enum irq_work_type wtype, int *processed, u64 data) { struct idxd_desc *desc, *t; struct llist_node *head; int queued = 0; unsigned long flags; - enum idxd_complete_type reason; *processed = 0; head = llist_del_all(&irq_entry->pending_llist); if (!head) goto out; - if (wtype == IRQ_WORK_NORMAL) - reason = IDXD_COMPLETE_NORMAL; - else - reason = IDXD_COMPLETE_DEV_FAIL; - llist_for_each_entry_safe(desc, t, head, llnode) { u8 status = desc->completion->status & DSA_COMP_STATUS_MASK; @@ -275,9 +200,7 @@ static int irq_process_pending_llist(struct idxd_irq_entry *irq_entry, continue; } - if (unlikely(status != DSA_COMP_SUCCESS)) - match_fault(desc, data); - complete_desc(desc, reason); + complete_desc(desc, IDXD_COMPLETE_NORMAL); (*processed)++; } else { spin_lock_irqsave(&irq_entry->list_lock, flags); @@ -293,20 +216,14 @@ static int irq_process_pending_llist(struct idxd_irq_entry *irq_entry, } static int irq_process_work_list(struct idxd_irq_entry *irq_entry, - enum irq_work_type wtype, int *processed, u64 data) { int queued = 0; unsigned long flags; LIST_HEAD(flist); struct idxd_desc *desc, *n; - enum idxd_complete_type reason; *processed = 0; - if (wtype == IRQ_WORK_NORMAL) - reason = IDXD_COMPLETE_NORMAL; - else - reason = IDXD_COMPLETE_DEV_FAIL; /* * This lock protects list corruption from access of list outside of the irq handler @@ -338,9 +255,7 @@ static int irq_process_work_list(struct idxd_irq_entry *irq_entry, continue; } - if (unlikely(status != DSA_COMP_SUCCESS)) - match_fault(desc, data); - complete_desc(desc, reason); + complete_desc(desc, IDXD_COMPLETE_NORMAL); } return queued; @@ -370,14 +285,12 @@ static int idxd_desc_process(struct idxd_irq_entry *irq_entry) * 5. Repeat until no more descriptors. */ do { - rc = irq_process_work_list(irq_entry, IRQ_WORK_NORMAL, - &processed, 0); + rc = irq_process_work_list(irq_entry, &processed, 0); total += processed; if (rc != 0) continue; - rc = irq_process_pending_llist(irq_entry, IRQ_WORK_NORMAL, - &processed, 0); + rc = irq_process_pending_llist(irq_entry, &processed, 0); total += processed; } while (rc != 0); From 7d3370e506ec5cd781ef6b938cf29c046eb77585 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 20 Jul 2021 21:48:35 -0700 Subject: [PATCH 042/696] Revert "Input: serio - make write method mandatory" This reverts commit 81c7c0a350bfe9306ad9fb10356534ede8f4ab31. The idea to make write method mandatory was flawed as several client drivers (such as atkbd) check for presence of write() method to adjust behavior of the driver. Reported-by: Nathan Chancellor Reported-by: Michael Kelley Signed-off-by: Dmitry Torokhov --- drivers/input/serio/ams_delta_serio.c | 6 ------ drivers/input/serio/serio.c | 5 ----- include/linux/serio.h | 5 ++++- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/drivers/input/serio/ams_delta_serio.c b/drivers/input/serio/ams_delta_serio.c index a1c314897951..1c0be299f179 100644 --- a/drivers/input/serio/ams_delta_serio.c +++ b/drivers/input/serio/ams_delta_serio.c @@ -89,11 +89,6 @@ static irqreturn_t ams_delta_serio_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static int ams_delta_serio_write(struct serio *serio, u8 data) -{ - return -EINVAL; -} - static int ams_delta_serio_open(struct serio *serio) { struct ams_delta_serio *priv = serio->port_data; @@ -162,7 +157,6 @@ static int ams_delta_serio_init(struct platform_device *pdev) priv->serio = serio; serio->id.type = SERIO_8042; - serio->write = ams_delta_serio_write; serio->open = ams_delta_serio_open; serio->close = ams_delta_serio_close; strlcpy(serio->name, "AMS DELTA keyboard adapter", sizeof(serio->name)); diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 8d229a11bb6b..29f491082926 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -694,11 +694,6 @@ EXPORT_SYMBOL(serio_reconnect); */ void __serio_register_port(struct serio *serio, struct module *owner) { - if (!serio->write) { - pr_err("%s: refusing to register %s without write method\n", - __func__, serio->name); - return; - } serio_init_port(serio); serio_queue_event(serio, owner, SERIO_REGISTER_PORT); } diff --git a/include/linux/serio.h b/include/linux/serio.h index 075f1b8d76fa..6c27d413da92 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -121,7 +121,10 @@ void serio_unregister_driver(struct serio_driver *drv); static inline int serio_write(struct serio *serio, unsigned char data) { - return serio->write(serio, data); + if (serio->write) + return serio->write(serio, data); + else + return -1; } static inline void serio_drv_write_wakeup(struct serio *serio) From da5e96ffd5a938b11c430d023109a19ba3b6d71d Mon Sep 17 00:00:00 2001 From: satya priya Date: Fri, 23 Jul 2021 12:12:37 -0700 Subject: [PATCH 043/696] dt-bindings: power: reset: Change 'additionalProperties' to true Change 'additionalProperties' to true as this is a generic binding. Signed-off-by: satya priya Acked-by: Rob Herring Reviewed-by: Sebastian Reichel Reviewed-by: Stephen Boyd Link: https://lore.kernel.org/r/1620800053-26405-4-git-send-email-skakit@codeaurora.org Signed-off-by: Dmitry Torokhov --- Documentation/devicetree/bindings/power/reset/reboot-mode.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/power/reset/reboot-mode.yaml b/Documentation/devicetree/bindings/power/reset/reboot-mode.yaml index 9c6fda6b1dd9..ad0a0b95cec1 100644 --- a/Documentation/devicetree/bindings/power/reset/reboot-mode.yaml +++ b/Documentation/devicetree/bindings/power/reset/reboot-mode.yaml @@ -36,7 +36,7 @@ patternProperties: "^mode-.*$": $ref: /schemas/types.yaml#/definitions/uint32 -additionalProperties: false +additionalProperties: true examples: - | From 400793bc351b83c11ce28210d86039e905c8ff32 Mon Sep 17 00:00:00 2001 From: satya priya Date: Fri, 23 Jul 2021 12:12:52 -0700 Subject: [PATCH 044/696] dt-bindings: input: pm8941-pwrkey: Convert pm8941 power key binding to yaml Convert qcom pm8941 power key binding from .txt to .yaml format. The example has been removed in favour of full example being available in the qcom,pon.yaml binding. Signed-off-by: satya priya Reviewed-by: Rob Herring Reviewed-by: Stephen Boyd Link: https://lore.kernel.org/r/1620800053-26405-5-git-send-email-skakit@codeaurora.org Signed-off-by: Dmitry Torokhov --- .../bindings/input/qcom,pm8941-pwrkey.txt | 55 ------------------- .../bindings/input/qcom,pm8941-pwrkey.yaml | 51 +++++++++++++++++ 2 files changed, 51 insertions(+), 55 deletions(-) delete mode 100644 Documentation/devicetree/bindings/input/qcom,pm8941-pwrkey.txt create mode 100644 Documentation/devicetree/bindings/input/qcom,pm8941-pwrkey.yaml diff --git a/Documentation/devicetree/bindings/input/qcom,pm8941-pwrkey.txt b/Documentation/devicetree/bindings/input/qcom,pm8941-pwrkey.txt deleted file mode 100644 index 6cd08bca2c66..000000000000 --- a/Documentation/devicetree/bindings/input/qcom,pm8941-pwrkey.txt +++ /dev/null @@ -1,55 +0,0 @@ -Qualcomm PM8941 PMIC Power Key - -PROPERTIES - -- compatible: - Usage: required - Value type: - Definition: must be one of: - "qcom,pm8941-pwrkey" - "qcom,pm8941-resin" - "qcom,pmk8350-pwrkey" - "qcom,pmk8350-resin" - -- reg: - Usage: required - Value type: - Definition: base address of registers for block - -- interrupts: - Usage: required - Value type: - Definition: key change interrupt; The format of the specifier is - defined by the binding document describing the node's - interrupt parent. - -- debounce: - Usage: optional - Value type: - Definition: time in microseconds that key must be pressed or released - for state change interrupt to trigger. - -- bias-pull-up: - Usage: optional - Value type: - Definition: presence of this property indicates that the KPDPWR_N pin - should be configured for pull up. - -- linux,code: - Usage: optional - Value type: - Definition: The input key-code associated with the power key. - Use the linux event codes defined in - include/dt-bindings/input/linux-event-codes.h - When property is omitted KEY_POWER is assumed. - -EXAMPLE - - pwrkey@800 { - compatible = "qcom,pm8941-pwrkey"; - reg = <0x800>; - interrupts = <0x0 0x8 0 IRQ_TYPE_EDGE_BOTH>; - debounce = <15625>; - bias-pull-up; - linux,code = ; - }; diff --git a/Documentation/devicetree/bindings/input/qcom,pm8941-pwrkey.yaml b/Documentation/devicetree/bindings/input/qcom,pm8941-pwrkey.yaml new file mode 100644 index 000000000000..62314a5fdce5 --- /dev/null +++ b/Documentation/devicetree/bindings/input/qcom,pm8941-pwrkey.yaml @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/qcom,pm8941-pwrkey.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm PM8941 PMIC Power Key + +maintainers: + - Courtney Cavin + - Vinod Koul + +allOf: + - $ref: input.yaml# + +properties: + compatible: + enum: + - qcom,pm8941-pwrkey + - qcom,pm8941-resin + - qcom,pmk8350-pwrkey + - qcom,pmk8350-resin + + interrupts: + maxItems: 1 + + debounce: + description: | + Time in microseconds that key must be pressed or + released for state change interrupt to trigger. + $ref: /schemas/types.yaml#/definitions/uint32 + + bias-pull-up: + description: | + Presence of this property indicates that the KPDPWR_N + pin should be configured for pull up. + $ref: /schemas/types.yaml#/definitions/flag + + linux,code: + description: | + The input key-code associated with the power key. + Use the linux event codes defined in + include/dt-bindings/input/linux-event-codes.h + When property is omitted KEY_POWER is assumed. + +required: + - compatible + - interrupts + +unevaluatedProperties: false +... From 76ba1900cb67390d963e07457ebf679c56c59094 Mon Sep 17 00:00:00 2001 From: satya priya Date: Fri, 23 Jul 2021 12:13:03 -0700 Subject: [PATCH 045/696] dt-bindings: power: reset: qcom-pon: Convert qcom PON binding to yaml Convert qcom PON binding from .txt to .yaml format. Signed-off-by: satya priya Reviewed-by: Rob Herring Reviewed-by: Sebastian Reichel Reviewed-by: Stephen Boyd Link: https://lore.kernel.org/r/1620800053-26405-6-git-send-email-skakit@codeaurora.org Signed-off-by: Dmitry Torokhov --- .../bindings/power/reset/qcom,pon.txt | 49 ------------ .../bindings/power/reset/qcom,pon.yaml | 80 +++++++++++++++++++ 2 files changed, 80 insertions(+), 49 deletions(-) delete mode 100644 Documentation/devicetree/bindings/power/reset/qcom,pon.txt create mode 100644 Documentation/devicetree/bindings/power/reset/qcom,pon.yaml diff --git a/Documentation/devicetree/bindings/power/reset/qcom,pon.txt b/Documentation/devicetree/bindings/power/reset/qcom,pon.txt deleted file mode 100644 index 0c0dc3a1e693..000000000000 --- a/Documentation/devicetree/bindings/power/reset/qcom,pon.txt +++ /dev/null @@ -1,49 +0,0 @@ -Qualcomm PON Device - -The Power On device for Qualcomm PM8xxx is MFD supporting pwrkey -and resin along with the Android reboot-mode. - -This DT node has pwrkey and resin as sub nodes. - -Required Properties: --compatible: Must be one of: - "qcom,pm8916-pon" - "qcom,pms405-pon" - "qcom,pm8998-pon" - --reg: Specifies the physical address of the pon register - -Optional subnode: --pwrkey: Specifies the subnode pwrkey and should follow the - qcom,pm8941-pwrkey.txt description. --resin: Specifies the subnode resin and should follow the - qcom,pm8xxx-pwrkey.txt description. - -The rest of the properties should follow the generic reboot-mode description -found in reboot-mode.txt - -Example: - - pon@800 { - compatible = "qcom,pm8916-pon"; - - reg = <0x800>; - mode-bootloader = <0x2>; - mode-recovery = <0x1>; - - pwrkey { - compatible = "qcom,pm8941-pwrkey"; - interrupts = <0x0 0x8 0 IRQ_TYPE_EDGE_BOTH>; - debounce = <15625>; - bias-pull-up; - linux,code = ; - }; - - resin { - compatible = "qcom,pm8941-resin"; - interrupts = <0x0 0x8 1 IRQ_TYPE_EDGE_BOTH>; - debounce = <15625>; - bias-pull-up; - linux,code = ; - }; - }; diff --git a/Documentation/devicetree/bindings/power/reset/qcom,pon.yaml b/Documentation/devicetree/bindings/power/reset/qcom,pon.yaml new file mode 100644 index 000000000000..353f155df0f4 --- /dev/null +++ b/Documentation/devicetree/bindings/power/reset/qcom,pon.yaml @@ -0,0 +1,80 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/power/reset/qcom,pon.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm PON Device + +maintainers: + - Vinod Koul + +description: | + The Power On device for Qualcomm PM8xxx is MFD supporting pwrkey + and resin along with the Android reboot-mode. + + This DT node has pwrkey and resin as sub nodes. + +allOf: + - $ref: reboot-mode.yaml# + +properties: + compatible: + enum: + - qcom,pm8916-pon + - qcom,pms405-pon + - qcom,pm8998-pon + + reg: + maxItems: 1 + + pwrkey: + type: object + $ref: "../../input/qcom,pm8941-pwrkey.yaml#" + + resin: + type: object + $ref: "../../input/qcom,pm8941-pwrkey.yaml#" + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + spmi_bus: spmi@c440000 { + reg = <0x0c440000 0x1100>; + #address-cells = <2>; + #size-cells = <0>; + pmk8350: pmic@0 { + reg = <0x0 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + pmk8350_pon: pon_hlos@1300 { + reg = <0x1300>; + compatible = "qcom,pm8998-pon"; + + pwrkey { + compatible = "qcom,pm8941-pwrkey"; + interrupts = < 0x0 0x8 0 IRQ_TYPE_EDGE_BOTH >; + debounce = <15625>; + bias-pull-up; + linux,code = ; + }; + + resin { + compatible = "qcom,pm8941-resin"; + interrupts = <0x0 0x8 1 IRQ_TYPE_EDGE_BOTH>; + debounce = <15625>; + bias-pull-up; + linux,code = ; + }; + }; + }; + }; +... From 5af9f79b41b2ac58cc1d7c08945d7dbe26ee694a Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 23 Jul 2021 17:33:24 -0700 Subject: [PATCH 046/696] Input: pm8941-pwrkey - fix comma vs semicolon issue There is absolutely no reason to use comma operator in this code, 2 separate statements make much more sense. Reviewed-by: Stephen Boyd Link: https://lore.kernel.org/r/YPsa1qCBn/SAmE5x@google.com Signed-off-by: Dmitry Torokhov --- drivers/input/misc/pm8941-pwrkey.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/misc/pm8941-pwrkey.c b/drivers/input/misc/pm8941-pwrkey.c index 10e3fc0eac6e..33609603245d 100644 --- a/drivers/input/misc/pm8941-pwrkey.c +++ b/drivers/input/misc/pm8941-pwrkey.c @@ -284,7 +284,7 @@ static int pm8941_pwrkey_probe(struct platform_device *pdev) } if (pwrkey->data->supports_ps_hold_poff_config) { - pwrkey->reboot_notifier.notifier_call = pm8941_reboot_notify, + pwrkey->reboot_notifier.notifier_call = pm8941_reboot_notify; error = register_reboot_notifier(&pwrkey->reboot_notifier); if (error) { dev_err(&pdev->dev, "failed to register reboot notifier: %d\n", From 04647773d6481885447dc263673144053d3ec561 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 23 Jul 2021 17:34:07 -0700 Subject: [PATCH 047/696] dt-bindings: input: Convert ChipOne ICN8318 binding to a schema The ChipOne ICN8318 Touchscreen Controller is supported by Linux thanks to its device tree binding. Now that we have the DT validation in place, let's convert the device tree bindings for that driver over to a YAML schema. Signed-off-by: Maxime Ripard Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20210721140424.725744-17-maxime@cerno.tech Signed-off-by: Dmitry Torokhov --- .../input/touchscreen/chipone,icn8318.yaml | 62 +++++++++++++++++++ .../input/touchscreen/chipone_icn8318.txt | 44 ------------- 2 files changed, 62 insertions(+), 44 deletions(-) create mode 100644 Documentation/devicetree/bindings/input/touchscreen/chipone,icn8318.yaml delete mode 100644 Documentation/devicetree/bindings/input/touchscreen/chipone_icn8318.txt diff --git a/Documentation/devicetree/bindings/input/touchscreen/chipone,icn8318.yaml b/Documentation/devicetree/bindings/input/touchscreen/chipone,icn8318.yaml new file mode 100644 index 000000000000..9df685bdc5db --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/chipone,icn8318.yaml @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/touchscreen/chipone,icn8318.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ChipOne ICN8318 Touchscreen Controller Device Tree Bindings + +maintainers: + - Dmitry Torokhov + +allOf: + - $ref: touchscreen.yaml# + +properties: + compatible: + const: chipone,icn8318 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + wake-gpios: + maxItems: 1 + +unevaluatedProperties: false + +required: + - compatible + - reg + - interrupts + - wake-gpios + - touchscreen-size-x + - touchscreen-size-y + +examples: + - | + #include + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + touchscreen@40 { + compatible = "chipone,icn8318"; + reg = <0x40>; + interrupt-parent = <&pio>; + interrupts = <9 IRQ_TYPE_EDGE_FALLING>; /* EINT9 (PG9) */ + pinctrl-names = "default"; + pinctrl-0 = <&ts_wake_pin_p66>; + wake-gpios = <&pio 1 3 GPIO_ACTIVE_HIGH>; /* PB3 */ + touchscreen-size-x = <800>; + touchscreen-size-y = <480>; + touchscreen-inverted-x; + touchscreen-swapped-x-y; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/input/touchscreen/chipone_icn8318.txt b/Documentation/devicetree/bindings/input/touchscreen/chipone_icn8318.txt deleted file mode 100644 index 38b0603f65f3..000000000000 --- a/Documentation/devicetree/bindings/input/touchscreen/chipone_icn8318.txt +++ /dev/null @@ -1,44 +0,0 @@ -* ChipOne icn8318 I2C touchscreen controller - -Required properties: - - compatible : "chipone,icn8318" - - reg : I2C slave address of the chip (0x40) - - interrupts : interrupt specification for the icn8318 interrupt - - wake-gpios : GPIO specification for the WAKE input - - touchscreen-size-x : horizontal resolution of touchscreen (in pixels) - - touchscreen-size-y : vertical resolution of touchscreen (in pixels) - -Optional properties: - - pinctrl-names : should be "default" - - pinctrl-0: : a phandle pointing to the pin settings for the - control gpios - - touchscreen-fuzz-x : horizontal noise value of the absolute input - device (in pixels) - - touchscreen-fuzz-y : vertical noise value of the absolute input - device (in pixels) - - touchscreen-inverted-x : X axis is inverted (boolean) - - touchscreen-inverted-y : Y axis is inverted (boolean) - - touchscreen-swapped-x-y : X and Y axis are swapped (boolean) - Swapping is done after inverting the axis - -Example: - -i2c@00000000 { - /* ... */ - - chipone_icn8318@40 { - compatible = "chipone,icn8318"; - reg = <0x40>; - interrupt-parent = <&pio>; - interrupts = <9 IRQ_TYPE_EDGE_FALLING>; /* EINT9 (PG9) */ - pinctrl-names = "default"; - pinctrl-0 = <&ts_wake_pin_p66>; - wake-gpios = <&pio 1 3 GPIO_ACTIVE_HIGH>; /* PB3 */ - touchscreen-size-x = <800>; - touchscreen-size-y = <480>; - touchscreen-inverted-x; - touchscreen-swapped-x-y; - }; - - /* ... */ -}; From 187acd8c148a5f6ffed70776ca7f02efca0342fb Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 23 Jul 2021 17:34:20 -0700 Subject: [PATCH 048/696] dt-bindings: input: Convert Pixcir Touchscreen binding to a schema The Pixcir Touchscreen Controller is supported by Linux thanks to its device tree binding. Now that we have the DT validation in place, let's convert the device tree bindings for that driver over to a YAML schema. Signed-off-by: Maxime Ripard Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20210721140424.725744-18-maxime@cerno.tech Signed-off-by: Dmitry Torokhov --- .../input/touchscreen/pixcir,pixcir_ts.yaml | 68 +++++++++++++++++++ .../input/touchscreen/pixcir_i2c_ts.txt | 31 --------- 2 files changed, 68 insertions(+), 31 deletions(-) create mode 100644 Documentation/devicetree/bindings/input/touchscreen/pixcir,pixcir_ts.yaml delete mode 100644 Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt diff --git a/Documentation/devicetree/bindings/input/touchscreen/pixcir,pixcir_ts.yaml b/Documentation/devicetree/bindings/input/touchscreen/pixcir,pixcir_ts.yaml new file mode 100644 index 000000000000..f9998edbff70 --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/pixcir,pixcir_ts.yaml @@ -0,0 +1,68 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/touchscreen/pixcir,pixcir_ts.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Pixcir Touchscreen Controller Device Tree Bindings + +maintainers: + - Dmitry Torokhov + +allOf: + - $ref: touchscreen.yaml# + +properties: + compatible: + enum: + - pixcir,pixcir_ts + - pixcir,pixcir_tangoc + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + attb-gpio: + maxItems: 1 + + reset-gpios: + maxItems: 1 + + enable-gpios: + maxItems: 1 + + wake-gpios: + maxItems: 1 + +unevaluatedProperties: false + +required: + - compatible + - reg + - interrupts + - attb-gpio + - touchscreen-size-x + - touchscreen-size-y + +examples: + - | + #include + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + touchscreen@5c { + compatible = "pixcir,pixcir_ts"; + reg = <0x5c>; + interrupts = <2 0>; + attb-gpio = <&gpf 2 0 2>; + touchscreen-size-x = <800>; + touchscreen-size-y = <600>; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt b/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt deleted file mode 100644 index 697a3e7831e7..000000000000 --- a/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt +++ /dev/null @@ -1,31 +0,0 @@ -* Pixcir I2C touchscreen controllers - -Required properties: -- compatible: must be "pixcir,pixcir_ts" or "pixcir,pixcir_tangoc" -- reg: I2C address of the chip -- interrupts: interrupt to which the chip is connected -- attb-gpio: GPIO connected to the ATTB line of the chip -- touchscreen-size-x: horizontal resolution of touchscreen (in pixels) -- touchscreen-size-y: vertical resolution of touchscreen (in pixels) - -Optional properties: -- reset-gpios: GPIO connected to the RESET line of the chip -- enable-gpios: GPIO connected to the ENABLE line of the chip -- wake-gpios: GPIO connected to the WAKE line of the chip - -Example: - - i2c@00000000 { - /* ... */ - - pixcir_ts@5c { - compatible = "pixcir,pixcir_ts"; - reg = <0x5c>; - interrupts = <2 0>; - attb-gpio = <&gpf 2 0 2>; - touchscreen-size-x = <800>; - touchscreen-size-y = <600>; - }; - - /* ... */ - }; From cc3d15a51717b8f5850444aa437bf5535e80d263 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 23 Jul 2021 17:34:36 -0700 Subject: [PATCH 049/696] dt-bindings: input: Convert Regulator Haptic binding to a schema The Haptic feedback based on a regulator is supported by Linux thanks to its device tree binding. Now that we have the DT validation in place, let's convert the device tree bindings for that driver over to a YAML schema. Signed-off-by: Maxime Ripard Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20210721140424.725744-19-maxime@cerno.tech Signed-off-by: Dmitry Torokhov --- .../bindings/input/regulator-haptic.txt | 21 --------- .../bindings/input/regulator-haptic.yaml | 43 +++++++++++++++++++ 2 files changed, 43 insertions(+), 21 deletions(-) delete mode 100644 Documentation/devicetree/bindings/input/regulator-haptic.txt create mode 100644 Documentation/devicetree/bindings/input/regulator-haptic.yaml diff --git a/Documentation/devicetree/bindings/input/regulator-haptic.txt b/Documentation/devicetree/bindings/input/regulator-haptic.txt deleted file mode 100644 index 3ed1c7eb2f97..000000000000 --- a/Documentation/devicetree/bindings/input/regulator-haptic.txt +++ /dev/null @@ -1,21 +0,0 @@ -* Regulator Haptic Device Tree Bindings - -Required Properties: - - compatible : Should be "regulator-haptic" - - haptic-supply : Power supply to the haptic motor. - [*] refer Documentation/devicetree/bindings/regulator/regulator.txt - - - max-microvolt : The maximum voltage value supplied to the haptic motor. - [The unit of the voltage is a micro] - - - min-microvolt : The minimum voltage value supplied to the haptic motor. - [The unit of the voltage is a micro] - -Example: - - haptics { - compatible = "regulator-haptic"; - haptic-supply = <&motor_regulator>; - max-microvolt = <2700000>; - min-microvolt = <1100000>; - }; diff --git a/Documentation/devicetree/bindings/input/regulator-haptic.yaml b/Documentation/devicetree/bindings/input/regulator-haptic.yaml new file mode 100644 index 000000000000..b1ae72f9cd2d --- /dev/null +++ b/Documentation/devicetree/bindings/input/regulator-haptic.yaml @@ -0,0 +1,43 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/input/regulator-haptic.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Regulator Haptic Device Tree Bindings + +maintainers: + - Jaewon Kim + +properties: + compatible: + const: regulator-haptic + + haptic-supply: + description: > + Power supply to the haptic motor + + max-microvolt: + description: > + The maximum voltage value supplied to the haptic motor + + min-microvolt: + description: > + The minimum voltage value supplied to the haptic motor + +required: + - compatible + - haptic-supply + - max-microvolt + - min-microvolt + +additionalProperties: false + +examples: + - | + haptics { + compatible = "regulator-haptic"; + haptic-supply = <&motor_regulator>; + max-microvolt = <2700000>; + min-microvolt = <1100000>; + }; From a5b84e4e4f57cceceb206fd8b1c828c81b7e63a6 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 23 Jul 2021 17:34:57 -0700 Subject: [PATCH 050/696] dt-bindings: input: sun4i-lradc: Add wakeup-source The LRADC can be a wakeup source and is listed as such in some DT already. Let's make sure we allow that property in the binding. Signed-off-by: Maxime Ripard Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20210721140424.725744-21-maxime@cerno.tech Signed-off-by: Dmitry Torokhov --- .../bindings/input/allwinner,sun4i-a10-lradc-keys.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/input/allwinner,sun4i-a10-lradc-keys.yaml b/Documentation/devicetree/bindings/input/allwinner,sun4i-a10-lradc-keys.yaml index cffd02028d02..d74f2002409e 100644 --- a/Documentation/devicetree/bindings/input/allwinner,sun4i-a10-lradc-keys.yaml +++ b/Documentation/devicetree/bindings/input/allwinner,sun4i-a10-lradc-keys.yaml @@ -29,6 +29,8 @@ properties: description: Regulator for the LRADC reference voltage + wakeup-source: true + patternProperties: "^button-[0-9]+$": type: object From d453ceb6549af8798913de6a20444cb7200fdb69 Mon Sep 17 00:00:00 2001 From: Gwendal Grignou Date: Thu, 13 May 2021 17:57:33 -0700 Subject: [PATCH 051/696] platform/chrome: sensorhub: Add trace events for sample Add trace event to report samples and their timestamp coming from the EC. It allows to check if the timestamps are correct and the filter is working correctly without introducing too much latency. To enable these events: cd /sys/kernel/debug/tracing/ echo 1 > events/cros_ec/enable echo 0 > events/cros_ec/cros_ec_request_start/enable echo 0 > events/cros_ec/cros_ec_request_done/enable echo 1 > tracing_on cat trace_pipe Observe event flowing: irq/105-chromeo-95 [000] .... 613.659758: cros_ec_sensorhub_timestamp: ... irq/105-chromeo-95 [000] .... 613.665219: cros_ec_sensorhub_filter: dx: ... Signed-off-by: Gwendal Grignou Signed-off-by: Enric Balletbo i Serra --- drivers/platform/chrome/Makefile | 2 +- .../platform/chrome/cros_ec_sensorhub_ring.c | 14 +++ drivers/platform/chrome/cros_ec_trace.h | 94 +++++++++++++++++++ 3 files changed, 109 insertions(+), 1 deletion(-) diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile index 41baccba033f..f901d2e43166 100644 --- a/drivers/platform/chrome/Makefile +++ b/drivers/platform/chrome/Makefile @@ -20,7 +20,7 @@ obj-$(CONFIG_CROS_EC_CHARDEV) += cros_ec_chardev.o obj-$(CONFIG_CROS_EC_LIGHTBAR) += cros_ec_lightbar.o obj-$(CONFIG_CROS_EC_VBC) += cros_ec_vbc.o obj-$(CONFIG_CROS_EC_DEBUGFS) += cros_ec_debugfs.o -cros-ec-sensorhub-objs := cros_ec_sensorhub.o cros_ec_sensorhub_ring.o +cros-ec-sensorhub-objs := cros_ec_sensorhub.o cros_ec_sensorhub_ring.o cros_ec_trace.o obj-$(CONFIG_CROS_EC_SENSORHUB) += cros-ec-sensorhub.o obj-$(CONFIG_CROS_EC_SYSFS) += cros_ec_sysfs.o obj-$(CONFIG_CROS_USBPD_LOGGER) += cros_usbpd_logger.o diff --git a/drivers/platform/chrome/cros_ec_sensorhub_ring.c b/drivers/platform/chrome/cros_ec_sensorhub_ring.c index 8921f24e83ba..98e37080f760 100644 --- a/drivers/platform/chrome/cros_ec_sensorhub_ring.c +++ b/drivers/platform/chrome/cros_ec_sensorhub_ring.c @@ -17,6 +17,8 @@ #include #include +#include "cros_ec_trace.h" + /* Precision of fixed point for the m values from the filter */ #define M_PRECISION BIT(23) @@ -291,6 +293,7 @@ cros_ec_sensor_ring_ts_filter_update(struct cros_ec_sensors_ts_filter_state state->median_m = 0; state->median_error = 0; } + trace_cros_ec_sensorhub_filter(state, dx, dy); } /** @@ -427,6 +430,11 @@ cros_ec_sensor_ring_process_event(struct cros_ec_sensorhub *sensorhub, if (new_timestamp - *current_timestamp > 0) *current_timestamp = new_timestamp; } + trace_cros_ec_sensorhub_timestamp(in->timestamp, + fifo_info->timestamp, + fifo_timestamp, + *current_timestamp, + now); } if (in->flags & MOTIONSENSE_SENSOR_FLAG_ODR) { @@ -460,6 +468,12 @@ cros_ec_sensor_ring_process_event(struct cros_ec_sensorhub *sensorhub, /* Regular sample */ out->sensor_id = in->sensor_num; + trace_cros_ec_sensorhub_data(in->sensor_num, + fifo_info->timestamp, + fifo_timestamp, + *current_timestamp, + now); + if (*current_timestamp - now > 0) { /* * This fix is needed to overcome the timestamp filter putting diff --git a/drivers/platform/chrome/cros_ec_trace.h b/drivers/platform/chrome/cros_ec_trace.h index f744b21bc655..f50b9f9b8610 100644 --- a/drivers/platform/chrome/cros_ec_trace.h +++ b/drivers/platform/chrome/cros_ec_trace.h @@ -15,6 +15,7 @@ #include #include #include +#include #include @@ -70,6 +71,99 @@ TRACE_EVENT(cros_ec_request_done, __entry->retval) ); +TRACE_EVENT(cros_ec_sensorhub_timestamp, + TP_PROTO(u32 ec_sample_timestamp, u32 ec_fifo_timestamp, s64 fifo_timestamp, + s64 current_timestamp, s64 current_time), + TP_ARGS(ec_sample_timestamp, ec_fifo_timestamp, fifo_timestamp, current_timestamp, + current_time), + TP_STRUCT__entry( + __field(u32, ec_sample_timestamp) + __field(u32, ec_fifo_timestamp) + __field(s64, fifo_timestamp) + __field(s64, current_timestamp) + __field(s64, current_time) + __field(s64, delta) + ), + TP_fast_assign( + __entry->ec_sample_timestamp = ec_sample_timestamp; + __entry->ec_fifo_timestamp = ec_fifo_timestamp; + __entry->fifo_timestamp = fifo_timestamp; + __entry->current_timestamp = current_timestamp; + __entry->current_time = current_time; + __entry->delta = current_timestamp - current_time; + ), + TP_printk("ec_ts: %12lld, ec_fifo_ts: %12lld, fifo_ts: %12lld, curr_ts: %12lld, curr_time: %12lld, delta %12lld", + __entry->ec_sample_timestamp, + __entry->ec_fifo_timestamp, + __entry->fifo_timestamp, + __entry->current_timestamp, + __entry->current_time, + __entry->delta + ) +); + +TRACE_EVENT(cros_ec_sensorhub_data, + TP_PROTO(u32 ec_sensor_num, u32 ec_fifo_timestamp, s64 fifo_timestamp, + s64 current_timestamp, s64 current_time), + TP_ARGS(ec_sensor_num, ec_fifo_timestamp, fifo_timestamp, current_timestamp, current_time), + TP_STRUCT__entry( + __field(u32, ec_sensor_num) + __field(u32, ec_fifo_timestamp) + __field(s64, fifo_timestamp) + __field(s64, current_timestamp) + __field(s64, current_time) + __field(s64, delta) + ), + TP_fast_assign( + __entry->ec_sensor_num = ec_sensor_num; + __entry->ec_fifo_timestamp = ec_fifo_timestamp; + __entry->fifo_timestamp = fifo_timestamp; + __entry->current_timestamp = current_timestamp; + __entry->current_time = current_time; + __entry->delta = current_timestamp - current_time; + ), + TP_printk("ec_num: %4d, ec_fifo_ts: %12lld, fifo_ts: %12lld, curr_ts: %12lld, curr_time: %12lld, delta %12lld", + __entry->ec_sensor_num, + __entry->ec_fifo_timestamp, + __entry->fifo_timestamp, + __entry->current_timestamp, + __entry->current_time, + __entry->delta + ) +); + +TRACE_EVENT(cros_ec_sensorhub_filter, + TP_PROTO(struct cros_ec_sensors_ts_filter_state *state, s64 dx, s64 dy), + TP_ARGS(state, dx, dy), + TP_STRUCT__entry( + __field(s64, dx) + __field(s64, dy) + __field(s64, median_m) + __field(s64, median_error) + __field(s64, history_len) + __field(s64, x) + __field(s64, y) + ), + TP_fast_assign( + __entry->dx = dx; + __entry->dy = dy; + __entry->median_m = state->median_m; + __entry->median_error = state->median_error; + __entry->history_len = state->history_len; + __entry->x = state->x_offset; + __entry->y = state->y_offset; + ), + TP_printk("dx: %12lld. dy: %12lld median_m: %12lld median_error: %12lld len: %d x: %12lld y: %12lld", + __entry->dx, + __entry->dy, + __entry->median_m, + __entry->median_error, + __entry->history_len, + __entry->x, + __entry->y + ) +); + #endif /* _CROS_EC_TRACE_H_ */ From 3abc16af57c9939724df92fcbda296b25cc95168 Mon Sep 17 00:00:00 2001 From: Patryk Duda Date: Tue, 18 May 2021 16:07:58 +0200 Subject: [PATCH 052/696] platform/chrome: cros_ec_proto: Send command again when timeout occurs Sometimes kernel is trying to probe Fingerprint MCU (FPMCU) when it hasn't initialized SPI yet. This can happen because FPMCU is restarted during system boot and kernel can send message in short window eg. between sysjump to RW and SPI initialization. Cc: # 4.4+ Signed-off-by: Patryk Duda Link: https://lore.kernel.org/r/20210518140758.29318-1-pdk@semihalf.com Signed-off-by: Benson Leung --- drivers/platform/chrome/cros_ec_proto.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c index aa7f7aa77297..a7404d69b2d3 100644 --- a/drivers/platform/chrome/cros_ec_proto.c +++ b/drivers/platform/chrome/cros_ec_proto.c @@ -279,6 +279,15 @@ static int cros_ec_host_command_proto_query(struct cros_ec_device *ec_dev, msg->insize = sizeof(struct ec_response_get_protocol_info); ret = send_command(ec_dev, msg); + /* + * Send command once again when timeout occurred. + * Fingerprint MCU (FPMCU) is restarted during system boot which + * introduces small window in which FPMCU won't respond for any + * messages sent by kernel. There is no need to wait before next + * attempt because we waited at least EC_MSG_DEADLINE_MS. + */ + if (ret == -ETIMEDOUT) + ret = send_command(ec_dev, msg); if (ret < 0) { dev_dbg(ec_dev->dev, From f997ea3b7afc108eb9761f321b57de2d089c7c48 Mon Sep 17 00:00:00 2001 From: Xie Yongji Date: Mon, 17 May 2021 16:35:57 +0800 Subject: [PATCH 053/696] 9p/trans_virtio: Remove sysfs file on probe failure This ensures we don't leak the sysfs file if we failed to allocate chan->vc_wq during probe. Link: http://lkml.kernel.org/r/20210517083557.172-1-xieyongji@bytedance.com Fixes: 86c8437383ac ("net/9p: Add sysfs mount_tag file for virtio 9P device") Signed-off-by: Xie Yongji Signed-off-by: Dominique Martinet --- net/9p/trans_virtio.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index 2bbd7dce0f1d..490a4c900339 100644 --- a/net/9p/trans_virtio.c +++ b/net/9p/trans_virtio.c @@ -610,7 +610,7 @@ static int p9_virtio_probe(struct virtio_device *vdev) chan->vc_wq = kmalloc(sizeof(wait_queue_head_t), GFP_KERNEL); if (!chan->vc_wq) { err = -ENOMEM; - goto out_free_tag; + goto out_remove_file; } init_waitqueue_head(chan->vc_wq); chan->ring_bufs_avail = 1; @@ -628,6 +628,8 @@ static int p9_virtio_probe(struct virtio_device *vdev) return 0; +out_remove_file: + sysfs_remove_file(&vdev->dev.kobj, &dev_attr_mount_tag.attr); out_free_tag: kfree(tag); out_free_vq: From 732b33d0dbf17e9483f0b50385bf606f724f50a2 Mon Sep 17 00:00:00 2001 From: Harshvardhan Jha Date: Tue, 27 Jul 2021 05:37:10 +0530 Subject: [PATCH 054/696] 9p/xen: Fix end of loop tests for list_for_each_entry This patch addresses the following problems: - priv can never be NULL, so this part of the check is useless - if the loop ran through the whole list, priv->client is invalid and it is more appropriate and sufficient to check for the end of list_for_each_entry loop condition. Link: http://lkml.kernel.org/r/20210727000709.225032-1-harshvardhan.jha@oracle.com Signed-off-by: Harshvardhan Jha Reviewed-by: Stefano Stabellini Tested-by: Stefano Stabellini Cc: Signed-off-by: Dominique Martinet --- net/9p/trans_xen.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/9p/trans_xen.c b/net/9p/trans_xen.c index f4fea28e05da..3ec1a51a6944 100644 --- a/net/9p/trans_xen.c +++ b/net/9p/trans_xen.c @@ -138,7 +138,7 @@ static bool p9_xen_write_todo(struct xen_9pfs_dataring *ring, RING_IDX size) static int p9_xen_request(struct p9_client *client, struct p9_req_t *p9_req) { - struct xen_9pfs_front_priv *priv = NULL; + struct xen_9pfs_front_priv *priv; RING_IDX cons, prod, masked_cons, masked_prod; unsigned long flags; u32 size = p9_req->tc.size; @@ -151,7 +151,7 @@ static int p9_xen_request(struct p9_client *client, struct p9_req_t *p9_req) break; } read_unlock(&xen_9pfs_lock); - if (!priv || priv->client != client) + if (list_entry_is_head(priv, &xen_9pfs_devs, list)) return -EINVAL; num = p9_req->tc.tag % priv->num_rings; From 75ba9a715cb65e9c3fb17f13929d8741e570795f Mon Sep 17 00:00:00 2001 From: Baokun Li Date: Tue, 8 Jun 2021 11:09:05 +0800 Subject: [PATCH 055/696] dmaengine: xilinx_dma: Use list_move_tail instead of list_del/list_add_tail Using list_move_tail() instead of list_del() + list_add_tail(). Reported-by: Hulk Robot Signed-off-by: Baokun Li Reviewed-by: Radhey Shyam Pandey Link: https://lore.kernel.org/r/20210608030905.2818831-1-libaokun1@huawei.com Signed-off-by: Vinod Koul --- drivers/dma/xilinx/xilinx_dma.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c index 4b9530a7bf65..213e1a7314b7 100644 --- a/drivers/dma/xilinx/xilinx_dma.c +++ b/drivers/dma/xilinx/xilinx_dma.c @@ -1420,8 +1420,7 @@ static void xilinx_vdma_start_transfer(struct xilinx_dma_chan *chan) chan->desc_submitcount++; chan->desc_pendingcount--; - list_del(&desc->node); - list_add_tail(&desc->node, &chan->active_list); + list_move_tail(&desc->node, &chan->active_list); if (chan->desc_submitcount == chan->num_frms) chan->desc_submitcount = 0; From df208d63cfc5128529059d28565bd8754da2dbd5 Mon Sep 17 00:00:00 2001 From: Baokun Li Date: Wed, 9 Jun 2021 15:28:02 +0800 Subject: [PATCH 056/696] dmaengine: fsl-dpaa2-qdma: Use list_move_tail instead of list_del/list_add_tail Using list_move_tail() instead of list_del() + list_add_tail(). Reported-by: Hulk Robot Signed-off-by: Baokun Li Link: https://lore.kernel.org/r/20210609072802.1368785-1-libaokun1@huawei.com Signed-off-by: Vinod Koul --- drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.c b/drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.c index 4ae057922ef1..a0358f2c5cbb 100644 --- a/drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.c +++ b/drivers/dma/fsl-dpaa2-qdma/dpaa2-qdma.c @@ -291,9 +291,8 @@ static void dpaa2_qdma_issue_pending(struct dma_chan *chan) err = dpaa2_io_service_enqueue_fq(NULL, dpaa2_chan->fqid, fd); if (err) { - list_del(&dpaa2_comp->list); - list_add_tail(&dpaa2_comp->list, - &dpaa2_chan->comp_free); + list_move_tail(&dpaa2_comp->list, + &dpaa2_chan->comp_free); } } err_enqueue: @@ -626,8 +625,7 @@ static void dpaa2_qdma_free_desc(struct virt_dma_desc *vdesc) dpaa2_comp = to_fsl_qdma_comp(vdesc); qchan = dpaa2_comp->qchan; spin_lock_irqsave(&qchan->queue_lock, flags); - list_del(&dpaa2_comp->list); - list_add_tail(&dpaa2_comp->list, &qchan->comp_free); + list_move_tail(&dpaa2_comp->list, &qchan->comp_free); spin_unlock_irqrestore(&qchan->queue_lock, flags); } From 48594dbf793a15ee1a63ed879691cf436c14f459 Mon Sep 17 00:00:00 2001 From: Baokun Li Date: Wed, 9 Jun 2021 15:13:49 +0800 Subject: [PATCH 057/696] dmaengine: zynqmp_dma: Use list_move_tail instead of list_del/list_add_tail Using list_move_tail() instead of list_del() + list_add_tail(). Reported-by: Hulk Robot Signed-off-by: Baokun Li Link: https://lore.kernel.org/r/20210609071349.1336853-1-libaokun1@huawei.com Signed-off-by: Vinod Koul --- drivers/dma/xilinx/zynqmp_dma.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/dma/xilinx/zynqmp_dma.c b/drivers/dma/xilinx/zynqmp_dma.c index 5fecf5aa6e85..97f02f8eb03a 100644 --- a/drivers/dma/xilinx/zynqmp_dma.c +++ b/drivers/dma/xilinx/zynqmp_dma.c @@ -434,8 +434,7 @@ static void zynqmp_dma_free_descriptor(struct zynqmp_dma_chan *chan, struct zynqmp_dma_desc_sw *child, *next; chan->desc_free_cnt++; - list_del(&sdesc->node); - list_add_tail(&sdesc->node, &chan->free_list); + list_move_tail(&sdesc->node, &chan->free_list); list_for_each_entry_safe(child, next, &sdesc->tx_list, node) { chan->desc_free_cnt++; list_move_tail(&child->node, &chan->free_list); From 26f1ca91d242a506bc4461c5b8f33f457d2608ba Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Wed, 16 Jun 2021 22:34:38 +0200 Subject: [PATCH 058/696] dmaengine: hisi_dma: Remove some useless code When using 'pcim_enable_device()', 'pci_alloc_irq_vectors()' is auto-magically a managed function. It is useless (but harmless) to record an action to explicitly call 'pci_free_irq_vectors()'. So keep things simple, comment why and how these resources are freed, axe some useless code and save some memory. Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/4f8932e2d0d8d092bf60272511100030e013bc72.1623875508.git.christophe.jaillet@wanadoo.fr Signed-off-by: Vinod Koul --- drivers/dma/hisi_dma.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/dma/hisi_dma.c b/drivers/dma/hisi_dma.c index a259ee010e9b..c855a0e4f9ff 100644 --- a/drivers/dma/hisi_dma.c +++ b/drivers/dma/hisi_dma.c @@ -133,11 +133,6 @@ static inline void hisi_dma_update_bit(void __iomem *addr, u32 pos, bool val) writel_relaxed(tmp, addr); } -static void hisi_dma_free_irq_vectors(void *data) -{ - pci_free_irq_vectors(data); -} - static void hisi_dma_pause_dma(struct hisi_dma_dev *hdma_dev, u32 index, bool pause) { @@ -544,6 +539,7 @@ static int hisi_dma_probe(struct pci_dev *pdev, const struct pci_device_id *id) pci_set_drvdata(pdev, hdma_dev); pci_set_master(pdev); + /* This will be freed by 'pcim_release()'. See 'pcim_enable_device()' */ ret = pci_alloc_irq_vectors(pdev, HISI_DMA_MSI_NUM, HISI_DMA_MSI_NUM, PCI_IRQ_MSI); if (ret < 0) { @@ -551,10 +547,6 @@ static int hisi_dma_probe(struct pci_dev *pdev, const struct pci_device_id *id) return ret; } - ret = devm_add_action_or_reset(dev, hisi_dma_free_irq_vectors, pdev); - if (ret) - return ret; - dma_dev = &hdma_dev->dma_dev; dma_cap_set(DMA_MEMCPY, dma_dev->cap_mask); dma_dev->device_free_chan_resources = hisi_dma_free_chan_resources; From 4aece33cacf726d34ecd8824aee369652ec2beec Mon Sep 17 00:00:00 2001 From: Olivier Dautricourt Date: Thu, 17 Jun 2021 21:52:32 +0200 Subject: [PATCH 059/696] dt-bindings: dma: altera-msgdma: make response port optional Response port is not required in some configuration of the IP core. Signed-off-by: Olivier Dautricourt Reviewed-by: Rob Herring Reviewed-by: Stefan Roese Link: https://lore.kernel.org/r/fb28146a23a182be9e5435c1d3e5cac36b372294.1623898678.git.olivier.dautricourt@orolia.com Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/dma/altr,msgdma.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/dma/altr,msgdma.yaml b/Documentation/devicetree/bindings/dma/altr,msgdma.yaml index a4f9fe23dcd9..b193ee2db4a7 100644 --- a/Documentation/devicetree/bindings/dma/altr,msgdma.yaml +++ b/Documentation/devicetree/bindings/dma/altr,msgdma.yaml @@ -24,13 +24,15 @@ properties: items: - description: Control and Status Register Slave Port - description: Descriptor Slave Port - - description: Response Slave Port + - description: Response Slave Port (Optional) + minItems: 2 reg-names: items: - const: csr - const: desc - const: resp + minItems: 2 interrupts: maxItems: 1 From af2eec750281e581a16b6449b83ce5e994b79d89 Mon Sep 17 00:00:00 2001 From: Olivier Dautricourt Date: Thu, 17 Jun 2021 21:53:18 +0200 Subject: [PATCH 060/696] dmaengine: altera-msgdma: make response port optional The response slave port can be disabled in some configuration [1] and csr + MSGDMA_CSR_RESP_FILL_LEVEL will be 0 even if transfer has suceeded. We have to only rely on the interrupts in that scenario. This was tested on cyclone V with the controller resp port disabled. [1] https://www.intel.com/content/www/us/en/programmable/documentation/sfo1400787952932.html 30.3.1.2 30.3.1.3 30.5.5 Fixes: https://forum.rocketboards.org/t/ip-msgdma-linux-driver/1919 Signed-off-by: Olivier Dautricourt Reviewed-by: Stefan Roese Link: https://lore.kernel.org/r/8220756f2191ca08cb21702252d1f2d4f753a7f5.1623898678.git.olivier.dautricourt@orolia.com Signed-off-by: Vinod Koul --- drivers/dma/altera-msgdma.c | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/drivers/dma/altera-msgdma.c b/drivers/dma/altera-msgdma.c index 0fe0676f8e1d..5a2c7573b692 100644 --- a/drivers/dma/altera-msgdma.c +++ b/drivers/dma/altera-msgdma.c @@ -691,10 +691,14 @@ static void msgdma_tasklet(struct tasklet_struct *t) spin_lock_irqsave(&mdev->lock, flags); - /* Read number of responses that are available */ - count = ioread32(mdev->csr + MSGDMA_CSR_RESP_FILL_LEVEL); - dev_dbg(mdev->dev, "%s (%d): response count=%d\n", - __func__, __LINE__, count); + if (mdev->resp) { + /* Read number of responses that are available */ + count = ioread32(mdev->csr + MSGDMA_CSR_RESP_FILL_LEVEL); + dev_dbg(mdev->dev, "%s (%d): response count=%d\n", + __func__, __LINE__, count); + } else { + count = 1; + } while (count--) { /* @@ -703,8 +707,12 @@ static void msgdma_tasklet(struct tasklet_struct *t) * have any real values, like transferred bytes or error * bits. So we need to just drop these values. */ - size = ioread32(mdev->resp + MSGDMA_RESP_BYTES_TRANSFERRED); - status = ioread32(mdev->resp + MSGDMA_RESP_STATUS); + if (mdev->resp) { + size = ioread32(mdev->resp + + MSGDMA_RESP_BYTES_TRANSFERRED); + status = ioread32(mdev->resp + + MSGDMA_RESP_STATUS); + } msgdma_complete_descriptor(mdev); msgdma_chan_desc_cleanup(mdev); @@ -757,14 +765,21 @@ static void msgdma_dev_remove(struct msgdma_device *mdev) } static int request_and_map(struct platform_device *pdev, const char *name, - struct resource **res, void __iomem **ptr) + struct resource **res, void __iomem **ptr, + bool optional) { struct resource *region; struct device *device = &pdev->dev; *res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); if (*res == NULL) { - dev_err(device, "resource %s not defined\n", name); + if (optional) { + *ptr = NULL; + dev_info(device, "optional resource %s not defined\n", + name); + return 0; + } + dev_err(device, "mandatory resource %s not defined\n", name); return -ENODEV; } @@ -805,17 +820,17 @@ static int msgdma_probe(struct platform_device *pdev) mdev->dev = &pdev->dev; /* Map CSR space */ - ret = request_and_map(pdev, "csr", &dma_res, &mdev->csr); + ret = request_and_map(pdev, "csr", &dma_res, &mdev->csr, false); if (ret) return ret; /* Map (extended) descriptor space */ - ret = request_and_map(pdev, "desc", &dma_res, &mdev->desc); + ret = request_and_map(pdev, "desc", &dma_res, &mdev->desc, false); if (ret) return ret; /* Map response space */ - ret = request_and_map(pdev, "resp", &dma_res, &mdev->resp); + ret = request_and_map(pdev, "resp", &dma_res, &mdev->resp, true); if (ret) return ret; From ef94b0413bf4e0d328989fecf5b773e82c8794ac Mon Sep 17 00:00:00 2001 From: Amelie Delaunay Date: Thu, 24 Jun 2021 11:39:58 +0200 Subject: [PATCH 061/696] dt-bindings: dma: add alternative REQ/ACK protocol selection in stm32-dma Default REQ/ACK protocol consists in maintaining ACK signal up to the removal of REQuest and the transfer completion. In case of alternative REQ/ACK protocol, ACK de-assertion does not wait the removal of the REQuest, but only the transfer completion. Due to a possible DMA stream lock when transferring data to/from STM32 USART/UART, this new bindings allow to select this alternative protocol in device tree, especially for STM32 USART/UART nodes. Signed-off-by: Amelie Delaunay Acked-by: Rob Herring Link: https://lore.kernel.org/r/20210624093959.142265-2-amelie.delaunay@foss.st.com Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/dma/st,stm32-dma.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Documentation/devicetree/bindings/dma/st,stm32-dma.yaml b/Documentation/devicetree/bindings/dma/st,stm32-dma.yaml index 2a5325f480f6..4bf676fd25dc 100644 --- a/Documentation/devicetree/bindings/dma/st,stm32-dma.yaml +++ b/Documentation/devicetree/bindings/dma/st,stm32-dma.yaml @@ -40,6 +40,13 @@ description: | 0x0: FIFO mode with threshold selectable with bit 0-1 0x1: Direct mode: each DMA request immediately initiates a transfer from/to the memory, FIFO is bypassed. + -bit 4: alternative DMA request/acknowledge protocol + 0x0: Use standard DMA ACK management, where ACK signal is maintained + up to the removal of request and transfer completion + 0x1: Use alternative DMA ACK management, where ACK de-assertion does + not wait for the de-assertion of the REQuest, ACK is only managed + by transfer completion. This must only be used on channels + managing transfers for STM32 USART/UART. maintainers: From 2b5b74054c214ed2192713b88799fbc4cda8a1fe Mon Sep 17 00:00:00 2001 From: Amelie Delaunay Date: Thu, 24 Jun 2021 11:39:59 +0200 Subject: [PATCH 062/696] dmaengine: stm32-dma: add alternate REQ/ACK protocol management STM32 USART/UART is not managing correctly the default DMA REQ/ACK protocol leading to possibly lock the DMA stream. Default protocol consists in maintaining ACK signal up to the removal of REQuest and the transfer completion. In case of alternative REQ/ACK protocol, ACK de-assertion does not wait the removal of the REQuest, but only the transfer completion. This patch retrieves the need of the alternative protocol through the device tree, and sets the protocol accordingly. It also unwrap STM32_DMA_DIRECT_MODE_GET macro definition for consistency with new STM32_DMA_ALT_ACK_MODE_GET macro definition. Signed-off-by: Amelie Delaunay Link: https://lore.kernel.org/r/20210624093959.142265-3-amelie.delaunay@foss.st.com Signed-off-by: Vinod Koul --- drivers/dma/stm32-dma.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c index f54ecb123a52..d3aa34b3d2f7 100644 --- a/drivers/dma/stm32-dma.c +++ b/drivers/dma/stm32-dma.c @@ -60,6 +60,7 @@ #define STM32_DMA_SCR_PSIZE_GET(n) ((n & STM32_DMA_SCR_PSIZE_MASK) >> 11) #define STM32_DMA_SCR_DIR_MASK GENMASK(7, 6) #define STM32_DMA_SCR_DIR(n) ((n & 0x3) << 6) +#define STM32_DMA_SCR_TRBUFF BIT(20) /* Bufferable transfer for USART/UART */ #define STM32_DMA_SCR_CT BIT(19) /* Target in double buffer */ #define STM32_DMA_SCR_DBM BIT(18) /* Double Buffer Mode */ #define STM32_DMA_SCR_PINCOS BIT(15) /* Peripheral inc offset size */ @@ -138,8 +139,9 @@ #define STM32_DMA_THRESHOLD_FTR_MASK GENMASK(1, 0) #define STM32_DMA_THRESHOLD_FTR_GET(n) ((n) & STM32_DMA_THRESHOLD_FTR_MASK) #define STM32_DMA_DIRECT_MODE_MASK BIT(2) -#define STM32_DMA_DIRECT_MODE_GET(n) (((n) & STM32_DMA_DIRECT_MODE_MASK) \ - >> 2) +#define STM32_DMA_DIRECT_MODE_GET(n) (((n) & STM32_DMA_DIRECT_MODE_MASK) >> 2) +#define STM32_DMA_ALT_ACK_MODE_MASK BIT(4) +#define STM32_DMA_ALT_ACK_MODE_GET(n) (((n) & STM32_DMA_ALT_ACK_MODE_MASK) >> 4) enum stm32_dma_width { STM32_DMA_BYTE, @@ -1252,6 +1254,8 @@ static void stm32_dma_set_config(struct stm32_dma_chan *chan, chan->threshold = STM32_DMA_THRESHOLD_FTR_GET(cfg->features); if (STM32_DMA_DIRECT_MODE_GET(cfg->features)) chan->threshold = STM32_DMA_FIFO_THRESHOLD_NONE; + if (STM32_DMA_ALT_ACK_MODE_GET(cfg->features)) + chan->chan_reg.dma_scr |= STM32_DMA_SCR_TRBUFF; } static struct dma_chan *stm32_dma_of_xlate(struct of_phandle_args *dma_spec, From 48ae638be56b43cde9ddca20fc5678401886f5db Mon Sep 17 00:00:00 2001 From: Salah Triki Date: Sat, 10 Jul 2021 17:54:32 +0100 Subject: [PATCH 063/696] ppc4xx: replace sscanf() by kstrtoul() Fix the checkpatch.pl warning: "Prefer kstrto to single variable sscanf". Signed-off-by: Salah Triki Link: https://lore.kernel.org/r/20210710165432.GA690401@pc Signed-off-by: Vinod Koul --- drivers/dma/ppc4xx/adma.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/dma/ppc4xx/adma.c b/drivers/dma/ppc4xx/adma.c index df7704053d91..e2b5129c5f84 100644 --- a/drivers/dma/ppc4xx/adma.c +++ b/drivers/dma/ppc4xx/adma.c @@ -4319,6 +4319,7 @@ static ssize_t enable_store(struct device_driver *dev, const char *buf, size_t count) { unsigned long val; + int err; if (!count || count > 11) return -EINVAL; @@ -4327,7 +4328,10 @@ static ssize_t enable_store(struct device_driver *dev, const char *buf, return -EFAULT; /* Write a key */ - sscanf(buf, "%lx", &val); + err = kstrtoul(buf, 16, &val); + if (err) + return err; + dcr_write(ppc440spe_mq_dcr_host, DCRN_MQ0_XORBA, val); isync(); @@ -4368,7 +4372,7 @@ static ssize_t poly_store(struct device_driver *dev, const char *buf, size_t count) { unsigned long reg, val; - + int err; #ifdef CONFIG_440SP /* 440SP uses default 0x14D polynomial only */ return -EINVAL; @@ -4378,7 +4382,9 @@ static ssize_t poly_store(struct device_driver *dev, const char *buf, return -EINVAL; /* e.g., 0x14D or 0x11D */ - sscanf(buf, "%lx", &val); + err = kstrtoul(buf, 16, &val); + if (err) + return err; if (val & ~0x1FF) return -EINVAL; From 059e969c2a7d9efb463c0d8c574f1b3f1e010bed Mon Sep 17 00:00:00 2001 From: Zhang Qilong Date: Mon, 7 Jun 2021 14:46:40 +0800 Subject: [PATCH 064/696] dmaengine: tegra210-adma: Using pm_runtime_resume_and_get to replace open coding use pm_runtime_resume_and_get() to replace pm_runtime_get_sync and pm_runtime_put_noidle. this change is just to simplify the code, there is no actual functional change. Signed-off-by: Zhang Qilong Link: https://lore.kernel.org/r/20210607064640.121394-4-zhangqilong3@huawei.com Signed-off-by: Vinod Koul --- drivers/dma/tegra210-adma.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/dma/tegra210-adma.c b/drivers/dma/tegra210-adma.c index 4735742e826d..b1115a6d1935 100644 --- a/drivers/dma/tegra210-adma.c +++ b/drivers/dma/tegra210-adma.c @@ -655,9 +655,8 @@ static int tegra_adma_alloc_chan_resources(struct dma_chan *dc) return ret; } - ret = pm_runtime_get_sync(tdc2dev(tdc)); + ret = pm_runtime_resume_and_get(tdc2dev(tdc)); if (ret < 0) { - pm_runtime_put_noidle(tdc2dev(tdc)); free_irq(tdc->irq, tdc); return ret; } @@ -869,10 +868,8 @@ static int tegra_adma_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); ret = pm_runtime_get_sync(&pdev->dev); - if (ret < 0) { - pm_runtime_put_noidle(&pdev->dev); + if (ret < 0) goto rpm_disable; - } ret = tegra_adma_init(tdma); if (ret) From 258cb692b82025d0e6e1cccb72baa60ff78d0ce8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= Date: Wed, 28 Jul 2021 11:46:07 +0200 Subject: [PATCH 065/696] dmaengine: at_xdmac: use platform_driver_register MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When using SCMI clocks, the clocks are probed later than subsys initcall level. This driver uses platform_driver_probe which is not compatible with deferred probing and won't be probed again later if probe function fails due to clocks not being available at that time. This patch replaces the use of platform_driver_probe with platform_driver_register which will allow probing the driver later again when clocks will be available. Signed-off-by: Clément Léger Link: https://lore.kernel.org/r/20210728094607.50589-1-clement.leger@bootlin.com Signed-off-by: Vinod Koul --- drivers/dma/at_xdmac.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index 64a52bf4d737..ab78e0f6afd7 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -2240,10 +2240,16 @@ static struct platform_driver at_xdmac_driver = { static int __init at_xdmac_init(void) { - return platform_driver_probe(&at_xdmac_driver, at_xdmac_probe); + return platform_driver_register(&at_xdmac_driver); } subsys_initcall(at_xdmac_init); +static void __exit at_xdmac_exit(void) +{ + platform_driver_unregister(&at_xdmac_driver); +} +module_exit(at_xdmac_exit); + MODULE_DESCRIPTION("Atmel Extended DMA Controller driver"); MODULE_AUTHOR("Ludovic Desroches "); MODULE_LICENSE("GPL"); From ade8a86b512cf8db0d0e975a971ce356953cfcb3 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Tue, 20 Jul 2021 13:42:10 -0700 Subject: [PATCH 066/696] dmaengine: idxd: Set defaults for GRPCFG traffic class Set GRPCFG traffic class to value of 1 for best performance on current generation of accelerators. Also add override option to allow experimentation. Sysfs knobs are disabled for DSA/IAX gen1 devices. Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/162681373005.1968485.3761065664382799202.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul --- Documentation/admin-guide/kernel-parameters.txt | 5 +++++ drivers/dma/idxd/idxd.h | 1 + drivers/dma/idxd/init.c | 13 +++++++++++-- drivers/dma/idxd/registers.h | 3 +++ drivers/dma/idxd/sysfs.c | 6 ++++++ 5 files changed, 26 insertions(+), 2 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index bdb22006f713..ec5411cdec20 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -1747,6 +1747,11 @@ support for the idxd driver. By default it is set to true (1). + idxd.tc_override= [HW] + Format: + Allow override of default traffic class configuration + for the device. By default it is set to false (0). + ieee754= [MIPS] Select IEEE Std 754 conformance mode Format: { strict | legacy | 2008 | relaxed } Default: strict diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h index d0874d8877d9..4e4dc0110e77 100644 --- a/drivers/dma/idxd/idxd.h +++ b/drivers/dma/idxd/idxd.h @@ -16,6 +16,7 @@ #define IDXD_DRIVER_VERSION "1.00" extern struct kmem_cache *idxd_desc_pool; +extern bool tc_override; struct idxd_wq; struct idxd_dev; diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c index 8db56f98059f..eb09bc591c31 100644 --- a/drivers/dma/idxd/init.c +++ b/drivers/dma/idxd/init.c @@ -32,6 +32,10 @@ static bool sva = true; module_param(sva, bool, 0644); MODULE_PARM_DESC(sva, "Toggle SVA support on/off"); +bool tc_override; +module_param(tc_override, bool, 0644); +MODULE_PARM_DESC(tc_override, "Override traffic class defaults"); + #define DRV_NAME "idxd" bool support_enqcmd; @@ -336,8 +340,13 @@ static int idxd_setup_groups(struct idxd_device *idxd) } idxd->groups[i] = group; - group->tc_a = -1; - group->tc_b = -1; + if (idxd->hw.version < DEVICE_VERSION_2 && !tc_override) { + group->tc_a = 1; + group->tc_b = 1; + } else { + group->tc_a = -1; + group->tc_b = -1; + } } return 0; diff --git a/drivers/dma/idxd/registers.h b/drivers/dma/idxd/registers.h index 7343a8f48819..ffc7550a77ee 100644 --- a/drivers/dma/idxd/registers.h +++ b/drivers/dma/idxd/registers.h @@ -7,6 +7,9 @@ #define PCI_DEVICE_ID_INTEL_DSA_SPR0 0x0b25 #define PCI_DEVICE_ID_INTEL_IAX_SPR0 0x0cfe +#define DEVICE_VERSION_1 0x100 +#define DEVICE_VERSION_2 0x200 + #define IDXD_MMIO_BAR 0 #define IDXD_WQ_BAR 2 #define IDXD_PORTAL_SIZE PAGE_SIZE diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c index b883e9f16e7f..881a12596d4b 100644 --- a/drivers/dma/idxd/sysfs.c +++ b/drivers/dma/idxd/sysfs.c @@ -327,6 +327,9 @@ static ssize_t group_traffic_class_a_store(struct device *dev, if (idxd->state == IDXD_DEV_ENABLED) return -EPERM; + if (idxd->hw.version < DEVICE_VERSION_2 && !tc_override) + return -EPERM; + if (val < 0 || val > 7) return -EINVAL; @@ -366,6 +369,9 @@ static ssize_t group_traffic_class_b_store(struct device *dev, if (idxd->state == IDXD_DEV_ENABLED) return -EPERM; + if (idxd->hw.version < DEVICE_VERSION_2 && !tc_override) + return -EPERM; + if (val < 0 || val > 7) return -EINVAL; From 568b2126466f926a10be0b53b40c2d6ae056d8d6 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Wed, 21 Jul 2021 11:35:03 -0700 Subject: [PATCH 067/696] dmaengine: idxd: fix uninit var for alt_drv 0-day detected uninitialized alt_drv variable in the bind_store() function. The branch can be taken when device is not idxd device or wq 'struct device'. Init alt_drv to NULL. Fixes: 6e7f3ee97bbe ("dmaengine: idxd: move dsa_drv support to compatible mode") Reported-by: kernel test robot Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/162689250332.2114335.636367120454420852.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/compat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/idxd/compat.c b/drivers/dma/idxd/compat.c index d67746ee0c1a..d7616c240dcd 100644 --- a/drivers/dma/idxd/compat.c +++ b/drivers/dma/idxd/compat.c @@ -34,7 +34,7 @@ static ssize_t bind_store(struct device_driver *drv, const char *buf, size_t cou { struct bus_type *bus = drv->bus; struct device *dev; - struct device_driver *alt_drv; + struct device_driver *alt_drv = NULL; int rc = -ENODEV; struct idxd_dev *idxd_dev; From 673d812d30be67942762bb9e8548abb26a3ba4a7 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Thu, 22 Jul 2021 10:54:10 -0700 Subject: [PATCH 068/696] dmaengine: idxd: fix wq slot allocation index check The sbitmap wait and allocate routine checks the index that is returned from sbitmap_queue_get(). It should be idxd >= 0 as 0 is also a valid index. This fixes issue where submission path hangs when WQ size is 1. Fixes: 0705107fcc80 ("dmaengine: idxd: move submission to sbitmap_queue") Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/162697645067.3478714.506720687816951762.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/submit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/idxd/submit.c b/drivers/dma/idxd/submit.c index 6ef704dd4d0b..65b0130ab2db 100644 --- a/drivers/dma/idxd/submit.c +++ b/drivers/dma/idxd/submit.c @@ -59,7 +59,7 @@ struct idxd_desc *idxd_alloc_desc(struct idxd_wq *wq, enum idxd_op_type optype) if (signal_pending_state(TASK_INTERRUPTIBLE, current)) break; idx = sbitmap_queue_get(sbq, &cpu); - if (idx > 0) + if (idx >= 0) break; schedule(); } From a9c171527a3403cae6c1907744b1bc9ca301f912 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Tue, 20 Jul 2021 13:42:04 -0700 Subject: [PATCH 069/696] dmaengine: idxd: rotate portal address for better performance The device submission portal is on a 4k page and any of those 64bit aligned address on the page can be used for descriptor submission. By rotating the offset through the 4k range and prevent successive writes to the same MMIO address, performance improvement is observed through testing. Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/162681372446.1968485.10634280461681015569.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/device.c | 1 + drivers/dma/idxd/idxd.h | 20 ++++++++++++++++++++ drivers/dma/idxd/submit.c | 2 +- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c index 99350ac9a292..41f67a195eb6 100644 --- a/drivers/dma/idxd/device.c +++ b/drivers/dma/idxd/device.c @@ -320,6 +320,7 @@ void idxd_wq_unmap_portal(struct idxd_wq *wq) devm_iounmap(dev, wq->portal); wq->portal = NULL; + wq->portal_offset = 0; } void idxd_wqs_unmap_portal(struct idxd_device *idxd) diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h index 4e4dc0110e77..94983bced189 100644 --- a/drivers/dma/idxd/idxd.h +++ b/drivers/dma/idxd/idxd.h @@ -11,6 +11,7 @@ #include #include #include +#include #include "registers.h" #define IDXD_DRIVER_VERSION "1.00" @@ -162,6 +163,7 @@ struct idxd_dma_chan { struct idxd_wq { void __iomem *portal; + u32 portal_offset; struct percpu_ref wq_active; struct completion wq_dead; struct idxd_dev idxd_dev; @@ -468,6 +470,24 @@ static inline int idxd_get_wq_portal_full_offset(int wq_id, return ((wq_id * 4) << PAGE_SHIFT) + idxd_get_wq_portal_offset(prot); } +#define IDXD_PORTAL_MASK (PAGE_SIZE - 1) + +/* + * Even though this function can be accessed by multiple threads, it is safe to use. + * At worst the address gets used more than once before it gets incremented. We don't + * hit a threshold until iops becomes many million times a second. So the occasional + * reuse of the same address is tolerable compare to using an atomic variable. This is + * safe on a system that has atomic load/store for 32bit integers. Given that this is an + * Intel iEP device, that should not be a problem. + */ +static inline void __iomem *idxd_wq_portal_addr(struct idxd_wq *wq) +{ + int ofs = wq->portal_offset; + + wq->portal_offset = (ofs + sizeof(struct dsa_raw_desc)) & IDXD_PORTAL_MASK; + return wq->portal + ofs; +} + static inline void idxd_wq_get(struct idxd_wq *wq) { wq->client_count++; diff --git a/drivers/dma/idxd/submit.c b/drivers/dma/idxd/submit.c index 65b0130ab2db..92ae9a157cc9 100644 --- a/drivers/dma/idxd/submit.c +++ b/drivers/dma/idxd/submit.c @@ -146,7 +146,7 @@ int idxd_submit_desc(struct idxd_wq *wq, struct idxd_desc *desc) if (!percpu_ref_tryget_live(&wq->wq_active)) return -ENXIO; - portal = wq->portal; + portal = idxd_wq_portal_addr(wq); /* * The wmb() flushes writes to coherent DMA data before From 125d10373ad991888c9e94d2da49bcc5ccba2127 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Tue, 20 Jul 2021 13:42:15 -0700 Subject: [PATCH 070/696] dmanegine: idxd: add software command status Enabling device and wq returns standard errno and that does not provide enough details to indicate what exactly failed. The hardware command status is only 8bits. Expand the command status to 32bits and use the upper 16 bits to define software errors to provide more details on the exact failure. Bit 31 will be used to indicate the error is software set as the driver is using some of the spec defined hardware error as well. Cc: Ramesh Thomas Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/162681373579.1968485.5891788397526827892.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul --- .../ABI/stable/sysfs-driver-dma-idxd | 2 ++ drivers/dma/idxd/cdev.c | 5 +++- drivers/dma/idxd/device.c | 22 +++++++++++++++--- drivers/dma/idxd/dma.c | 4 ++++ drivers/dma/idxd/idxd.h | 2 +- drivers/dma/idxd/sysfs.c | 11 ++++++++- include/uapi/linux/idxd.h | 23 +++++++++++++++++++ 7 files changed, 63 insertions(+), 6 deletions(-) diff --git a/Documentation/ABI/stable/sysfs-driver-dma-idxd b/Documentation/ABI/stable/sysfs-driver-dma-idxd index adb0c93e8dfc..df4afbccf037 100644 --- a/Documentation/ABI/stable/sysfs-driver-dma-idxd +++ b/Documentation/ABI/stable/sysfs-driver-dma-idxd @@ -128,6 +128,8 @@ Date: Aug 28, 2020 KernelVersion: 5.10.0 Contact: dmaengine@vger.kernel.org Description: The last executed device administrative command's status/error. + Also last configuration error overloaded. + Writing to it will clear the status. What: /sys/bus/dsa/devices/wq./block_on_fault Date: Oct 27, 2020 diff --git a/drivers/dma/idxd/cdev.c b/drivers/dma/idxd/cdev.c index f6a4603517ba..4d2ecdb130e7 100644 --- a/drivers/dma/idxd/cdev.c +++ b/drivers/dma/idxd/cdev.c @@ -320,9 +320,12 @@ static int idxd_user_drv_probe(struct idxd_dev *idxd_dev) goto err; rc = idxd_wq_add_cdev(wq); - if (rc < 0) + if (rc < 0) { + idxd->cmd_status = IDXD_SCMD_CDEV_ERR; goto err_cdev; + } + idxd->cmd_status = 0; mutex_unlock(&wq->wq_lock); return 0; diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c index 41f67a195eb6..86fa4b4590f9 100644 --- a/drivers/dma/idxd/device.c +++ b/drivers/dma/idxd/device.c @@ -840,6 +840,7 @@ static int idxd_wq_config_write(struct idxd_wq *wq) wq->wqcfg->wq_size = wq->size; if (wq->size == 0) { + idxd->cmd_status = IDXD_SCMD_WQ_NO_SIZE; dev_warn(dev, "Incorrect work queue size: 0\n"); return -EINVAL; } @@ -975,6 +976,7 @@ static int idxd_wqs_setup(struct idxd_device *idxd) continue; if (wq_shared(wq) && !device_swq_supported(idxd)) { + idxd->cmd_status = IDXD_SCMD_WQ_NO_SWQ_SUPPORT; dev_warn(dev, "No shared wq support but configured.\n"); return -EINVAL; } @@ -983,8 +985,10 @@ static int idxd_wqs_setup(struct idxd_device *idxd) configured++; } - if (configured == 0) + if (configured == 0) { + idxd->cmd_status = IDXD_SCMD_WQ_NONE_CONFIGURED; return -EINVAL; + } return 0; } @@ -1140,21 +1144,26 @@ int __drv_enable_wq(struct idxd_wq *wq) lockdep_assert_held(&wq->wq_lock); - if (idxd->state != IDXD_DEV_ENABLED) + if (idxd->state != IDXD_DEV_ENABLED) { + idxd->cmd_status = IDXD_SCMD_DEV_NOT_ENABLED; goto err; + } if (wq->state != IDXD_WQ_DISABLED) { dev_dbg(dev, "wq %d already enabled.\n", wq->id); + idxd->cmd_status = IDXD_SCMD_WQ_ENABLED; rc = -EBUSY; goto err; } if (!wq->group) { dev_dbg(dev, "wq %d not attached to group.\n", wq->id); + idxd->cmd_status = IDXD_SCMD_WQ_NO_GRP; goto err; } if (strlen(wq->name) == 0) { + idxd->cmd_status = IDXD_SCMD_WQ_NO_NAME; dev_dbg(dev, "wq %d name not set.\n", wq->id); goto err; } @@ -1162,6 +1171,7 @@ int __drv_enable_wq(struct idxd_wq *wq) /* Shared WQ checks */ if (wq_shared(wq)) { if (!device_swq_supported(idxd)) { + idxd->cmd_status = IDXD_SCMD_WQ_NO_SVM; dev_dbg(dev, "PASID not enabled and shared wq.\n"); goto err; } @@ -1174,6 +1184,7 @@ int __drv_enable_wq(struct idxd_wq *wq) * threshold via sysfs. */ if (wq->threshold == 0) { + idxd->cmd_status = IDXD_SCMD_WQ_NO_THRESH; dev_dbg(dev, "Shared wq and threshold 0.\n"); goto err; } @@ -1197,6 +1208,7 @@ int __drv_enable_wq(struct idxd_wq *wq) rc = idxd_wq_map_portal(wq); if (rc < 0) { + idxd->cmd_status = IDXD_SCMD_WQ_PORTAL_ERR; dev_dbg(dev, "wq %d portal mapping failed: %d\n", wq->id, rc); goto err_map_portal; } @@ -1259,8 +1271,10 @@ int idxd_device_drv_probe(struct idxd_dev *idxd_dev) * enabled state, then the device was altered outside of driver's control. * If the state is in halted state, then we don't want to proceed. */ - if (idxd->state != IDXD_DEV_DISABLED) + if (idxd->state != IDXD_DEV_DISABLED) { + idxd->cmd_status = IDXD_SCMD_DEV_ENABLED; return -ENXIO; + } /* Device configuration */ spin_lock_irqsave(&idxd->dev_lock, flags); @@ -1279,9 +1293,11 @@ int idxd_device_drv_probe(struct idxd_dev *idxd_dev) rc = idxd_register_dma_device(idxd); if (rc < 0) { idxd_device_disable(idxd); + idxd->cmd_status = IDXD_SCMD_DEV_DMA_ERR; return rc; } + idxd->cmd_status = 0; return 0; } diff --git a/drivers/dma/idxd/dma.c b/drivers/dma/idxd/dma.c index 2fd7ec29a08f..a195225687bb 100644 --- a/drivers/dma/idxd/dma.c +++ b/drivers/dma/idxd/dma.c @@ -284,22 +284,26 @@ static int idxd_dmaengine_drv_probe(struct idxd_dev *idxd_dev) rc = idxd_wq_alloc_resources(wq); if (rc < 0) { + idxd->cmd_status = IDXD_SCMD_WQ_RES_ALLOC_ERR; dev_dbg(dev, "WQ resource alloc failed\n"); goto err_res_alloc; } rc = idxd_wq_init_percpu_ref(wq); if (rc < 0) { + idxd->cmd_status = IDXD_SCMD_PERCPU_ERR; dev_dbg(dev, "percpu_ref setup failed\n"); goto err_ref; } rc = idxd_register_dma_channel(wq); if (rc < 0) { + idxd->cmd_status = IDXD_SCMD_DMA_CHAN_ERR; dev_dbg(dev, "Failed to register dma channel\n"); goto err_dma; } + idxd->cmd_status = 0; mutex_unlock(&wq->wq_lock); return 0; diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h index 94983bced189..bfcb03329f77 100644 --- a/drivers/dma/idxd/idxd.h +++ b/drivers/dma/idxd/idxd.h @@ -252,7 +252,7 @@ struct idxd_device { unsigned long flags; int id; int major; - u8 cmd_status; + u32 cmd_status; struct pci_dev *pdev; void __iomem *reg_base; diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c index 881a12596d4b..4c01587c9d4a 100644 --- a/drivers/dma/idxd/sysfs.c +++ b/drivers/dma/idxd/sysfs.c @@ -1217,7 +1217,16 @@ static ssize_t cmd_status_show(struct device *dev, return sysfs_emit(buf, "%#x\n", idxd->cmd_status); } -static DEVICE_ATTR_RO(cmd_status); + +static ssize_t cmd_status_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct idxd_device *idxd = confdev_to_idxd(dev); + + idxd->cmd_status = 0; + return count; +} +static DEVICE_ATTR_RW(cmd_status); static struct attribute *idxd_device_attributes[] = { &dev_attr_version.attr, diff --git a/include/uapi/linux/idxd.h b/include/uapi/linux/idxd.h index e33997b4d750..1c0175aa0e42 100644 --- a/include/uapi/linux/idxd.h +++ b/include/uapi/linux/idxd.h @@ -9,6 +9,29 @@ #include #endif +/* Driver command error status */ +enum idxd_scmd_stat { + IDXD_SCMD_DEV_ENABLED = 0x80000010, + IDXD_SCMD_DEV_NOT_ENABLED = 0x80000020, + IDXD_SCMD_WQ_ENABLED = 0x80000021, + IDXD_SCMD_DEV_DMA_ERR = 0x80020000, + IDXD_SCMD_WQ_NO_GRP = 0x80030000, + IDXD_SCMD_WQ_NO_NAME = 0x80040000, + IDXD_SCMD_WQ_NO_SVM = 0x80050000, + IDXD_SCMD_WQ_NO_THRESH = 0x80060000, + IDXD_SCMD_WQ_PORTAL_ERR = 0x80070000, + IDXD_SCMD_WQ_RES_ALLOC_ERR = 0x80080000, + IDXD_SCMD_PERCPU_ERR = 0x80090000, + IDXD_SCMD_DMA_CHAN_ERR = 0x800a0000, + IDXD_SCMD_CDEV_ERR = 0x800b0000, + IDXD_SCMD_WQ_NO_SWQ_SUPPORT = 0x800c0000, + IDXD_SCMD_WQ_NONE_CONFIGURED = 0x800d0000, + IDXD_SCMD_WQ_NO_SIZE = 0x800e0000, +}; + +#define IDXD_SCMD_SOFTERR_MASK 0x80000000 +#define IDXD_SCMD_SOFTERR_SHIFT 16 + /* Descriptor flags */ #define IDXD_OP_FLAG_FENCE 0x0001 #define IDXD_OP_FLAG_BOF 0x0002 From b60bb6e2bfc192091b8f792781b83b5e0f9324f6 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Thu, 22 Jul 2021 13:10:51 -0700 Subject: [PATCH 071/696] dmaengine: idxd: fix abort status check Coverity static analysis of linux-next found issue. The check (status == IDXD_COMP_DESC_ABORT) is always false since status was previously masked with 0x7f and IDXD_COMP_DESC_ABORT is 0xff. Fixes: 6b4b87f2c31a ("dmaengine: idxd: fix submission race window") Reported-by: Colin Ian King Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/162698465160.3560828.18173186265683415384.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/irq.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/dma/idxd/irq.c b/drivers/dma/idxd/irq.c index e018459b534f..65dc7bbb0a13 100644 --- a/drivers/dma/idxd/irq.c +++ b/drivers/dma/idxd/irq.c @@ -194,7 +194,11 @@ static int irq_process_pending_llist(struct idxd_irq_entry *irq_entry, u8 status = desc->completion->status & DSA_COMP_STATUS_MASK; if (status) { - if (unlikely(status == IDXD_COMP_DESC_ABORT)) { + /* + * Check against the original status as ABORT is software defined + * and 0xff, which DSA_COMP_STATUS_MASK can mask out. + */ + if (unlikely(desc->completion->status == IDXD_COMP_DESC_ABORT)) { complete_desc(desc, IDXD_COMPLETE_ABORT); (*processed)++; continue; @@ -250,7 +254,11 @@ static int irq_process_work_list(struct idxd_irq_entry *irq_entry, list_for_each_entry(desc, &flist, list) { u8 status = desc->completion->status & DSA_COMP_STATUS_MASK; - if (unlikely(status == IDXD_COMP_DESC_ABORT)) { + /* + * Check against the original status as ABORT is software defined + * and 0xff, which DSA_COMP_STATUS_MASK can mask out. + */ + if (unlikely(desc->completion->status == IDXD_COMP_DESC_ABORT)) { complete_desc(desc, IDXD_COMPLETE_ABORT); continue; } From 5eea6c9712bd2a707216d7b923090510d60f9663 Mon Sep 17 00:00:00 2001 From: Jordy Zomer Date: Sat, 31 Jul 2021 11:19:38 +0200 Subject: [PATCH 072/696] dmaengine: usb-dmac: make usb_dmac_get_current_residue unsigned The usb_dmac_get_current_residue function used to take a signed integer as a pos parameter. The only callers of this function passes an unsigned integer to it. Therefore to make it obviously safe, let's just make this an unsgined integer as this is used in pointer arithmetics. Signed-off-by: Jordy Zomer Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20210731091939.510816-1-jordy@pwning.systems Signed-off-by: Vinod Koul --- drivers/dma/sh/usb-dmac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/sh/usb-dmac.c b/drivers/dma/sh/usb-dmac.c index 1cc06900153e..5edaeb89d1e6 100644 --- a/drivers/dma/sh/usb-dmac.c +++ b/drivers/dma/sh/usb-dmac.c @@ -466,7 +466,7 @@ static int usb_dmac_chan_terminate_all(struct dma_chan *chan) static unsigned int usb_dmac_get_current_residue(struct usb_dmac_chan *chan, struct usb_dmac_desc *desc, - int sg_index) + unsigned int sg_index) { struct usb_dmac_sg *sg = desc->sg + sg_index; u32 mem_addr = sg->mem_addr & 0xffffffff; From 32286e2793858a8491c2276b2754e9850467bb6b Mon Sep 17 00:00:00 2001 From: Pandith N Date: Mon, 2 Aug 2021 11:24:52 +0530 Subject: [PATCH 073/696] dmaengine: dw-axi-dmac: Remove free slot check algorithm in dw_axi_dma_set_hw_channel Removed free slot check algorithm in dw_axi_dma_set_hw_channel. For 8 DMA channels, use respective handshake slot in DMA_HS_SEL APB register. For every channel, an dedicated slot is provided in hardware handshake register AXIDMA_CTRL_DMA_HS_SEL_n. Peripheral source number is programmed in respective channel slots. Signed-off-by: Pandith N Tested-by: Pan Kris Link: https://lore.kernel.org/r/20210802055454.15192-2-pandith.n@intel.com Signed-off-by: Vinod Koul --- .../dma/dw-axi-dmac/dw-axi-dmac-platform.c | 49 +++++++------------ drivers/dma/dw-axi-dmac/dw-axi-dmac.h | 2 + 2 files changed, 21 insertions(+), 30 deletions(-) diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c index d9e4ac3edb4e..c3bb2b4820a3 100644 --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c @@ -470,18 +470,13 @@ static void dma_chan_free_chan_resources(struct dma_chan *dchan) pm_runtime_put(chan->chip->dev); } -static void dw_axi_dma_set_hw_channel(struct axi_dma_chip *chip, - u32 handshake_num, bool set) +static void dw_axi_dma_set_hw_channel(struct axi_dma_chan *chan, bool set) { - unsigned long start = 0; - unsigned long reg_value; - unsigned long reg_mask; - unsigned long reg_set; - unsigned long mask; - unsigned long val; + struct axi_dma_chip *chip = chan->chip; + unsigned long reg_value, val; if (!chip->apb_regs) { - dev_dbg(chip->dev, "apb_regs not initialized\n"); + dev_err(chip->dev, "apb_regs not initialized\n"); return; } @@ -490,26 +485,22 @@ static void dw_axi_dma_set_hw_channel(struct axi_dma_chip *chip, * Lock the DMA channel by assign a handshake number to the channel. * Unlock the DMA channel by assign 0x3F to the channel. */ - if (set) { - reg_set = UNUSED_CHANNEL; - val = handshake_num; - } else { - reg_set = handshake_num; + if (set) + val = chan->hw_handshake_num; + else val = UNUSED_CHANNEL; - } reg_value = lo_hi_readq(chip->apb_regs + DMAC_APB_HW_HS_SEL_0); - for_each_set_clump8(start, reg_mask, ®_value, 64) { - if (reg_mask == reg_set) { - mask = GENMASK_ULL(start + 7, start); - reg_value &= ~mask; - reg_value |= rol64(val, start); - lo_hi_writeq(reg_value, - chip->apb_regs + DMAC_APB_HW_HS_SEL_0); - break; - } - } + /* Channel is already allocated, set handshake as per channel ID */ + /* 64 bit write should handle for 8 channels */ + + reg_value &= ~(DMA_APB_HS_SEL_MASK << + (chan->id * DMA_APB_HS_SEL_BIT_SIZE)); + reg_value |= (val << (chan->id * DMA_APB_HS_SEL_BIT_SIZE)); + lo_hi_writeq(reg_value, chip->apb_regs + DMAC_APB_HW_HS_SEL_0); + + return; } /* @@ -742,7 +733,7 @@ dw_axi_dma_chan_prep_cyclic(struct dma_chan *dchan, dma_addr_t dma_addr, llp = hw_desc->llp; } while (total_segments); - dw_axi_dma_set_hw_channel(chan->chip, chan->hw_handshake_num, true); + dw_axi_dma_set_hw_channel(chan, true); return vchan_tx_prep(&chan->vc, &desc->vd, flags); @@ -822,7 +813,7 @@ dw_axi_dma_chan_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl, llp = hw_desc->llp; } while (num_sgs); - dw_axi_dma_set_hw_channel(chan->chip, chan->hw_handshake_num, true); + dw_axi_dma_set_hw_channel(chan, true); return vchan_tx_prep(&chan->vc, &desc->vd, flags); @@ -1098,8 +1089,7 @@ static int dma_chan_terminate_all(struct dma_chan *dchan) "%s failed to stop\n", axi_chan_name(chan)); if (chan->direction != DMA_MEM_TO_MEM) - dw_axi_dma_set_hw_channel(chan->chip, - chan->hw_handshake_num, false); + dw_axi_dma_set_hw_channel(chan, false); if (chan->direction == DMA_MEM_TO_DEV) dw_axi_dma_set_byte_halfword(chan, false); @@ -1365,7 +1355,6 @@ static int dw_probe(struct platform_device *pdev) if (ret) return ret; - INIT_LIST_HEAD(&dw->dma.channels); for (i = 0; i < hdata->nr_channels; i++) { struct axi_dma_chan *chan = &dw->chan[i]; diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h index b69897887c76..358f553cafe9 100644 --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h @@ -184,6 +184,8 @@ static inline struct axi_dma_chan *dchan_to_axi_dma_chan(struct dma_chan *dchan) #define DMAC_APB_HALFWORD_WR_CH_EN 0x020 /* DMAC Halfword write enables */ #define UNUSED_CHANNEL 0x3F /* Set unused DMA channel to 0x3F */ +#define DMA_APB_HS_SEL_BIT_SIZE 0x08 /* HW handshake bits per channel */ +#define DMA_APB_HS_SEL_MASK 0xFF /* HW handshake select masks */ #define MAX_BLOCK_SIZE 0x1000 /* 1024 blocks * 4 bytes data width */ /* DMAC_CFG */ From f95f3b53513d4bd846169fc42705548609494cce Mon Sep 17 00:00:00 2001 From: Pandith N Date: Mon, 2 Aug 2021 11:24:53 +0530 Subject: [PATCH 074/696] dmaengine: dw-axi-dmac: support parallel memory <--> peripheral transfers Added support for multiple DMA_MEM_TO_DEV, DMA_DEV_TO_MEM transfers in parallel. This is required for peripherals using DMA for transmit and receive operations at the same time. APB slot number needs to be programmed in channel hardware handshaking interface Signed-off-by: Pandith N Tested-by: Pan Kris Link: https://lore.kernel.org/r/20210802055454.15192-3-pandith.n@intel.com Signed-off-by: Vinod Koul --- drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 4 ++++ drivers/dma/dw-axi-dmac/dw-axi-dmac.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c index c3bb2b4820a3..3edc647271b4 100644 --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c @@ -363,12 +363,16 @@ static void axi_chan_block_xfer_start(struct axi_dma_chan *chan, DWAXIDMAC_TT_FC_MEM_TO_PER_DST : DWAXIDMAC_TT_FC_MEM_TO_PER_DMAC) << CH_CFG_H_TT_FC_POS; + if (chan->chip->apb_regs) + reg |= (chan->id << CH_CFG_H_DST_PER_POS); break; case DMA_DEV_TO_MEM: reg |= (chan->config.device_fc ? DWAXIDMAC_TT_FC_PER_TO_MEM_SRC : DWAXIDMAC_TT_FC_PER_TO_MEM_DMAC) << CH_CFG_H_TT_FC_POS; + if (chan->chip->apb_regs) + reg |= (chan->id << CH_CFG_H_SRC_PER_POS); break; default: break; diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h index 358f553cafe9..380005afde16 100644 --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h @@ -258,6 +258,8 @@ enum { /* CH_CFG_H */ #define CH_CFG_H_PRIORITY_POS 17 +#define CH_CFG_H_DST_PER_POS 12 +#define CH_CFG_H_SRC_PER_POS 7 #define CH_CFG_H_HS_SEL_DST_POS 4 #define CH_CFG_H_HS_SEL_SRC_POS 3 enum { From c454d16a7d5a9af88b844d98bec50d2363c19941 Mon Sep 17 00:00:00 2001 From: Pandith N Date: Mon, 2 Aug 2021 11:24:54 +0530 Subject: [PATCH 075/696] dmaengine: dw-axi-dmac: Burst length settings Burst length, DMA HW capability set in dt-binding is now used in driver. Signed-off-by: Pandith N Tested-by: Pan Kris Link: https://lore.kernel.org/r/20210802055454.15192-4-pandith.n@intel.com Signed-off-by: Vinod Koul --- drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c index 3edc647271b4..35993ab92154 100644 --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c @@ -1290,7 +1290,7 @@ static int parse_device_properties(struct axi_dma_chip *chip) return -EINVAL; chip->dw->hdata->restrict_axi_burst_len = true; - chip->dw->hdata->axi_rw_burst_len = tmp - 1; + chip->dw->hdata->axi_rw_burst_len = tmp; } return 0; @@ -1379,6 +1379,7 @@ static int dw_probe(struct platform_device *pdev) /* DMA capabilities */ dw->dma.chancnt = hdata->nr_channels; + dw->dma.max_burst = hdata->axi_rw_burst_len; dw->dma.src_addr_widths = AXI_DMA_BUSWIDTHS; dw->dma.dst_addr_widths = AXI_DMA_BUSWIDTHS; dw->dma.directions = BIT(DMA_MEM_TO_MEM); From b92e83f7c4f0e5dea11fd9aef1039d3121897391 Mon Sep 17 00:00:00 2001 From: Alexander Sverdlin Date: Mon, 26 Jul 2021 16:59:53 +0300 Subject: [PATCH 076/696] dmaengine: ep93xx: Prepare clock before using it Use clk_prepare_enable()/clk_disable_unprepare() in preparation for switch to Common Clock Framework, otherwise the following is visible: WARNING: CPU: 0 PID: 1 at drivers/clk/clk.c:1011 clk_core_enable+0x9c/0xbc Enabling unprepared m2p0 ... Hardware name: Cirrus Logic EDB9302 Evaluation Board ... clk_core_enable clk_core_enable_lock ep93xx_dma_alloc_chan_resources dma_chan_get find_candidate __dma_request_channel snd_dmaengine_pcm_request_channel dmaengine_pcm_new snd_soc_pcm_component_new soc_new_pcm snd_soc_bind_card edb93xx_probe ... ep93xx-i2s ep93xx-i2s: Missing dma channel for stream: 0 ep93xx-i2s ep93xx-i2s: ASoC: error at snd_soc_pcm_component_new on ep93xx-i2s: -22 edb93xx-audio edb93xx-audio: ASoC: can't create pcm CS4271 HiFi :-22 edb93xx-audio edb93xx-audio: snd_soc_register_card() failed: -22 edb93xx-audio: probe of edb93xx-audio failed with error -22 Signed-off-by: Alexander Sverdlin Signed-off-by: Nikita Shubin Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20210726140001.24820-6-nikita.shubin@maquefel.me Signed-off-by: Vinod Koul --- drivers/dma/ep93xx_dma.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/dma/ep93xx_dma.c b/drivers/dma/ep93xx_dma.c index 01027779beb8..98f9ee70362e 100644 --- a/drivers/dma/ep93xx_dma.c +++ b/drivers/dma/ep93xx_dma.c @@ -897,7 +897,7 @@ static int ep93xx_dma_alloc_chan_resources(struct dma_chan *chan) if (data && data->name) name = data->name; - ret = clk_enable(edmac->clk); + ret = clk_prepare_enable(edmac->clk); if (ret) return ret; @@ -936,7 +936,7 @@ static int ep93xx_dma_alloc_chan_resources(struct dma_chan *chan) fail_free_irq: free_irq(edmac->irq, edmac); fail_clk_disable: - clk_disable(edmac->clk); + clk_disable_unprepare(edmac->clk); return ret; } @@ -969,7 +969,7 @@ static void ep93xx_dma_free_chan_resources(struct dma_chan *chan) list_for_each_entry_safe(desc, d, &list, node) kfree(desc); - clk_disable(edmac->clk); + clk_disable_unprepare(edmac->clk); free_irq(edmac->irq, edmac); } From dd861267bfecc49df5232c33d3566a334ff5e9f6 Mon Sep 17 00:00:00 2001 From: Juergen Borleis Date: Thu, 29 Jul 2021 09:18:21 +0200 Subject: [PATCH 077/696] dma: imx-dma: configure the generic DMA type to make it work Commit dea7a9f dmaengine: imx-dma: remove dma_slave_config direction usage changes the method from a "configuration when called" to an "configuration when used". Due to this, only the cyclic DMA type gets configured correctly, while the generic DMA type is left non-configured. Without this additional call, the struct imxdma_channel::word_size member is stuck at DMA_SLAVE_BUSWIDTH_UNDEFINED and imxdma_prep_slave_sg() always returns NULL. Signed-off-by: Juergen Borleis Link: https://lore.kernel.org/r/20210729071821.9857-1-jbe@pengutronix.de Signed-off-by: Vinod Koul --- drivers/dma/imx-dma.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c index 7f116bbcfad2..2ddc31e64db0 100644 --- a/drivers/dma/imx-dma.c +++ b/drivers/dma/imx-dma.c @@ -812,6 +812,8 @@ static struct dma_async_tx_descriptor *imxdma_prep_slave_sg( dma_length += sg_dma_len(sg); } + imxdma_config_write(chan, &imxdmac->config, direction); + switch (imxdmac->word_size) { case DMA_SLAVE_BUSWIDTH_4_BYTES: if (sg_dma_len(sgl) & 3 || sgl->dma_address & 3) From e9c5b0b53ccca81dd0a35c62309e243a57c7959d Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Thu, 29 Jul 2021 14:04:01 +0200 Subject: [PATCH 078/696] dmaengine: idxd: Fix a possible NULL pointer dereference 'device_driver_attach()' dereferences its first argument (i.e. 'alt_drv') so it must not be NULL. Simplify the error handling logic about NULL 'alt_drv' in order to be more robust and future-proof. Fixes: 568b2126466f ("dmaengine: idxd: fix uninit var for alt_drv") Fixes: 6e7f3ee97bbe ("dmaengine: idxd: move dsa_drv support to compatible mode") Signed-off-by: Christophe JAILLET Acked-by: Dave Jiang Link: https://lore.kernel.org/r/77f0dc4f3966591d1f0cffb614a94085f8895a85.1627560174.git.christophe.jaillet@wanadoo.fr Signed-off-by: Vinod Koul --- drivers/dma/idxd/compat.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/dma/idxd/compat.c b/drivers/dma/idxd/compat.c index d7616c240dcd..3df21615f888 100644 --- a/drivers/dma/idxd/compat.c +++ b/drivers/dma/idxd/compat.c @@ -45,23 +45,16 @@ static ssize_t bind_store(struct device_driver *drv, const char *buf, size_t cou idxd_dev = confdev_to_idxd_dev(dev); if (is_idxd_dev(idxd_dev)) { alt_drv = driver_find("idxd", bus); - if (!alt_drv) - return -ENODEV; } else if (is_idxd_wq_dev(idxd_dev)) { struct idxd_wq *wq = confdev_to_wq(dev); - if (is_idxd_wq_kernel(wq)) { + if (is_idxd_wq_kernel(wq)) alt_drv = driver_find("dmaengine", bus); - if (!alt_drv) - return -ENODEV; - } else if (is_idxd_wq_user(wq)) { + else if (is_idxd_wq_user(wq)) alt_drv = driver_find("user", bus); - if (!alt_drv) - return -ENODEV; - } else { - return -ENODEV; - } } + if (!alt_drv) + return -ENODEV; rc = device_driver_attach(alt_drv, dev); if (rc < 0) From ced75a2f5da71de5775fda44250e27d7b8024355 Mon Sep 17 00:00:00 2001 From: Jessica Yu Date: Mon, 2 Aug 2021 15:26:39 +0200 Subject: [PATCH 079/696] MAINTAINERS: Add Luis Chamberlain as modules maintainer Luis has kindly agreed to help maintain the module loader. As my responsibilities have shifted, I've found myself with less cycles to devote to upstream maintenance these days. Luis is already very involved and engaged upstream, and with his experience maintaining the kmod module loader and usermode helper, I believe he is a great fit for this area of the kernel. Acked-by: Luis Chamberlain Signed-off-by: Jessica Yu --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index a61f4f3b78a9..d2bdcc8dc25f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12526,6 +12526,7 @@ Q: http://patchwork.linuxtv.org/project/linux-media/list/ F: drivers/media/dvb-frontends/mn88473* MODULE SUPPORT +M: Luis Chamberlain M: Jessica Yu S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/jeyu/linux.git modules-next From 1ca70b24afb999376bee3cf3b4a52732988fa0d7 Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Tue, 20 Jul 2021 11:15:42 -0700 Subject: [PATCH 080/696] MAINTAINERS: add Nick as Reviewer for compiler_attributes.h $ ./scripts/get_maintainer.pl --rolestats --git-blame -f \ include/linux/compiler_attributes.h ... Nick Desaulniers (supporter:CLANG/LLVM BUILD SUPPORT,authored lines:43/331=13%,commits:8/15=53%) It's also important for me to stay up on which compiler attributes clang is missing. Signed-off-by: Nick Desaulniers Signed-off-by: Miguel Ojeda --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 0cce91cd5624..30724a8cf304 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4575,6 +4575,7 @@ F: drivers/platform/x86/compal-laptop.c COMPILER ATTRIBUTES M: Miguel Ojeda +R: Nick Desaulniers S: Maintained F: include/linux/compiler_attributes.h From 9eec0792024983276871baeb201609abb07dd35d Mon Sep 17 00:00:00 2001 From: Weizhao Ouyang Date: Thu, 5 Aug 2021 17:58:23 +0800 Subject: [PATCH 081/696] coccinelle: api: rename kzfree to kfree_sensitive Commit 453431a54934 ("mm, treewide: rename kzfree() to kfree_sensitive()") renamed kzfree() to kfree_sensitive(), it should be applied to coccinelle. Signed-off-by: Weizhao Ouyang Signed-off-by: Julia Lawall Acked-by: Denis Efremov --- scripts/coccinelle/api/kvmalloc.cocci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/coccinelle/api/kvmalloc.cocci b/scripts/coccinelle/api/kvmalloc.cocci index c30dab718a49..5ddcb76b76b0 100644 --- a/scripts/coccinelle/api/kvmalloc.cocci +++ b/scripts/coccinelle/api/kvmalloc.cocci @@ -79,7 +79,7 @@ position p : script:python() { relevant(p) }; } else { ... when != krealloc(E, ...) when any -* \(kfree\|kzfree\)(E) +* \(kfree\|kfree_sensitive\)(E) ... } From dae68c6b9620ab694c8334de640c6d64daeb90e2 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 4 Aug 2021 12:41:29 +0200 Subject: [PATCH 082/696] rtc: s5m: switch to devm_rtc_allocate_device Switch to devm_rtc_allocate_device/devm_rtc_register_device, this allows for further improvement of the driver. Signed-off-by: Alexandre Belloni Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20210804104133.5158-1-alexandre.belloni@bootlin.com --- drivers/rtc/rtc-s5m.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c index 6b56f8eacba6..4c1596c55de8 100644 --- a/drivers/rtc/rtc-s5m.c +++ b/drivers/rtc/rtc-s5m.c @@ -788,12 +788,16 @@ static int s5m_rtc_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 1); - info->rtc_dev = devm_rtc_device_register(&pdev->dev, "s5m-rtc", - &s5m_rtc_ops, THIS_MODULE); - + info->rtc_dev = devm_rtc_allocate_device(&pdev->dev); if (IS_ERR(info->rtc_dev)) return PTR_ERR(info->rtc_dev); + info->rtc_dev->ops = &s5m_rtc_ops; + + err = devm_rtc_register_device(info->rtc_dev); + if (err) + return err; + if (!info->irq) { dev_info(&pdev->dev, "Alarm IRQ not available\n"); return 0; From 1ed4dba2bc166bae5af713a114ed91619ef70c43 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 4 Aug 2021 12:41:30 +0200 Subject: [PATCH 083/696] rtc: s5m: signal the core when alarm are not available Clear the RTC_FEATURE_ALARM bit to signal to the core when alarms are not available to ensure the alarm callbacks are never called and userspace is aware alarms are not supported. Signed-off-by: Alexandre Belloni Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20210804104133.5158-2-alexandre.belloni@bootlin.com --- drivers/rtc/rtc-s5m.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c index 4c1596c55de8..ee195697e6c6 100644 --- a/drivers/rtc/rtc-s5m.c +++ b/drivers/rtc/rtc-s5m.c @@ -794,25 +794,20 @@ static int s5m_rtc_probe(struct platform_device *pdev) info->rtc_dev->ops = &s5m_rtc_ops; - err = devm_rtc_register_device(info->rtc_dev); - if (err) - return err; - if (!info->irq) { - dev_info(&pdev->dev, "Alarm IRQ not available\n"); - return 0; + clear_bit(RTC_FEATURE_ALARM, info->rtc_dev->features); + } else { + ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL, + s5m_rtc_alarm_irq, 0, "rtc-alarm0", + info); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n", + info->irq, ret); + return ret; + } } - ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL, - s5m_rtc_alarm_irq, 0, "rtc-alarm0", - info); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n", - info->irq, ret); - return ret; - } - - return 0; + return devm_rtc_register_device(info->rtc_dev); } #ifdef CONFIG_PM_SLEEP From 308247d20464a684f335001f2f835240e67f9126 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 4 Aug 2021 12:41:31 +0200 Subject: [PATCH 084/696] rtc: s5m: enable wakeup only when available Call device_init_wakeup() only when alarms are available and the RTC is actually able to wake up the system. Signed-off-by: Alexandre Belloni Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20210804104133.5158-3-alexandre.belloni@bootlin.com --- drivers/rtc/rtc-s5m.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c index ee195697e6c6..87df797758fc 100644 --- a/drivers/rtc/rtc-s5m.c +++ b/drivers/rtc/rtc-s5m.c @@ -786,8 +786,6 @@ static int s5m_rtc_probe(struct platform_device *pdev) if (ret) return ret; - device_init_wakeup(&pdev->dev, 1); - info->rtc_dev = devm_rtc_allocate_device(&pdev->dev); if (IS_ERR(info->rtc_dev)) return PTR_ERR(info->rtc_dev); @@ -805,6 +803,7 @@ static int s5m_rtc_probe(struct platform_device *pdev) info->irq, ret); return ret; } + device_init_wakeup(&pdev->dev, 1); } return devm_rtc_register_device(info->rtc_dev); From fffd603ae9f6ee1da47fa4ae4c70c324323bc201 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 4 Aug 2021 12:41:32 +0200 Subject: [PATCH 085/696] rtc: s5m: set range The S5M8763X type seems to handles dates from year 0000 to 9999, there is no info on leap year handling after 2099. The other models handles dates from 2000 to 2099. Signed-off-by: Alexandre Belloni Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20210804104133.5158-4-alexandre.belloni@bootlin.com --- drivers/rtc/rtc-s5m.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c index 87df797758fc..fb9c6b709e13 100644 --- a/drivers/rtc/rtc-s5m.c +++ b/drivers/rtc/rtc-s5m.c @@ -204,15 +204,9 @@ static int s5m8767_tm_to_data(struct rtc_time *tm, u8 *data) data[RTC_WEEKDAY] = 1 << tm->tm_wday; data[RTC_DATE] = tm->tm_mday; data[RTC_MONTH] = tm->tm_mon + 1; - data[RTC_YEAR1] = tm->tm_year > 100 ? (tm->tm_year - 100) : 0; + data[RTC_YEAR1] = tm->tm_year - 100; - if (tm->tm_year < 100) { - pr_err("RTC cannot handle the year %d\n", - 1900 + tm->tm_year); - return -EINVAL; - } else { - return 0; - } + return 0; } /* @@ -792,6 +786,14 @@ static int s5m_rtc_probe(struct platform_device *pdev) info->rtc_dev->ops = &s5m_rtc_ops; + if (info->device_type == S5M8763X) { + info->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_0000; + info->rtc_dev->range_max = RTC_TIMESTAMP_END_9999; + } else { + info->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_2000; + info->rtc_dev->range_max = RTC_TIMESTAMP_END_2099; + } + if (!info->irq) { clear_bit(RTC_FEATURE_ALARM, info->rtc_dev->features); } else { From 53cbf462f6b5c9de364efdf443ffb74ed082463a Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Mon, 2 Aug 2021 10:58:20 -0700 Subject: [PATCH 086/696] dmaengine: idxd: Remove unused status variable in irq_process_work_list() status is no longer used within this block: drivers/dma/idxd/irq.c:255:6: warning: unused variable 'status' [-Wunused-variable] u8 status = desc->completion->status & DSA_COMP_STATUS_MASK; ^ 1 warning generated. Fixes: b60bb6e2bfc1 ("dmaengine: idxd: fix abort status check") Signed-off-by: Nathan Chancellor Acked-by: Dave Jiang Link: https://lore.kernel.org/r/20210802175820.3153920-1-nathan@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/idxd/irq.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/dma/idxd/irq.c b/drivers/dma/idxd/irq.c index 65dc7bbb0a13..91e46ca3a0ad 100644 --- a/drivers/dma/idxd/irq.c +++ b/drivers/dma/idxd/irq.c @@ -252,8 +252,6 @@ static int irq_process_work_list(struct idxd_irq_entry *irq_entry, spin_unlock_irqrestore(&irq_entry->list_lock, flags); list_for_each_entry(desc, &flist, list) { - u8 status = desc->completion->status & DSA_COMP_STATUS_MASK; - /* * Check against the original status as ABORT is software defined * and 0xff, which DSA_COMP_STATUS_MASK can mask out. From dfa6a2f4c2eab087959faff5a87119c8ff766c74 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 2 Aug 2021 21:43:53 +0300 Subject: [PATCH 087/696] dmaengine: dw: Remove error message from DT parsing code Users are a bit frightened of the harmless message that tells that DT is missed on ACPI-based platforms. Remove it for good, it will simplify the future conversion to fwnode and device property APIs. Fixes: a9ddb575d6d6 ("dmaengine: dw_dmac: Enhance device tree support") Depends-on: f5e84eae7956 ("dmaengine: dw: platform: Split OF helpers to separate module") BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=199379 Signed-off-by: Andy Shevchenko Reviewed-by: Serge Semin Tested-by: Serge Semin Link: https://lore.kernel.org/r/20210802184355.49879-1-andriy.shevchenko@linux.intel.com Signed-off-by: Vinod Koul --- drivers/dma/dw/of.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/dma/dw/of.c b/drivers/dma/dw/of.c index c1cf7675b9d1..4d2b89142721 100644 --- a/drivers/dma/dw/of.c +++ b/drivers/dma/dw/of.c @@ -54,11 +54,6 @@ struct dw_dma_platform_data *dw_dma_parse_dt(struct platform_device *pdev) u32 nr_masters; u32 nr_channels; - if (!np) { - dev_err(&pdev->dev, "Missing DT data\n"); - return NULL; - } - if (of_property_read_u32(np, "dma-masters", &nr_masters)) return NULL; if (nr_masters < 1 || nr_masters > DW_DMA_MAX_NR_MASTERS) From 08bf54fcf5ca87328541e035090c6a85c8e064f4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 2 Aug 2021 21:43:54 +0300 Subject: [PATCH 088/696] dmaengine: dw: Convert members to u32 in platform data u32 is a type that is used for properties retrieval from DT. With the type change it allows to clean up properties reading routine. While at it, order the fields in way how they are parsed. Signed-off-by: Andy Shevchenko Reviewed-by: Serge Semin Tested-by: Serge Semin Link: https://lore.kernel.org/r/20210802184355.49879-2-andriy.shevchenko@linux.intel.com Signed-off-by: Vinod Koul --- include/linux/platform_data/dma-dw.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/include/linux/platform_data/dma-dw.h b/include/linux/platform_data/dma-dw.h index b11b0c8bc5da..860ba4bc5ead 100644 --- a/include/linux/platform_data/dma-dw.h +++ b/include/linux/platform_data/dma-dw.h @@ -41,11 +41,11 @@ struct dw_dma_slave { /** * struct dw_dma_platform_data - Controller configuration parameters + * @nr_masters: Number of AHB masters supported by the controller * @nr_channels: Number of channels supported by hardware (max 8) * @chan_allocation_order: Allocate channels starting from 0 or 7 * @chan_priority: Set channel priority increasing from 0 to 7 or 7 to 0. * @block_size: Maximum block size supported by the controller - * @nr_masters: Number of AHB masters supported by the controller * @data_width: Maximum data width supported by hardware per AHB master * (in bytes, power of 2) * @multi_block: Multi block transfers supported by hardware per channel. @@ -55,25 +55,25 @@ struct dw_dma_slave { * @quirks: Optional platform quirks. */ struct dw_dma_platform_data { - unsigned int nr_channels; + u32 nr_masters; + u32 nr_channels; #define CHAN_ALLOCATION_ASCENDING 0 /* zero to seven */ #define CHAN_ALLOCATION_DESCENDING 1 /* seven to zero */ - unsigned char chan_allocation_order; + u32 chan_allocation_order; #define CHAN_PRIORITY_ASCENDING 0 /* chan0 highest */ #define CHAN_PRIORITY_DESCENDING 1 /* chan7 highest */ - unsigned char chan_priority; - unsigned int block_size; - unsigned char nr_masters; - unsigned char data_width[DW_DMA_MAX_NR_MASTERS]; - unsigned char multi_block[DW_DMA_MAX_NR_CHANNELS]; + u32 chan_priority; + u32 block_size; + u32 data_width[DW_DMA_MAX_NR_MASTERS]; + u32 multi_block[DW_DMA_MAX_NR_CHANNELS]; u32 max_burst[DW_DMA_MAX_NR_CHANNELS]; #define CHAN_PROTCTL_PRIVILEGED BIT(0) #define CHAN_PROTCTL_BUFFERABLE BIT(1) #define CHAN_PROTCTL_CACHEABLE BIT(2) #define CHAN_PROTCTL_MASK GENMASK(2, 0) - unsigned char protctl; + u32 protctl; #define DW_DMA_QUIRK_XBAR_PRESENT BIT(0) - unsigned int quirks; + u32 quirks; }; #endif /* _PLATFORM_DATA_DMA_DW_H */ From d6ff82cc1bff97923dfa0640d27271bc220a5004 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 2 Aug 2021 21:43:55 +0300 Subject: [PATCH 089/696] dmaengine: dw: Simplify DT property parser Since we converted internal data types to match DT, there is no need to have an intermediate conversion layer, hence drop a few conditionals and for loops for good. Signed-off-by: Andy Shevchenko Reviewed-by: Serge Semin Tested-by: Serge Semin Link: https://lore.kernel.org/r/20210802184355.49879-3-andriy.shevchenko@linux.intel.com Signed-off-by: Vinod Koul --- drivers/dma/dw/of.c | 44 ++++++++++++++++---------------------------- 1 file changed, 16 insertions(+), 28 deletions(-) diff --git a/drivers/dma/dw/of.c b/drivers/dma/dw/of.c index 4d2b89142721..523ca806837c 100644 --- a/drivers/dma/dw/of.c +++ b/drivers/dma/dw/of.c @@ -50,7 +50,7 @@ struct dw_dma_platform_data *dw_dma_parse_dt(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct dw_dma_platform_data *pdata; - u32 tmp, arr[DW_DMA_MAX_NR_MASTERS], mb[DW_DMA_MAX_NR_CHANNELS]; + u32 tmp, arr[DW_DMA_MAX_NR_MASTERS]; u32 nr_masters; u32 nr_channels; @@ -71,41 +71,29 @@ struct dw_dma_platform_data *dw_dma_parse_dt(struct platform_device *pdev) pdata->nr_masters = nr_masters; pdata->nr_channels = nr_channels; - if (!of_property_read_u32(np, "chan_allocation_order", &tmp)) - pdata->chan_allocation_order = (unsigned char)tmp; + of_property_read_u32(np, "chan_allocation_order", &pdata->chan_allocation_order); + of_property_read_u32(np, "chan_priority", &pdata->chan_priority); - if (!of_property_read_u32(np, "chan_priority", &tmp)) - pdata->chan_priority = tmp; + of_property_read_u32(np, "block_size", &pdata->block_size); - if (!of_property_read_u32(np, "block_size", &tmp)) - pdata->block_size = tmp; - - if (!of_property_read_u32_array(np, "data-width", arr, nr_masters)) { - for (tmp = 0; tmp < nr_masters; tmp++) - pdata->data_width[tmp] = arr[tmp]; - } else if (!of_property_read_u32_array(np, "data_width", arr, nr_masters)) { + /* Try deprecated property first */ + if (!of_property_read_u32_array(np, "data_width", arr, nr_masters)) { for (tmp = 0; tmp < nr_masters; tmp++) pdata->data_width[tmp] = BIT(arr[tmp] & 0x07); } - if (!of_property_read_u32_array(np, "multi-block", mb, nr_channels)) { - for (tmp = 0; tmp < nr_channels; tmp++) - pdata->multi_block[tmp] = mb[tmp]; - } else { - for (tmp = 0; tmp < nr_channels; tmp++) - pdata->multi_block[tmp] = 1; - } + /* If "data_width" and "data-width" both provided use the latter one */ + of_property_read_u32_array(np, "data-width", pdata->data_width, nr_masters); - if (of_property_read_u32_array(np, "snps,max-burst-len", pdata->max_burst, - nr_channels)) { - memset32(pdata->max_burst, DW_DMA_MAX_BURST, nr_channels); - } + memset32(pdata->multi_block, 1, nr_channels); + of_property_read_u32_array(np, "multi-block", pdata->multi_block, nr_channels); - if (!of_property_read_u32(np, "snps,dma-protection-control", &tmp)) { - if (tmp > CHAN_PROTCTL_MASK) - return NULL; - pdata->protctl = tmp; - } + memset32(pdata->max_burst, DW_DMA_MAX_BURST, nr_channels); + of_property_read_u32_array(np, "snps,max-burst-len", pdata->max_burst, nr_channels); + + of_property_read_u32(np, "snps,dma-protection-control", &pdata->protctl); + if (pdata->protctl > CHAN_PROTCTL_MASK) + return NULL; return pdata; } From 4153a7f6440f46261a3004009eaa914914f08055 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 4 Aug 2021 21:51:40 +0200 Subject: [PATCH 090/696] dmaengine: xilinx: Add empty device_config function Various DMA users call the dmaengine_slave_config() and expect it to succeed, but that can only succeed if .device_config is implemented. Add empty device_config function rather than patching all the places which use dmaengine_slave_config(). Signed-off-by: Marek Vasut Cc: Akinobu Mita Cc: Kedareswara rao Appana Cc: Michal Simek Cc: Vinod Koul Link: https://lore.kernel.org/r/20210804195140.61396-1-marex@denx.de Signed-off-by: Vinod Koul --- drivers/dma/xilinx/xilinx_dma.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c index 213e1a7314b7..97cbde4e0a29 100644 --- a/drivers/dma/xilinx/xilinx_dma.c +++ b/drivers/dma/xilinx/xilinx_dma.c @@ -1657,6 +1657,17 @@ static void xilinx_dma_issue_pending(struct dma_chan *dchan) spin_unlock_irqrestore(&chan->lock, flags); } +/** + * xilinx_dma_device_config - Configure the DMA channel + * @dchan: DMA channel + * @config: channel configuration + */ +static int xilinx_dma_device_config(struct dma_chan *dchan, + struct dma_slave_config *config) +{ + return 0; +} + /** * xilinx_dma_complete_descriptor - Mark the active descriptor as complete * @chan : xilinx DMA channel @@ -3095,6 +3106,7 @@ static int xilinx_dma_probe(struct platform_device *pdev) xdev->common.device_synchronize = xilinx_dma_synchronize; xdev->common.device_tx_status = xilinx_dma_tx_status; xdev->common.device_issue_pending = xilinx_dma_issue_pending; + xdev->common.device_config = xilinx_dma_device_config; if (xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) { dma_cap_set(DMA_CYCLIC, xdev->common.cap_mask); xdev->common.device_prep_slave_sg = xilinx_dma_prep_slave_sg; From 81c2f79c2104c5b48f01da674bc2f7d4bc600db4 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Tue, 3 Aug 2021 15:32:06 -0700 Subject: [PATCH 091/696] dmaengine: idxd: add capability check for 'block on fault' attribute The device general capability has a bit that indicate whether 'block on fault' is supported. Add check to wq sysfs knob to check if cap exists before allowing user to toggle. Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/162802992615.3084999.12539468940404102898.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/sysfs.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c index 4c01587c9d4a..a88886d0f27b 100644 --- a/drivers/dma/idxd/sysfs.c +++ b/drivers/dma/idxd/sysfs.c @@ -642,6 +642,9 @@ static ssize_t wq_block_on_fault_store(struct device *dev, bool bof; int rc; + if (!idxd->hw.gen_cap.block_on_fault) + return -EOPNOTSUPP; + if (!test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags)) return -EPERM; From bd2f4ae5e019efcfadd6b491204fd60adf14f4a3 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Tue, 3 Aug 2021 15:37:15 -0700 Subject: [PATCH 092/696] dmaengine: idxd: clear block on fault flag when clear wq The block on fault flag is not cleared when we disable or reset wq. This causes it to remain set if the user does not clear it on the next configuration load. Add clear of flag in dxd_wq_disable_cleanup() routine. Fixes: da32b28c95a7 ("dmaengine: idxd: cleanup workqueue config after disabling") Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/162803023553.3086015.8158952172068868803.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/device.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c index 86fa4b4590f9..21f0d732b76e 100644 --- a/drivers/dma/idxd/device.c +++ b/drivers/dma/idxd/device.c @@ -402,6 +402,7 @@ static void idxd_wq_disable_cleanup(struct idxd_wq *wq) wq->priority = 0; wq->ats_dis = 0; clear_bit(WQ_FLAG_DEDICATED, &wq->flags); + clear_bit(WQ_FLAG_BLOCK_ON_FAULT, &wq->flags); memset(wq->name, 0, WQ_NAME_SIZE); } From d803c8b9f3f2b8e5c047f2d0a27a9ea3ef91510f Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Tue, 3 Aug 2021 15:29:30 -0700 Subject: [PATCH 093/696] dmaengine: idxd: make I/O interrupt handler one shot The interrupt thread handler currently loops forever to process outstanding completions. This causes either an "irq X: nobody cared" kernel splat or the NMI watchdog kicks in due to running too long in the function. The irq thread handler is expected to run again after exiting if there are interrupts fired while the thread handler is running. So the handler code can process all the completed I/O in a single pass and exit without losing the follow on completed I/O. Reviewed-by: Dan Williams Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/162802977005.3084234.11836261157026497585.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/irq.c | 59 ++++++------------------------------------ 1 file changed, 8 insertions(+), 51 deletions(-) diff --git a/drivers/dma/idxd/irq.c b/drivers/dma/idxd/irq.c index 91e46ca3a0ad..11addb394793 100644 --- a/drivers/dma/idxd/irq.c +++ b/drivers/dma/idxd/irq.c @@ -22,11 +22,6 @@ struct idxd_fault { struct idxd_device *idxd; }; -static int irq_process_work_list(struct idxd_irq_entry *irq_entry, - int *processed, u64 data); -static int irq_process_pending_llist(struct idxd_irq_entry *irq_entry, - int *processed, u64 data); - static void idxd_device_reinit(struct work_struct *work) { struct idxd_device *idxd = container_of(work, struct idxd_device, work); @@ -177,18 +172,15 @@ irqreturn_t idxd_misc_thread(int vec, void *data) return IRQ_HANDLED; } -static int irq_process_pending_llist(struct idxd_irq_entry *irq_entry, - int *processed, u64 data) +static void irq_process_pending_llist(struct idxd_irq_entry *irq_entry) { struct idxd_desc *desc, *t; struct llist_node *head; - int queued = 0; unsigned long flags; - *processed = 0; head = llist_del_all(&irq_entry->pending_llist); if (!head) - goto out; + return; llist_for_each_entry_safe(desc, t, head, llnode) { u8 status = desc->completion->status & DSA_COMP_STATUS_MASK; @@ -200,35 +192,25 @@ static int irq_process_pending_llist(struct idxd_irq_entry *irq_entry, */ if (unlikely(desc->completion->status == IDXD_COMP_DESC_ABORT)) { complete_desc(desc, IDXD_COMPLETE_ABORT); - (*processed)++; continue; } complete_desc(desc, IDXD_COMPLETE_NORMAL); - (*processed)++; } else { spin_lock_irqsave(&irq_entry->list_lock, flags); list_add_tail(&desc->list, &irq_entry->work_list); spin_unlock_irqrestore(&irq_entry->list_lock, flags); - queued++; } } - - out: - return queued; } -static int irq_process_work_list(struct idxd_irq_entry *irq_entry, - int *processed, u64 data) +static void irq_process_work_list(struct idxd_irq_entry *irq_entry) { - int queued = 0; unsigned long flags; LIST_HEAD(flist); struct idxd_desc *desc, *n; - *processed = 0; - /* * This lock protects list corruption from access of list outside of the irq handler * thread. @@ -236,16 +218,13 @@ static int irq_process_work_list(struct idxd_irq_entry *irq_entry, spin_lock_irqsave(&irq_entry->list_lock, flags); if (list_empty(&irq_entry->work_list)) { spin_unlock_irqrestore(&irq_entry->list_lock, flags); - return 0; + return; } list_for_each_entry_safe(desc, n, &irq_entry->work_list, list) { if (desc->completion->status) { list_del(&desc->list); - (*processed)++; list_add_tail(&desc->list, &flist); - } else { - queued++; } } @@ -263,13 +242,11 @@ static int irq_process_work_list(struct idxd_irq_entry *irq_entry, complete_desc(desc, IDXD_COMPLETE_NORMAL); } - - return queued; } -static int idxd_desc_process(struct idxd_irq_entry *irq_entry) +irqreturn_t idxd_wq_thread(int irq, void *data) { - int rc, processed, total = 0; + struct idxd_irq_entry *irq_entry = data; /* * There are two lists we are processing. The pending_llist is where @@ -288,29 +265,9 @@ static int idxd_desc_process(struct idxd_irq_entry *irq_entry) * and process the completed entries. * 4. If the entry is still waiting on hardware, list_add_tail() to * the work_list. - * 5. Repeat until no more descriptors. */ - do { - rc = irq_process_work_list(irq_entry, &processed, 0); - total += processed; - if (rc != 0) - continue; - - rc = irq_process_pending_llist(irq_entry, &processed, 0); - total += processed; - } while (rc != 0); - - return total; -} - -irqreturn_t idxd_wq_thread(int irq, void *data) -{ - struct idxd_irq_entry *irq_entry = data; - int processed; - - processed = idxd_desc_process(irq_entry); - if (processed == 0) - return IRQ_NONE; + irq_process_work_list(irq_entry); + irq_process_pending_llist(irq_entry); return IRQ_HANDLED; } From 5161a55c069f53d88da49274cbef6e3c74eadea9 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 2 Aug 2021 10:29:38 -0700 Subject: [PATCH 094/696] cxl: Move cxl_core to new directory CXL core is growing, and it's already arguably unmanageable. To support future growth, move core functionality to a new directory and rename the file to represent just bus support. Future work will remove non-bus functionality. Note that mem.h is renamed to cxlmem.h to avoid a namespace collision with the global ARCH=um mem.h header. Reported-by: kernel test robot Signed-off-by: Ben Widawsky Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/162792537866.368511.8915631504621088321.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams --- Documentation/driver-api/cxl/memory-devices.rst | 2 +- drivers/cxl/Makefile | 4 +--- drivers/cxl/core/Makefile | 5 +++++ drivers/cxl/{core.c => core/bus.c} | 4 ++-- drivers/cxl/{mem.h => cxlmem.h} | 0 drivers/cxl/pci.c | 2 +- drivers/cxl/pmem.c | 2 +- 7 files changed, 11 insertions(+), 8 deletions(-) create mode 100644 drivers/cxl/core/Makefile rename drivers/cxl/{core.c => core/bus.c} (99%) rename drivers/cxl/{mem.h => cxlmem.h} (100%) diff --git a/Documentation/driver-api/cxl/memory-devices.rst b/Documentation/driver-api/cxl/memory-devices.rst index 487ce4f41d77..a86e2c7c551a 100644 --- a/Documentation/driver-api/cxl/memory-devices.rst +++ b/Documentation/driver-api/cxl/memory-devices.rst @@ -36,7 +36,7 @@ CXL Core .. kernel-doc:: drivers/cxl/cxl.h :internal: -.. kernel-doc:: drivers/cxl/core.c +.. kernel-doc:: drivers/cxl/core/bus.c :doc: cxl core External Interfaces diff --git a/drivers/cxl/Makefile b/drivers/cxl/Makefile index 32954059b37b..d1aaabc940f3 100644 --- a/drivers/cxl/Makefile +++ b/drivers/cxl/Makefile @@ -1,11 +1,9 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_CXL_BUS) += cxl_core.o +obj-$(CONFIG_CXL_BUS) += core/ obj-$(CONFIG_CXL_MEM) += cxl_pci.o obj-$(CONFIG_CXL_ACPI) += cxl_acpi.o obj-$(CONFIG_CXL_PMEM) += cxl_pmem.o -ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=CXL -cxl_core-y := core.o cxl_pci-y := pci.o cxl_acpi-y := acpi.o cxl_pmem-y := pmem.o diff --git a/drivers/cxl/core/Makefile b/drivers/cxl/core/Makefile new file mode 100644 index 000000000000..ad137f96e5c8 --- /dev/null +++ b/drivers/cxl/core/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_CXL_BUS) += cxl_core.o + +ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=CXL -I$(srctree)/drivers/cxl +cxl_core-y := bus.o diff --git a/drivers/cxl/core.c b/drivers/cxl/core/bus.c similarity index 99% rename from drivers/cxl/core.c rename to drivers/cxl/core/bus.c index a2e4d54fc7bc..0815eec23944 100644 --- a/drivers/cxl/core.c +++ b/drivers/cxl/core/bus.c @@ -6,8 +6,8 @@ #include #include #include -#include "cxl.h" -#include "mem.h" +#include +#include /** * DOC: cxl core diff --git a/drivers/cxl/mem.h b/drivers/cxl/cxlmem.h similarity index 100% rename from drivers/cxl/mem.h rename to drivers/cxl/cxlmem.h diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c index 4cf351a3cf99..a945c5fda292 100644 --- a/drivers/cxl/pci.c +++ b/drivers/cxl/pci.c @@ -12,9 +12,9 @@ #include #include #include +#include "cxlmem.h" #include "pci.h" #include "cxl.h" -#include "mem.h" /** * DOC: cxl pci diff --git a/drivers/cxl/pmem.c b/drivers/cxl/pmem.c index 0088e41dd2f3..9652c3ee41e7 100644 --- a/drivers/cxl/pmem.c +++ b/drivers/cxl/pmem.c @@ -6,7 +6,7 @@ #include #include #include -#include "mem.h" +#include "cxlmem.h" #include "cxl.h" /* From 95aaed266801a801add6d17cd3a4f7deb610af2e Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 2 Aug 2021 10:29:43 -0700 Subject: [PATCH 095/696] cxl/core: Improve CXL core kernel docs Now that CXL core's role is well understood, the documentation should reflect that information. Signed-off-by: Ben Widawsky Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/162792538379.368511.9055351193841619781.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams --- drivers/cxl/core/bus.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/cxl/core/bus.c b/drivers/cxl/core/bus.c index 0815eec23944..6ea69d70086b 100644 --- a/drivers/cxl/core/bus.c +++ b/drivers/cxl/core/bus.c @@ -12,8 +12,15 @@ /** * DOC: cxl core * - * The CXL core provides a sysfs hierarchy for control devices and a rendezvous - * point for cross-device interleave coordination through cxl ports. + * The CXL core provides a set of interfaces that can be consumed by CXL aware + * drivers. The interfaces allow for creation, modification, and destruction of + * regions, memory devices, ports, and decoders. CXL aware drivers must register + * with the CXL core via these interfaces in order to be able to participate in + * cross-device interleave coordination. The CXL core also establishes and + * maintains the bridge to the nvdimm subsystem. + * + * CXL core introduces sysfs hierarchy to control the devices that are + * instantiated by the core. */ static DEFINE_IDA(cxl_port_ida); From 06737cd0d216be1cf6e8052e4fca0d391298f184 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 2 Aug 2021 10:29:49 -0700 Subject: [PATCH 096/696] cxl/core: Move pmem functionality Refactor the pmem / nvdimm-bridge functionality from core/bus.c to core/pmem.c. Introduce drivers/core/core.h to communicate data structures and helpers between the core bus and other functionality that registers devices on the bus. Signed-off-by: Ben Widawsky Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/162792538899.368511.3881663908293411300.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams --- .../driver-api/cxl/memory-devices.rst | 3 + drivers/cxl/core/Makefile | 1 + drivers/cxl/core/bus.c | 205 +----------------- drivers/cxl/core/core.h | 17 ++ drivers/cxl/core/pmem.c | 204 +++++++++++++++++ 5 files changed, 228 insertions(+), 202 deletions(-) create mode 100644 drivers/cxl/core/core.h create mode 100644 drivers/cxl/core/pmem.c diff --git a/Documentation/driver-api/cxl/memory-devices.rst b/Documentation/driver-api/cxl/memory-devices.rst index a86e2c7c551a..e65c0ba82229 100644 --- a/Documentation/driver-api/cxl/memory-devices.rst +++ b/Documentation/driver-api/cxl/memory-devices.rst @@ -39,6 +39,9 @@ CXL Core .. kernel-doc:: drivers/cxl/core/bus.c :doc: cxl core +.. kernel-doc:: drivers/cxl/core/pmem.c + :internal: + External Interfaces =================== diff --git a/drivers/cxl/core/Makefile b/drivers/cxl/core/Makefile index ad137f96e5c8..e037521fe02b 100644 --- a/drivers/cxl/core/Makefile +++ b/drivers/cxl/core/Makefile @@ -3,3 +3,4 @@ obj-$(CONFIG_CXL_BUS) += cxl_core.o ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=CXL -I$(srctree)/drivers/cxl cxl_core-y := bus.o +cxl_core-y += pmem.o diff --git a/drivers/cxl/core/bus.c b/drivers/cxl/core/bus.c index 6ea69d70086b..408654ad70db 100644 --- a/drivers/cxl/core/bus.c +++ b/drivers/cxl/core/bus.c @@ -8,6 +8,7 @@ #include #include #include +#include "core.h" /** * DOC: cxl core @@ -37,7 +38,7 @@ static struct attribute *cxl_base_attributes[] = { NULL, }; -static struct attribute_group cxl_base_attribute_group = { +struct attribute_group cxl_base_attribute_group = { .attrs = cxl_base_attributes, }; @@ -514,11 +515,6 @@ err: return ERR_PTR(rc); } -static void unregister_dev(void *dev) -{ - device_unregister(dev); -} - struct cxl_decoder * devm_cxl_add_decoder(struct device *host, struct cxl_port *port, int nr_targets, resource_size_t base, resource_size_t len, @@ -543,7 +539,7 @@ devm_cxl_add_decoder(struct device *host, struct cxl_port *port, int nr_targets, if (rc) goto err; - rc = devm_add_action_or_reset(host, unregister_dev, dev); + rc = devm_add_action_or_reset(host, unregister_cxl_dev, dev); if (rc) return ERR_PTR(rc); return cxld; @@ -626,201 +622,6 @@ void cxl_probe_component_regs(struct device *dev, void __iomem *base, } EXPORT_SYMBOL_GPL(cxl_probe_component_regs); -static void cxl_nvdimm_bridge_release(struct device *dev) -{ - struct cxl_nvdimm_bridge *cxl_nvb = to_cxl_nvdimm_bridge(dev); - - kfree(cxl_nvb); -} - -static const struct attribute_group *cxl_nvdimm_bridge_attribute_groups[] = { - &cxl_base_attribute_group, - NULL, -}; - -static const struct device_type cxl_nvdimm_bridge_type = { - .name = "cxl_nvdimm_bridge", - .release = cxl_nvdimm_bridge_release, - .groups = cxl_nvdimm_bridge_attribute_groups, -}; - -struct cxl_nvdimm_bridge *to_cxl_nvdimm_bridge(struct device *dev) -{ - if (dev_WARN_ONCE(dev, dev->type != &cxl_nvdimm_bridge_type, - "not a cxl_nvdimm_bridge device\n")) - return NULL; - return container_of(dev, struct cxl_nvdimm_bridge, dev); -} -EXPORT_SYMBOL_GPL(to_cxl_nvdimm_bridge); - -static struct cxl_nvdimm_bridge * -cxl_nvdimm_bridge_alloc(struct cxl_port *port) -{ - struct cxl_nvdimm_bridge *cxl_nvb; - struct device *dev; - - cxl_nvb = kzalloc(sizeof(*cxl_nvb), GFP_KERNEL); - if (!cxl_nvb) - return ERR_PTR(-ENOMEM); - - dev = &cxl_nvb->dev; - cxl_nvb->port = port; - cxl_nvb->state = CXL_NVB_NEW; - device_initialize(dev); - device_set_pm_not_required(dev); - dev->parent = &port->dev; - dev->bus = &cxl_bus_type; - dev->type = &cxl_nvdimm_bridge_type; - - return cxl_nvb; -} - -static void unregister_nvb(void *_cxl_nvb) -{ - struct cxl_nvdimm_bridge *cxl_nvb = _cxl_nvb; - bool flush; - - /* - * If the bridge was ever activated then there might be in-flight state - * work to flush. Once the state has been changed to 'dead' then no new - * work can be queued by user-triggered bind. - */ - device_lock(&cxl_nvb->dev); - flush = cxl_nvb->state != CXL_NVB_NEW; - cxl_nvb->state = CXL_NVB_DEAD; - device_unlock(&cxl_nvb->dev); - - /* - * Even though the device core will trigger device_release_driver() - * before the unregister, it does not know about the fact that - * cxl_nvdimm_bridge_driver defers ->remove() work. So, do the driver - * release not and flush it before tearing down the nvdimm device - * hierarchy. - */ - device_release_driver(&cxl_nvb->dev); - if (flush) - flush_work(&cxl_nvb->state_work); - device_unregister(&cxl_nvb->dev); -} - -struct cxl_nvdimm_bridge *devm_cxl_add_nvdimm_bridge(struct device *host, - struct cxl_port *port) -{ - struct cxl_nvdimm_bridge *cxl_nvb; - struct device *dev; - int rc; - - if (!IS_ENABLED(CONFIG_CXL_PMEM)) - return ERR_PTR(-ENXIO); - - cxl_nvb = cxl_nvdimm_bridge_alloc(port); - if (IS_ERR(cxl_nvb)) - return cxl_nvb; - - dev = &cxl_nvb->dev; - rc = dev_set_name(dev, "nvdimm-bridge"); - if (rc) - goto err; - - rc = device_add(dev); - if (rc) - goto err; - - rc = devm_add_action_or_reset(host, unregister_nvb, cxl_nvb); - if (rc) - return ERR_PTR(rc); - - return cxl_nvb; - -err: - put_device(dev); - return ERR_PTR(rc); -} -EXPORT_SYMBOL_GPL(devm_cxl_add_nvdimm_bridge); - -static void cxl_nvdimm_release(struct device *dev) -{ - struct cxl_nvdimm *cxl_nvd = to_cxl_nvdimm(dev); - - kfree(cxl_nvd); -} - -static const struct attribute_group *cxl_nvdimm_attribute_groups[] = { - &cxl_base_attribute_group, - NULL, -}; - -static const struct device_type cxl_nvdimm_type = { - .name = "cxl_nvdimm", - .release = cxl_nvdimm_release, - .groups = cxl_nvdimm_attribute_groups, -}; - -bool is_cxl_nvdimm(struct device *dev) -{ - return dev->type == &cxl_nvdimm_type; -} -EXPORT_SYMBOL_GPL(is_cxl_nvdimm); - -struct cxl_nvdimm *to_cxl_nvdimm(struct device *dev) -{ - if (dev_WARN_ONCE(dev, !is_cxl_nvdimm(dev), - "not a cxl_nvdimm device\n")) - return NULL; - return container_of(dev, struct cxl_nvdimm, dev); -} -EXPORT_SYMBOL_GPL(to_cxl_nvdimm); - -static struct cxl_nvdimm *cxl_nvdimm_alloc(struct cxl_memdev *cxlmd) -{ - struct cxl_nvdimm *cxl_nvd; - struct device *dev; - - cxl_nvd = kzalloc(sizeof(*cxl_nvd), GFP_KERNEL); - if (!cxl_nvd) - return ERR_PTR(-ENOMEM); - - dev = &cxl_nvd->dev; - cxl_nvd->cxlmd = cxlmd; - device_initialize(dev); - device_set_pm_not_required(dev); - dev->parent = &cxlmd->dev; - dev->bus = &cxl_bus_type; - dev->type = &cxl_nvdimm_type; - - return cxl_nvd; -} - -int devm_cxl_add_nvdimm(struct device *host, struct cxl_memdev *cxlmd) -{ - struct cxl_nvdimm *cxl_nvd; - struct device *dev; - int rc; - - cxl_nvd = cxl_nvdimm_alloc(cxlmd); - if (IS_ERR(cxl_nvd)) - return PTR_ERR(cxl_nvd); - - dev = &cxl_nvd->dev; - rc = dev_set_name(dev, "pmem%d", cxlmd->id); - if (rc) - goto err; - - rc = device_add(dev); - if (rc) - goto err; - - dev_dbg(host, "%s: register %s\n", dev_name(dev->parent), - dev_name(dev)); - - return devm_add_action_or_reset(host, unregister_dev, dev); - -err: - put_device(dev); - return rc; -} -EXPORT_SYMBOL_GPL(devm_cxl_add_nvdimm); - /** * cxl_probe_device_regs() - Detect CXL Device register blocks * @dev: Host device of the @base mapping diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h new file mode 100644 index 000000000000..49045daf8bd7 --- /dev/null +++ b/drivers/cxl/core/core.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright(c) 2020 Intel Corporation. */ + +#ifndef __CXL_CORE_H__ +#define __CXL_CORE_H__ + +extern const struct device_type cxl_nvdimm_bridge_type; +extern const struct device_type cxl_nvdimm_type; + +extern struct attribute_group cxl_base_attribute_group; + +static inline void unregister_cxl_dev(void *dev) +{ + device_unregister(dev); +} + +#endif /* __CXL_CORE_H__ */ diff --git a/drivers/cxl/core/pmem.c b/drivers/cxl/core/pmem.c new file mode 100644 index 000000000000..69c97cc0d945 --- /dev/null +++ b/drivers/cxl/core/pmem.c @@ -0,0 +1,204 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright(c) 2020 Intel Corporation. */ + +#include +#include +#include +#include + +#include "core.h" + +static void cxl_nvdimm_bridge_release(struct device *dev) +{ + struct cxl_nvdimm_bridge *cxl_nvb = to_cxl_nvdimm_bridge(dev); + + kfree(cxl_nvb); +} + +static const struct attribute_group *cxl_nvdimm_bridge_attribute_groups[] = { + &cxl_base_attribute_group, + NULL, +}; + +const struct device_type cxl_nvdimm_bridge_type = { + .name = "cxl_nvdimm_bridge", + .release = cxl_nvdimm_bridge_release, + .groups = cxl_nvdimm_bridge_attribute_groups, +}; + +struct cxl_nvdimm_bridge *to_cxl_nvdimm_bridge(struct device *dev) +{ + if (dev_WARN_ONCE(dev, dev->type != &cxl_nvdimm_bridge_type, + "not a cxl_nvdimm_bridge device\n")) + return NULL; + return container_of(dev, struct cxl_nvdimm_bridge, dev); +} +EXPORT_SYMBOL_GPL(to_cxl_nvdimm_bridge); + +static struct cxl_nvdimm_bridge * +cxl_nvdimm_bridge_alloc(struct cxl_port *port) +{ + struct cxl_nvdimm_bridge *cxl_nvb; + struct device *dev; + + cxl_nvb = kzalloc(sizeof(*cxl_nvb), GFP_KERNEL); + if (!cxl_nvb) + return ERR_PTR(-ENOMEM); + + dev = &cxl_nvb->dev; + cxl_nvb->port = port; + cxl_nvb->state = CXL_NVB_NEW; + device_initialize(dev); + device_set_pm_not_required(dev); + dev->parent = &port->dev; + dev->bus = &cxl_bus_type; + dev->type = &cxl_nvdimm_bridge_type; + + return cxl_nvb; +} + +static void unregister_nvb(void *_cxl_nvb) +{ + struct cxl_nvdimm_bridge *cxl_nvb = _cxl_nvb; + bool flush; + + /* + * If the bridge was ever activated then there might be in-flight state + * work to flush. Once the state has been changed to 'dead' then no new + * work can be queued by user-triggered bind. + */ + device_lock(&cxl_nvb->dev); + flush = cxl_nvb->state != CXL_NVB_NEW; + cxl_nvb->state = CXL_NVB_DEAD; + device_unlock(&cxl_nvb->dev); + + /* + * Even though the device core will trigger device_release_driver() + * before the unregister, it does not know about the fact that + * cxl_nvdimm_bridge_driver defers ->remove() work. So, do the driver + * release not and flush it before tearing down the nvdimm device + * hierarchy. + */ + device_release_driver(&cxl_nvb->dev); + if (flush) + flush_work(&cxl_nvb->state_work); + device_unregister(&cxl_nvb->dev); +} + +struct cxl_nvdimm_bridge *devm_cxl_add_nvdimm_bridge(struct device *host, + struct cxl_port *port) +{ + struct cxl_nvdimm_bridge *cxl_nvb; + struct device *dev; + int rc; + + if (!IS_ENABLED(CONFIG_CXL_PMEM)) + return ERR_PTR(-ENXIO); + + cxl_nvb = cxl_nvdimm_bridge_alloc(port); + if (IS_ERR(cxl_nvb)) + return cxl_nvb; + + dev = &cxl_nvb->dev; + rc = dev_set_name(dev, "nvdimm-bridge"); + if (rc) + goto err; + + rc = device_add(dev); + if (rc) + goto err; + + rc = devm_add_action_or_reset(host, unregister_nvb, cxl_nvb); + if (rc) + return ERR_PTR(rc); + + return cxl_nvb; + +err: + put_device(dev); + return ERR_PTR(rc); +} +EXPORT_SYMBOL_GPL(devm_cxl_add_nvdimm_bridge); + +static void cxl_nvdimm_release(struct device *dev) +{ + struct cxl_nvdimm *cxl_nvd = to_cxl_nvdimm(dev); + + kfree(cxl_nvd); +} + +static const struct attribute_group *cxl_nvdimm_attribute_groups[] = { + &cxl_base_attribute_group, + NULL, +}; + +const struct device_type cxl_nvdimm_type = { + .name = "cxl_nvdimm", + .release = cxl_nvdimm_release, + .groups = cxl_nvdimm_attribute_groups, +}; + +bool is_cxl_nvdimm(struct device *dev) +{ + return dev->type == &cxl_nvdimm_type; +} +EXPORT_SYMBOL_GPL(is_cxl_nvdimm); + +struct cxl_nvdimm *to_cxl_nvdimm(struct device *dev) +{ + if (dev_WARN_ONCE(dev, !is_cxl_nvdimm(dev), + "not a cxl_nvdimm device\n")) + return NULL; + return container_of(dev, struct cxl_nvdimm, dev); +} +EXPORT_SYMBOL_GPL(to_cxl_nvdimm); + +static struct cxl_nvdimm *cxl_nvdimm_alloc(struct cxl_memdev *cxlmd) +{ + struct cxl_nvdimm *cxl_nvd; + struct device *dev; + + cxl_nvd = kzalloc(sizeof(*cxl_nvd), GFP_KERNEL); + if (!cxl_nvd) + return ERR_PTR(-ENOMEM); + + dev = &cxl_nvd->dev; + cxl_nvd->cxlmd = cxlmd; + device_initialize(dev); + device_set_pm_not_required(dev); + dev->parent = &cxlmd->dev; + dev->bus = &cxl_bus_type; + dev->type = &cxl_nvdimm_type; + + return cxl_nvd; +} + +int devm_cxl_add_nvdimm(struct device *host, struct cxl_memdev *cxlmd) +{ + struct cxl_nvdimm *cxl_nvd; + struct device *dev; + int rc; + + cxl_nvd = cxl_nvdimm_alloc(cxlmd); + if (IS_ERR(cxl_nvd)) + return PTR_ERR(cxl_nvd); + + dev = &cxl_nvd->dev; + rc = dev_set_name(dev, "pmem%d", cxlmd->id); + if (rc) + goto err; + + rc = device_add(dev); + if (rc) + goto err; + + dev_dbg(host, "%s: register %s\n", dev_name(dev->parent), + dev_name(dev)); + + return devm_add_action_or_reset(host, unregister_cxl_dev, dev); + +err: + put_device(dev); + return rc; +} +EXPORT_SYMBOL_GPL(devm_cxl_add_nvdimm); From 0f06157e0135f5563efbc9aadbd93ba3d9322cab Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 3 Aug 2021 07:25:38 -0700 Subject: [PATCH 097/696] cxl/core: Move register mapping infrastructure The register mapping infrastructure is large enough to move to its own compilation unit. This also cleans up an unnecessary include of core/bus.c. Reported-by: kernel test robot Signed-off-by: Ben Widawsky Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/162800068975.665205.12895551621746585289.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams --- .../driver-api/cxl/memory-devices.rst | 3 + drivers/cxl/core/Makefile | 1 + drivers/cxl/core/bus.c | 228 ----------------- drivers/cxl/core/regs.c | 236 ++++++++++++++++++ 4 files changed, 240 insertions(+), 228 deletions(-) create mode 100644 drivers/cxl/core/regs.c diff --git a/Documentation/driver-api/cxl/memory-devices.rst b/Documentation/driver-api/cxl/memory-devices.rst index e65c0ba82229..46847d8c70a0 100644 --- a/Documentation/driver-api/cxl/memory-devices.rst +++ b/Documentation/driver-api/cxl/memory-devices.rst @@ -42,6 +42,9 @@ CXL Core .. kernel-doc:: drivers/cxl/core/pmem.c :internal: +.. kernel-doc:: drivers/cxl/core/regs.c + :internal: + External Interfaces =================== diff --git a/drivers/cxl/core/Makefile b/drivers/cxl/core/Makefile index e037521fe02b..a3522d2fbf5b 100644 --- a/drivers/cxl/core/Makefile +++ b/drivers/cxl/core/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_CXL_BUS) += cxl_core.o ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=CXL -I$(srctree)/drivers/cxl cxl_core-y := bus.o cxl_core-y += pmem.o +cxl_core-y += regs.o diff --git a/drivers/cxl/core/bus.c b/drivers/cxl/core/bus.c index 408654ad70db..c938d8590c9f 100644 --- a/drivers/cxl/core/bus.c +++ b/drivers/cxl/core/bus.c @@ -550,234 +550,6 @@ err: } EXPORT_SYMBOL_GPL(devm_cxl_add_decoder); -/** - * cxl_probe_component_regs() - Detect CXL Component register blocks - * @dev: Host device of the @base mapping - * @base: Mapping containing the HDM Decoder Capability Header - * @map: Map object describing the register block information found - * - * See CXL 2.0 8.2.4 Component Register Layout and Definition - * See CXL 2.0 8.2.5.5 CXL Device Register Interface - * - * Probe for component register information and return it in map object. - */ -void cxl_probe_component_regs(struct device *dev, void __iomem *base, - struct cxl_component_reg_map *map) -{ - int cap, cap_count; - u64 cap_array; - - *map = (struct cxl_component_reg_map) { 0 }; - - /* - * CXL.cache and CXL.mem registers are at offset 0x1000 as defined in - * CXL 2.0 8.2.4 Table 141. - */ - base += CXL_CM_OFFSET; - - cap_array = readq(base + CXL_CM_CAP_HDR_OFFSET); - - if (FIELD_GET(CXL_CM_CAP_HDR_ID_MASK, cap_array) != CM_CAP_HDR_CAP_ID) { - dev_err(dev, - "Couldn't locate the CXL.cache and CXL.mem capability array header./n"); - return; - } - - /* It's assumed that future versions will be backward compatible */ - cap_count = FIELD_GET(CXL_CM_CAP_HDR_ARRAY_SIZE_MASK, cap_array); - - for (cap = 1; cap <= cap_count; cap++) { - void __iomem *register_block; - u32 hdr; - int decoder_cnt; - u16 cap_id, offset; - u32 length; - - hdr = readl(base + cap * 0x4); - - cap_id = FIELD_GET(CXL_CM_CAP_HDR_ID_MASK, hdr); - offset = FIELD_GET(CXL_CM_CAP_PTR_MASK, hdr); - register_block = base + offset; - - switch (cap_id) { - case CXL_CM_CAP_CAP_ID_HDM: - dev_dbg(dev, "found HDM decoder capability (0x%x)\n", - offset); - - hdr = readl(register_block); - - decoder_cnt = cxl_hdm_decoder_count(hdr); - length = 0x20 * decoder_cnt + 0x10; - - map->hdm_decoder.valid = true; - map->hdm_decoder.offset = CXL_CM_OFFSET + offset; - map->hdm_decoder.size = length; - break; - default: - dev_dbg(dev, "Unknown CM cap ID: %d (0x%x)\n", cap_id, - offset); - break; - } - } -} -EXPORT_SYMBOL_GPL(cxl_probe_component_regs); - -/** - * cxl_probe_device_regs() - Detect CXL Device register blocks - * @dev: Host device of the @base mapping - * @base: Mapping of CXL 2.0 8.2.8 CXL Device Register Interface - * @map: Map object describing the register block information found - * - * Probe for device register information and return it in map object. - */ -void cxl_probe_device_regs(struct device *dev, void __iomem *base, - struct cxl_device_reg_map *map) -{ - int cap, cap_count; - u64 cap_array; - - *map = (struct cxl_device_reg_map){ 0 }; - - cap_array = readq(base + CXLDEV_CAP_ARRAY_OFFSET); - if (FIELD_GET(CXLDEV_CAP_ARRAY_ID_MASK, cap_array) != - CXLDEV_CAP_ARRAY_CAP_ID) - return; - - cap_count = FIELD_GET(CXLDEV_CAP_ARRAY_COUNT_MASK, cap_array); - - for (cap = 1; cap <= cap_count; cap++) { - u32 offset, length; - u16 cap_id; - - cap_id = FIELD_GET(CXLDEV_CAP_HDR_CAP_ID_MASK, - readl(base + cap * 0x10)); - offset = readl(base + cap * 0x10 + 0x4); - length = readl(base + cap * 0x10 + 0x8); - - switch (cap_id) { - case CXLDEV_CAP_CAP_ID_DEVICE_STATUS: - dev_dbg(dev, "found Status capability (0x%x)\n", offset); - - map->status.valid = true; - map->status.offset = offset; - map->status.size = length; - break; - case CXLDEV_CAP_CAP_ID_PRIMARY_MAILBOX: - dev_dbg(dev, "found Mailbox capability (0x%x)\n", offset); - map->mbox.valid = true; - map->mbox.offset = offset; - map->mbox.size = length; - break; - case CXLDEV_CAP_CAP_ID_SECONDARY_MAILBOX: - dev_dbg(dev, "found Secondary Mailbox capability (0x%x)\n", offset); - break; - case CXLDEV_CAP_CAP_ID_MEMDEV: - dev_dbg(dev, "found Memory Device capability (0x%x)\n", offset); - map->memdev.valid = true; - map->memdev.offset = offset; - map->memdev.size = length; - break; - default: - if (cap_id >= 0x8000) - dev_dbg(dev, "Vendor cap ID: %#x offset: %#x\n", cap_id, offset); - else - dev_dbg(dev, "Unknown cap ID: %#x offset: %#x\n", cap_id, offset); - break; - } - } -} -EXPORT_SYMBOL_GPL(cxl_probe_device_regs); - -static void __iomem *devm_cxl_iomap_block(struct device *dev, - resource_size_t addr, - resource_size_t length) -{ - void __iomem *ret_val; - struct resource *res; - - res = devm_request_mem_region(dev, addr, length, dev_name(dev)); - if (!res) { - resource_size_t end = addr + length - 1; - - dev_err(dev, "Failed to request region %pa-%pa\n", &addr, &end); - return NULL; - } - - ret_val = devm_ioremap(dev, addr, length); - if (!ret_val) - dev_err(dev, "Failed to map region %pr\n", res); - - return ret_val; -} - -int cxl_map_component_regs(struct pci_dev *pdev, - struct cxl_component_regs *regs, - struct cxl_register_map *map) -{ - struct device *dev = &pdev->dev; - resource_size_t phys_addr; - resource_size_t length; - - phys_addr = pci_resource_start(pdev, map->barno); - phys_addr += map->block_offset; - - phys_addr += map->component_map.hdm_decoder.offset; - length = map->component_map.hdm_decoder.size; - regs->hdm_decoder = devm_cxl_iomap_block(dev, phys_addr, length); - if (!regs->hdm_decoder) - return -ENOMEM; - - return 0; -} -EXPORT_SYMBOL_GPL(cxl_map_component_regs); - -int cxl_map_device_regs(struct pci_dev *pdev, - struct cxl_device_regs *regs, - struct cxl_register_map *map) -{ - struct device *dev = &pdev->dev; - resource_size_t phys_addr; - - phys_addr = pci_resource_start(pdev, map->barno); - phys_addr += map->block_offset; - - if (map->device_map.status.valid) { - resource_size_t addr; - resource_size_t length; - - addr = phys_addr + map->device_map.status.offset; - length = map->device_map.status.size; - regs->status = devm_cxl_iomap_block(dev, addr, length); - if (!regs->status) - return -ENOMEM; - } - - if (map->device_map.mbox.valid) { - resource_size_t addr; - resource_size_t length; - - addr = phys_addr + map->device_map.mbox.offset; - length = map->device_map.mbox.size; - regs->mbox = devm_cxl_iomap_block(dev, addr, length); - if (!regs->mbox) - return -ENOMEM; - } - - if (map->device_map.memdev.valid) { - resource_size_t addr; - resource_size_t length; - - addr = phys_addr + map->device_map.memdev.offset; - length = map->device_map.memdev.size; - regs->memdev = devm_cxl_iomap_block(dev, addr, length); - if (!regs->memdev) - return -ENOMEM; - } - - return 0; -} -EXPORT_SYMBOL_GPL(cxl_map_device_regs); - /** * __cxl_driver_register - register a driver for the cxl bus * @cxl_drv: cxl driver structure to attach diff --git a/drivers/cxl/core/regs.c b/drivers/cxl/core/regs.c new file mode 100644 index 000000000000..8535a7b94f28 --- /dev/null +++ b/drivers/cxl/core/regs.c @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright(c) 2020 Intel Corporation. */ + +#include +#include +#include +#include +#include + +/** + * cxl_probe_component_regs() - Detect CXL Component register blocks + * @dev: Host device of the @base mapping + * @base: Mapping containing the HDM Decoder Capability Header + * @map: Map object describing the register block information found + * + * See CXL 2.0 8.2.4 Component Register Layout and Definition + * See CXL 2.0 8.2.5.5 CXL Device Register Interface + * + * Probe for component register information and return it in map object. + */ +void cxl_probe_component_regs(struct device *dev, void __iomem *base, + struct cxl_component_reg_map *map) +{ + int cap, cap_count; + u64 cap_array; + + *map = (struct cxl_component_reg_map) { 0 }; + + /* + * CXL.cache and CXL.mem registers are at offset 0x1000 as defined in + * CXL 2.0 8.2.4 Table 141. + */ + base += CXL_CM_OFFSET; + + cap_array = readq(base + CXL_CM_CAP_HDR_OFFSET); + + if (FIELD_GET(CXL_CM_CAP_HDR_ID_MASK, cap_array) != CM_CAP_HDR_CAP_ID) { + dev_err(dev, + "Couldn't locate the CXL.cache and CXL.mem capability array header./n"); + return; + } + + /* It's assumed that future versions will be backward compatible */ + cap_count = FIELD_GET(CXL_CM_CAP_HDR_ARRAY_SIZE_MASK, cap_array); + + for (cap = 1; cap <= cap_count; cap++) { + void __iomem *register_block; + u32 hdr; + int decoder_cnt; + u16 cap_id, offset; + u32 length; + + hdr = readl(base + cap * 0x4); + + cap_id = FIELD_GET(CXL_CM_CAP_HDR_ID_MASK, hdr); + offset = FIELD_GET(CXL_CM_CAP_PTR_MASK, hdr); + register_block = base + offset; + + switch (cap_id) { + case CXL_CM_CAP_CAP_ID_HDM: + dev_dbg(dev, "found HDM decoder capability (0x%x)\n", + offset); + + hdr = readl(register_block); + + decoder_cnt = cxl_hdm_decoder_count(hdr); + length = 0x20 * decoder_cnt + 0x10; + + map->hdm_decoder.valid = true; + map->hdm_decoder.offset = CXL_CM_OFFSET + offset; + map->hdm_decoder.size = length; + break; + default: + dev_dbg(dev, "Unknown CM cap ID: %d (0x%x)\n", cap_id, + offset); + break; + } + } +} +EXPORT_SYMBOL_GPL(cxl_probe_component_regs); + +/** + * cxl_probe_device_regs() - Detect CXL Device register blocks + * @dev: Host device of the @base mapping + * @base: Mapping of CXL 2.0 8.2.8 CXL Device Register Interface + * @map: Map object describing the register block information found + * + * Probe for device register information and return it in map object. + */ +void cxl_probe_device_regs(struct device *dev, void __iomem *base, + struct cxl_device_reg_map *map) +{ + int cap, cap_count; + u64 cap_array; + + *map = (struct cxl_device_reg_map){ 0 }; + + cap_array = readq(base + CXLDEV_CAP_ARRAY_OFFSET); + if (FIELD_GET(CXLDEV_CAP_ARRAY_ID_MASK, cap_array) != + CXLDEV_CAP_ARRAY_CAP_ID) + return; + + cap_count = FIELD_GET(CXLDEV_CAP_ARRAY_COUNT_MASK, cap_array); + + for (cap = 1; cap <= cap_count; cap++) { + u32 offset, length; + u16 cap_id; + + cap_id = FIELD_GET(CXLDEV_CAP_HDR_CAP_ID_MASK, + readl(base + cap * 0x10)); + offset = readl(base + cap * 0x10 + 0x4); + length = readl(base + cap * 0x10 + 0x8); + + switch (cap_id) { + case CXLDEV_CAP_CAP_ID_DEVICE_STATUS: + dev_dbg(dev, "found Status capability (0x%x)\n", offset); + + map->status.valid = true; + map->status.offset = offset; + map->status.size = length; + break; + case CXLDEV_CAP_CAP_ID_PRIMARY_MAILBOX: + dev_dbg(dev, "found Mailbox capability (0x%x)\n", offset); + map->mbox.valid = true; + map->mbox.offset = offset; + map->mbox.size = length; + break; + case CXLDEV_CAP_CAP_ID_SECONDARY_MAILBOX: + dev_dbg(dev, "found Secondary Mailbox capability (0x%x)\n", offset); + break; + case CXLDEV_CAP_CAP_ID_MEMDEV: + dev_dbg(dev, "found Memory Device capability (0x%x)\n", offset); + map->memdev.valid = true; + map->memdev.offset = offset; + map->memdev.size = length; + break; + default: + if (cap_id >= 0x8000) + dev_dbg(dev, "Vendor cap ID: %#x offset: %#x\n", cap_id, offset); + else + dev_dbg(dev, "Unknown cap ID: %#x offset: %#x\n", cap_id, offset); + break; + } + } +} +EXPORT_SYMBOL_GPL(cxl_probe_device_regs); + +static void __iomem *devm_cxl_iomap_block(struct device *dev, + resource_size_t addr, + resource_size_t length) +{ + void __iomem *ret_val; + struct resource *res; + + res = devm_request_mem_region(dev, addr, length, dev_name(dev)); + if (!res) { + resource_size_t end = addr + length - 1; + + dev_err(dev, "Failed to request region %pa-%pa\n", &addr, &end); + return NULL; + } + + ret_val = devm_ioremap(dev, addr, length); + if (!ret_val) + dev_err(dev, "Failed to map region %pr\n", res); + + return ret_val; +} + +int cxl_map_component_regs(struct pci_dev *pdev, + struct cxl_component_regs *regs, + struct cxl_register_map *map) +{ + struct device *dev = &pdev->dev; + resource_size_t phys_addr; + resource_size_t length; + + phys_addr = pci_resource_start(pdev, map->barno); + phys_addr += map->block_offset; + + phys_addr += map->component_map.hdm_decoder.offset; + length = map->component_map.hdm_decoder.size; + regs->hdm_decoder = devm_cxl_iomap_block(dev, phys_addr, length); + if (!regs->hdm_decoder) + return -ENOMEM; + + return 0; +} +EXPORT_SYMBOL_GPL(cxl_map_component_regs); + +int cxl_map_device_regs(struct pci_dev *pdev, + struct cxl_device_regs *regs, + struct cxl_register_map *map) +{ + struct device *dev = &pdev->dev; + resource_size_t phys_addr; + + phys_addr = pci_resource_start(pdev, map->barno); + phys_addr += map->block_offset; + + if (map->device_map.status.valid) { + resource_size_t addr; + resource_size_t length; + + addr = phys_addr + map->device_map.status.offset; + length = map->device_map.status.size; + regs->status = devm_cxl_iomap_block(dev, addr, length); + if (!regs->status) + return -ENOMEM; + } + + if (map->device_map.mbox.valid) { + resource_size_t addr; + resource_size_t length; + + addr = phys_addr + map->device_map.mbox.offset; + length = map->device_map.mbox.size; + regs->mbox = devm_cxl_iomap_block(dev, addr, length); + if (!regs->mbox) + return -ENOMEM; + } + + if (map->device_map.memdev.valid) { + resource_size_t addr; + resource_size_t length; + + addr = phys_addr + map->device_map.memdev.offset; + length = map->device_map.memdev.size; + regs->memdev = devm_cxl_iomap_block(dev, addr, length); + if (!regs->memdev) + return -ENOMEM; + } + + return 0; +} +EXPORT_SYMBOL_GPL(cxl_map_device_regs); From 9cc238c7a526dba9ee8c210fa2828886fc65db66 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 2 Aug 2021 10:29:59 -0700 Subject: [PATCH 098/696] cxl/pci: Introduce cdevm_file_operations In preparation for moving cxl_memdev allocation to the core, introduce cdevm_file_operations to coordinate file operations shutdown relative to driver data release. The motivation for moving cxl_memdev allocation to the core (beyond better file organization of sysfs attributes in core/ and drivers in cxl/), is that device lifetime is longer than module lifetime. The cxl_pci module should be free to come and go without needing to coordinate with devices that need the text associated with cxl_memdev_release() to stay resident. The move will fix a use after free bug when looping driver load / unload with CONFIG_DEBUG_KOBJECT_RELEASE=y. Another motivation for passing in file_operations to the core cxl_memdev creation flow is to allow for alternate drivers, like unit test code, to define their own ioctl backends. Signed-off-by: Ben Widawsky Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/162792539962.368511.2962268954245340288.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams --- drivers/cxl/cxlmem.h | 15 ++++++++++ drivers/cxl/pci.c | 65 ++++++++++++++++++++++++++------------------ 2 files changed, 53 insertions(+), 27 deletions(-) diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h index 8f02d02b26b4..0cd463de1342 100644 --- a/drivers/cxl/cxlmem.h +++ b/drivers/cxl/cxlmem.h @@ -34,6 +34,21 @@ */ #define CXL_MEM_MAX_DEVS 65536 +/** + * struct cdevm_file_operations - devm coordinated cdev file operations + * @fops: file operations that are synchronized against @shutdown + * @shutdown: disconnect driver data + * + * @shutdown is invoked in the devres release path to disconnect any + * driver instance data from @dev. It assumes synchronization with any + * fops operation that requires driver data. After @shutdown an + * operation may only reference @device data. + */ +struct cdevm_file_operations { + struct file_operations fops; + void (*shutdown)(struct device *dev); +}; + /** * struct cxl_memdev - CXL bus object representing a Type-3 Memory Device * @dev: driver core device object diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c index a945c5fda292..f7a5ad5e1f4a 100644 --- a/drivers/cxl/pci.c +++ b/drivers/cxl/pci.c @@ -806,13 +806,30 @@ static int cxl_memdev_release_file(struct inode *inode, struct file *file) return 0; } -static const struct file_operations cxl_memdev_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = cxl_memdev_ioctl, - .open = cxl_memdev_open, - .release = cxl_memdev_release_file, - .compat_ioctl = compat_ptr_ioctl, - .llseek = noop_llseek, +static struct cxl_memdev *to_cxl_memdev(struct device *dev) +{ + return container_of(dev, struct cxl_memdev, dev); +} + +static void cxl_memdev_shutdown(struct device *dev) +{ + struct cxl_memdev *cxlmd = to_cxl_memdev(dev); + + down_write(&cxl_memdev_rwsem); + cxlmd->cxlm = NULL; + up_write(&cxl_memdev_rwsem); +} + +static const struct cdevm_file_operations cxl_memdev_fops = { + .fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = cxl_memdev_ioctl, + .open = cxl_memdev_open, + .release = cxl_memdev_release_file, + .compat_ioctl = compat_ptr_ioctl, + .llseek = noop_llseek, + }, + .shutdown = cxl_memdev_shutdown, }; static inline struct cxl_mem_command *cxl_mem_find_command(u16 opcode) @@ -1161,11 +1178,6 @@ free_maps: return ret; } -static struct cxl_memdev *to_cxl_memdev(struct device *dev) -{ - return container_of(dev, struct cxl_memdev, dev); -} - static void cxl_memdev_release(struct device *dev) { struct cxl_memdev *cxlmd = to_cxl_memdev(dev); @@ -1281,24 +1293,22 @@ static const struct device_type cxl_memdev_type = { .groups = cxl_memdev_attribute_groups, }; -static void cxl_memdev_shutdown(struct cxl_memdev *cxlmd) -{ - down_write(&cxl_memdev_rwsem); - cxlmd->cxlm = NULL; - up_write(&cxl_memdev_rwsem); -} - static void cxl_memdev_unregister(void *_cxlmd) { struct cxl_memdev *cxlmd = _cxlmd; struct device *dev = &cxlmd->dev; + struct cdev *cdev = &cxlmd->cdev; + const struct cdevm_file_operations *cdevm_fops; + + cdevm_fops = container_of(cdev->ops, typeof(*cdevm_fops), fops); + cdevm_fops->shutdown(dev); cdev_device_del(&cxlmd->cdev, dev); - cxl_memdev_shutdown(cxlmd); put_device(dev); } -static struct cxl_memdev *cxl_memdev_alloc(struct cxl_mem *cxlm) +static struct cxl_memdev *cxl_memdev_alloc(struct cxl_mem *cxlm, + const struct file_operations *fops) { struct pci_dev *pdev = cxlm->pdev; struct cxl_memdev *cxlmd; @@ -1324,7 +1334,7 @@ static struct cxl_memdev *cxl_memdev_alloc(struct cxl_mem *cxlm) device_set_pm_not_required(dev); cdev = &cxlmd->cdev; - cdev_init(cdev, &cxl_memdev_fops); + cdev_init(cdev, fops); return cxlmd; err: @@ -1332,15 +1342,16 @@ err: return ERR_PTR(rc); } -static struct cxl_memdev *devm_cxl_add_memdev(struct device *host, - struct cxl_mem *cxlm) +static struct cxl_memdev * +devm_cxl_add_memdev(struct device *host, struct cxl_mem *cxlm, + const struct cdevm_file_operations *cdevm_fops) { struct cxl_memdev *cxlmd; struct device *dev; struct cdev *cdev; int rc; - cxlmd = cxl_memdev_alloc(cxlm); + cxlmd = cxl_memdev_alloc(cxlm, &cdevm_fops->fops); if (IS_ERR(cxlmd)) return cxlmd; @@ -1370,7 +1381,7 @@ err: * The cdev was briefly live, shutdown any ioctl operations that * saw that state. */ - cxl_memdev_shutdown(cxlmd); + cdevm_fops->shutdown(dev); put_device(dev); return ERR_PTR(rc); } @@ -1611,7 +1622,7 @@ static int cxl_mem_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (rc) return rc; - cxlmd = devm_cxl_add_memdev(&pdev->dev, cxlm); + cxlmd = devm_cxl_add_memdev(&pdev->dev, cxlm, &cxl_memdev_fops); if (IS_ERR(cxlmd)) return PTR_ERR(cxlmd); From 3d135db510240fefd79da46181493d3e3b415f6b Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 2 Aug 2021 10:30:05 -0700 Subject: [PATCH 099/696] cxl/core: Move memdev management to core The motivation for moving cxl_memdev allocation to the core (beyond better file organization of sysfs attributes in core/ and drivers in cxl/), is that device lifetime is longer than module lifetime. The cxl_pci module should be free to come and go without needing to coordinate with devices that need the text associated with cxl_memdev_release() to stay resident. The move fixes a use after free bug when looping driver load / unload with CONFIG_DEBUG_KOBJECT_RELEASE=y. Another motivation for disconnecting cxl_memdev creation from cxl_pci is to enable other drivers, like a unit test driver, to registers memdevs. Fixes: b39cb1052a5c ("cxl/mem: Register CXL memX devices") Signed-off-by: Ben Widawsky Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/162792540495.368511.9748638751088219595.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams --- drivers/cxl/core/Makefile | 1 + drivers/cxl/core/bus.c | 16 ++- drivers/cxl/core/core.h | 3 + drivers/cxl/core/memdev.c | 246 ++++++++++++++++++++++++++++++++++++++ drivers/cxl/cxlmem.h | 15 ++- drivers/cxl/pci.c | 228 +---------------------------------- 6 files changed, 275 insertions(+), 234 deletions(-) create mode 100644 drivers/cxl/core/memdev.c diff --git a/drivers/cxl/core/Makefile b/drivers/cxl/core/Makefile index a3522d2fbf5b..0fdbf3c6ac1a 100644 --- a/drivers/cxl/core/Makefile +++ b/drivers/cxl/core/Makefile @@ -5,3 +5,4 @@ ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=CXL -I$(srctree)/drivers/cxl cxl_core-y := bus.o cxl_core-y += pmem.o cxl_core-y += regs.o +cxl_core-y += memdev.o diff --git a/drivers/cxl/core/bus.c b/drivers/cxl/core/bus.c index c938d8590c9f..37b87adaa33f 100644 --- a/drivers/cxl/core/bus.c +++ b/drivers/cxl/core/bus.c @@ -634,12 +634,26 @@ EXPORT_SYMBOL_GPL(cxl_bus_type); static __init int cxl_core_init(void) { - return bus_register(&cxl_bus_type); + int rc; + + rc = cxl_memdev_init(); + if (rc) + return rc; + + rc = bus_register(&cxl_bus_type); + if (rc) + goto err; + return 0; + +err: + cxl_memdev_exit(); + return rc; } static void cxl_core_exit(void) { bus_unregister(&cxl_bus_type); + cxl_memdev_exit(); } module_init(cxl_core_init); diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h index 49045daf8bd7..036a3c8106b4 100644 --- a/drivers/cxl/core/core.h +++ b/drivers/cxl/core/core.h @@ -14,4 +14,7 @@ static inline void unregister_cxl_dev(void *dev) device_unregister(dev); } +int cxl_memdev_init(void); +void cxl_memdev_exit(void); + #endif /* __CXL_CORE_H__ */ diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c new file mode 100644 index 000000000000..a9c317e32010 --- /dev/null +++ b/drivers/cxl/core/memdev.c @@ -0,0 +1,246 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright(c) 2020 Intel Corporation. */ + +#include +#include +#include +#include +#include +#include "core.h" + +/* + * An entire PCI topology full of devices should be enough for any + * config + */ +#define CXL_MEM_MAX_DEVS 65536 + +static int cxl_mem_major; +static DEFINE_IDA(cxl_memdev_ida); + +static void cxl_memdev_release(struct device *dev) +{ + struct cxl_memdev *cxlmd = to_cxl_memdev(dev); + + ida_free(&cxl_memdev_ida, cxlmd->id); + kfree(cxlmd); +} + +static char *cxl_memdev_devnode(struct device *dev, umode_t *mode, kuid_t *uid, + kgid_t *gid) +{ + return kasprintf(GFP_KERNEL, "cxl/%s", dev_name(dev)); +} + +static ssize_t firmware_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cxl_memdev *cxlmd = to_cxl_memdev(dev); + struct cxl_mem *cxlm = cxlmd->cxlm; + + return sysfs_emit(buf, "%.16s\n", cxlm->firmware_version); +} +static DEVICE_ATTR_RO(firmware_version); + +static ssize_t payload_max_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cxl_memdev *cxlmd = to_cxl_memdev(dev); + struct cxl_mem *cxlm = cxlmd->cxlm; + + return sysfs_emit(buf, "%zu\n", cxlm->payload_size); +} +static DEVICE_ATTR_RO(payload_max); + +static ssize_t label_storage_size_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cxl_memdev *cxlmd = to_cxl_memdev(dev); + struct cxl_mem *cxlm = cxlmd->cxlm; + + return sysfs_emit(buf, "%zu\n", cxlm->lsa_size); +} +static DEVICE_ATTR_RO(label_storage_size); + +static ssize_t ram_size_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct cxl_memdev *cxlmd = to_cxl_memdev(dev); + struct cxl_mem *cxlm = cxlmd->cxlm; + unsigned long long len = range_len(&cxlm->ram_range); + + return sysfs_emit(buf, "%#llx\n", len); +} + +static struct device_attribute dev_attr_ram_size = + __ATTR(size, 0444, ram_size_show, NULL); + +static ssize_t pmem_size_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct cxl_memdev *cxlmd = to_cxl_memdev(dev); + struct cxl_mem *cxlm = cxlmd->cxlm; + unsigned long long len = range_len(&cxlm->pmem_range); + + return sysfs_emit(buf, "%#llx\n", len); +} + +static struct device_attribute dev_attr_pmem_size = + __ATTR(size, 0444, pmem_size_show, NULL); + +static struct attribute *cxl_memdev_attributes[] = { + &dev_attr_firmware_version.attr, + &dev_attr_payload_max.attr, + &dev_attr_label_storage_size.attr, + NULL, +}; + +static struct attribute *cxl_memdev_pmem_attributes[] = { + &dev_attr_pmem_size.attr, + NULL, +}; + +static struct attribute *cxl_memdev_ram_attributes[] = { + &dev_attr_ram_size.attr, + NULL, +}; + +static struct attribute_group cxl_memdev_attribute_group = { + .attrs = cxl_memdev_attributes, +}; + +static struct attribute_group cxl_memdev_ram_attribute_group = { + .name = "ram", + .attrs = cxl_memdev_ram_attributes, +}; + +static struct attribute_group cxl_memdev_pmem_attribute_group = { + .name = "pmem", + .attrs = cxl_memdev_pmem_attributes, +}; + +static const struct attribute_group *cxl_memdev_attribute_groups[] = { + &cxl_memdev_attribute_group, + &cxl_memdev_ram_attribute_group, + &cxl_memdev_pmem_attribute_group, + NULL, +}; + +static const struct device_type cxl_memdev_type = { + .name = "cxl_memdev", + .release = cxl_memdev_release, + .devnode = cxl_memdev_devnode, + .groups = cxl_memdev_attribute_groups, +}; + +static void cxl_memdev_unregister(void *_cxlmd) +{ + struct cxl_memdev *cxlmd = _cxlmd; + struct device *dev = &cxlmd->dev; + struct cdev *cdev = &cxlmd->cdev; + const struct cdevm_file_operations *cdevm_fops; + + cdevm_fops = container_of(cdev->ops, typeof(*cdevm_fops), fops); + cdevm_fops->shutdown(dev); + + cdev_device_del(&cxlmd->cdev, dev); + put_device(dev); +} + +static struct cxl_memdev *cxl_memdev_alloc(struct cxl_mem *cxlm, + const struct file_operations *fops) +{ + struct pci_dev *pdev = cxlm->pdev; + struct cxl_memdev *cxlmd; + struct device *dev; + struct cdev *cdev; + int rc; + + cxlmd = kzalloc(sizeof(*cxlmd), GFP_KERNEL); + if (!cxlmd) + return ERR_PTR(-ENOMEM); + + rc = ida_alloc_range(&cxl_memdev_ida, 0, CXL_MEM_MAX_DEVS, GFP_KERNEL); + if (rc < 0) + goto err; + cxlmd->id = rc; + + dev = &cxlmd->dev; + device_initialize(dev); + dev->parent = &pdev->dev; + dev->bus = &cxl_bus_type; + dev->devt = MKDEV(cxl_mem_major, cxlmd->id); + dev->type = &cxl_memdev_type; + device_set_pm_not_required(dev); + + cdev = &cxlmd->cdev; + cdev_init(cdev, fops); + return cxlmd; + +err: + kfree(cxlmd); + return ERR_PTR(rc); +} + +struct cxl_memdev * +devm_cxl_add_memdev(struct device *host, struct cxl_mem *cxlm, + const struct cdevm_file_operations *cdevm_fops) +{ + struct cxl_memdev *cxlmd; + struct device *dev; + struct cdev *cdev; + int rc; + + cxlmd = cxl_memdev_alloc(cxlm, &cdevm_fops->fops); + if (IS_ERR(cxlmd)) + return cxlmd; + + dev = &cxlmd->dev; + rc = dev_set_name(dev, "mem%d", cxlmd->id); + if (rc) + goto err; + + /* + * Activate ioctl operations, no cxl_memdev_rwsem manipulation + * needed as this is ordered with cdev_add() publishing the device. + */ + cxlmd->cxlm = cxlm; + + cdev = &cxlmd->cdev; + rc = cdev_device_add(cdev, dev); + if (rc) + goto err; + + rc = devm_add_action_or_reset(host, cxl_memdev_unregister, cxlmd); + if (rc) + return ERR_PTR(rc); + return cxlmd; + +err: + /* + * The cdev was briefly live, shutdown any ioctl operations that + * saw that state. + */ + cdevm_fops->shutdown(dev); + put_device(dev); + return ERR_PTR(rc); +} +EXPORT_SYMBOL_GPL(devm_cxl_add_memdev); + +__init int cxl_memdev_init(void) +{ + dev_t devt; + int rc; + + rc = alloc_chrdev_region(&devt, 0, CXL_MEM_MAX_DEVS, "cxl"); + if (rc) + return rc; + + cxl_mem_major = MAJOR(devt); + + return 0; +} + +void cxl_memdev_exit(void) +{ + unregister_chrdev_region(MKDEV(cxl_mem_major, 0), CXL_MEM_MAX_DEVS); +} diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h index 0cd463de1342..25345ece25f8 100644 --- a/drivers/cxl/cxlmem.h +++ b/drivers/cxl/cxlmem.h @@ -28,12 +28,6 @@ (FIELD_GET(CXLMDEV_RESET_NEEDED_MASK, status) != \ CXLMDEV_RESET_NEEDED_NOT) -/* - * An entire PCI topology full of devices should be enough for any - * config - */ -#define CXL_MEM_MAX_DEVS 65536 - /** * struct cdevm_file_operations - devm coordinated cdev file operations * @fops: file operations that are synchronized against @shutdown @@ -63,6 +57,15 @@ struct cxl_memdev { int id; }; +static inline struct cxl_memdev *to_cxl_memdev(struct device *dev) +{ + return container_of(dev, struct cxl_memdev, dev); +} + +struct cxl_memdev * +devm_cxl_add_memdev(struct device *host, struct cxl_mem *cxlm, + const struct cdevm_file_operations *cdevm_fops); + /** * struct cxl_mem - A CXL memory device * @pdev: The PCI device associated with this CXL device. diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c index f7a5ad5e1f4a..193983e6edce 100644 --- a/drivers/cxl/pci.c +++ b/drivers/cxl/pci.c @@ -94,8 +94,6 @@ struct mbox_cmd { #define CXL_MBOX_SUCCESS 0 }; -static int cxl_mem_major; -static DEFINE_IDA(cxl_memdev_ida); static DECLARE_RWSEM(cxl_memdev_rwsem); static struct dentry *cxl_debugfs; static bool cxl_raw_allow_all; @@ -806,11 +804,6 @@ static int cxl_memdev_release_file(struct inode *inode, struct file *file) return 0; } -static struct cxl_memdev *to_cxl_memdev(struct device *dev) -{ - return container_of(dev, struct cxl_memdev, dev); -} - static void cxl_memdev_shutdown(struct device *dev) { struct cxl_memdev *cxlmd = to_cxl_memdev(dev); @@ -1178,214 +1171,6 @@ free_maps: return ret; } -static void cxl_memdev_release(struct device *dev) -{ - struct cxl_memdev *cxlmd = to_cxl_memdev(dev); - - ida_free(&cxl_memdev_ida, cxlmd->id); - kfree(cxlmd); -} - -static char *cxl_memdev_devnode(struct device *dev, umode_t *mode, kuid_t *uid, - kgid_t *gid) -{ - return kasprintf(GFP_KERNEL, "cxl/%s", dev_name(dev)); -} - -static ssize_t firmware_version_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct cxl_memdev *cxlmd = to_cxl_memdev(dev); - struct cxl_mem *cxlm = cxlmd->cxlm; - - return sysfs_emit(buf, "%.16s\n", cxlm->firmware_version); -} -static DEVICE_ATTR_RO(firmware_version); - -static ssize_t payload_max_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct cxl_memdev *cxlmd = to_cxl_memdev(dev); - struct cxl_mem *cxlm = cxlmd->cxlm; - - return sysfs_emit(buf, "%zu\n", cxlm->payload_size); -} -static DEVICE_ATTR_RO(payload_max); - -static ssize_t label_storage_size_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct cxl_memdev *cxlmd = to_cxl_memdev(dev); - struct cxl_mem *cxlm = cxlmd->cxlm; - - return sysfs_emit(buf, "%zu\n", cxlm->lsa_size); -} -static DEVICE_ATTR_RO(label_storage_size); - -static ssize_t ram_size_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct cxl_memdev *cxlmd = to_cxl_memdev(dev); - struct cxl_mem *cxlm = cxlmd->cxlm; - unsigned long long len = range_len(&cxlm->ram_range); - - return sysfs_emit(buf, "%#llx\n", len); -} - -static struct device_attribute dev_attr_ram_size = - __ATTR(size, 0444, ram_size_show, NULL); - -static ssize_t pmem_size_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct cxl_memdev *cxlmd = to_cxl_memdev(dev); - struct cxl_mem *cxlm = cxlmd->cxlm; - unsigned long long len = range_len(&cxlm->pmem_range); - - return sysfs_emit(buf, "%#llx\n", len); -} - -static struct device_attribute dev_attr_pmem_size = - __ATTR(size, 0444, pmem_size_show, NULL); - -static struct attribute *cxl_memdev_attributes[] = { - &dev_attr_firmware_version.attr, - &dev_attr_payload_max.attr, - &dev_attr_label_storage_size.attr, - NULL, -}; - -static struct attribute *cxl_memdev_pmem_attributes[] = { - &dev_attr_pmem_size.attr, - NULL, -}; - -static struct attribute *cxl_memdev_ram_attributes[] = { - &dev_attr_ram_size.attr, - NULL, -}; - -static struct attribute_group cxl_memdev_attribute_group = { - .attrs = cxl_memdev_attributes, -}; - -static struct attribute_group cxl_memdev_ram_attribute_group = { - .name = "ram", - .attrs = cxl_memdev_ram_attributes, -}; - -static struct attribute_group cxl_memdev_pmem_attribute_group = { - .name = "pmem", - .attrs = cxl_memdev_pmem_attributes, -}; - -static const struct attribute_group *cxl_memdev_attribute_groups[] = { - &cxl_memdev_attribute_group, - &cxl_memdev_ram_attribute_group, - &cxl_memdev_pmem_attribute_group, - NULL, -}; - -static const struct device_type cxl_memdev_type = { - .name = "cxl_memdev", - .release = cxl_memdev_release, - .devnode = cxl_memdev_devnode, - .groups = cxl_memdev_attribute_groups, -}; - -static void cxl_memdev_unregister(void *_cxlmd) -{ - struct cxl_memdev *cxlmd = _cxlmd; - struct device *dev = &cxlmd->dev; - struct cdev *cdev = &cxlmd->cdev; - const struct cdevm_file_operations *cdevm_fops; - - cdevm_fops = container_of(cdev->ops, typeof(*cdevm_fops), fops); - cdevm_fops->shutdown(dev); - - cdev_device_del(&cxlmd->cdev, dev); - put_device(dev); -} - -static struct cxl_memdev *cxl_memdev_alloc(struct cxl_mem *cxlm, - const struct file_operations *fops) -{ - struct pci_dev *pdev = cxlm->pdev; - struct cxl_memdev *cxlmd; - struct device *dev; - struct cdev *cdev; - int rc; - - cxlmd = kzalloc(sizeof(*cxlmd), GFP_KERNEL); - if (!cxlmd) - return ERR_PTR(-ENOMEM); - - rc = ida_alloc_range(&cxl_memdev_ida, 0, CXL_MEM_MAX_DEVS, GFP_KERNEL); - if (rc < 0) - goto err; - cxlmd->id = rc; - - dev = &cxlmd->dev; - device_initialize(dev); - dev->parent = &pdev->dev; - dev->bus = &cxl_bus_type; - dev->devt = MKDEV(cxl_mem_major, cxlmd->id); - dev->type = &cxl_memdev_type; - device_set_pm_not_required(dev); - - cdev = &cxlmd->cdev; - cdev_init(cdev, fops); - return cxlmd; - -err: - kfree(cxlmd); - return ERR_PTR(rc); -} - -static struct cxl_memdev * -devm_cxl_add_memdev(struct device *host, struct cxl_mem *cxlm, - const struct cdevm_file_operations *cdevm_fops) -{ - struct cxl_memdev *cxlmd; - struct device *dev; - struct cdev *cdev; - int rc; - - cxlmd = cxl_memdev_alloc(cxlm, &cdevm_fops->fops); - if (IS_ERR(cxlmd)) - return cxlmd; - - dev = &cxlmd->dev; - rc = dev_set_name(dev, "mem%d", cxlmd->id); - if (rc) - goto err; - - /* - * Activate ioctl operations, no cxl_memdev_rwsem manipulation - * needed as this is ordered with cdev_add() publishing the device. - */ - cxlmd->cxlm = cxlm; - - cdev = &cxlmd->cdev; - rc = cdev_device_add(cdev, dev); - if (rc) - goto err; - - rc = devm_add_action_or_reset(host, cxl_memdev_unregister, cxlmd); - if (rc) - return ERR_PTR(rc); - return cxlmd; - -err: - /* - * The cdev was briefly live, shutdown any ioctl operations that - * saw that state. - */ - cdevm_fops->shutdown(dev); - put_device(dev); - return ERR_PTR(rc); -} - static int cxl_xfer_log(struct cxl_mem *cxlm, uuid_t *uuid, u32 size, u8 *out) { u32 remaining = size; @@ -1651,26 +1436,16 @@ static struct pci_driver cxl_mem_driver = { static __init int cxl_mem_init(void) { struct dentry *mbox_debugfs; - dev_t devt; int rc; /* Double check the anonymous union trickery in struct cxl_regs */ BUILD_BUG_ON(offsetof(struct cxl_regs, memdev) != offsetof(struct cxl_regs, device_regs.memdev)); - rc = alloc_chrdev_region(&devt, 0, CXL_MEM_MAX_DEVS, "cxl"); + rc = pci_register_driver(&cxl_mem_driver); if (rc) return rc; - cxl_mem_major = MAJOR(devt); - - rc = pci_register_driver(&cxl_mem_driver); - if (rc) { - unregister_chrdev_region(MKDEV(cxl_mem_major, 0), - CXL_MEM_MAX_DEVS); - return rc; - } - cxl_debugfs = debugfs_create_dir("cxl", NULL); mbox_debugfs = debugfs_create_dir("mbox", cxl_debugfs); debugfs_create_bool("raw_allow_all", 0600, mbox_debugfs, @@ -1683,7 +1458,6 @@ static __exit void cxl_mem_exit(void) { debugfs_remove_recursive(cxl_debugfs); pci_unregister_driver(&cxl_mem_driver); - unregister_chrdev_region(MKDEV(cxl_mem_major, 0), CXL_MEM_MAX_DEVS); } MODULE_LICENSE("GPL v2"); From 1e39db573e4cdf798b899de2b1e72ac9bea08013 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 16 Jul 2021 16:15:46 -0700 Subject: [PATCH 100/696] cxl/pci: Ignore unknown register block types In an effort to explicit avoid supporting vendor specific register blocks (which can happily be mapped from userspace), entirely skip probing unknown types. The secondary benefit of this will be revealed in the future with code simplification. Signed-off-by: Ben Widawsky Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20210716231548.174778-2-ben.widawsky@intel.com Signed-off-by: Dan Williams --- drivers/cxl/pci.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c index 193983e6edce..90a1c895e442 100644 --- a/drivers/cxl/pci.c +++ b/drivers/cxl/pci.c @@ -1118,14 +1118,6 @@ static int cxl_mem_setup_regs(struct cxl_mem *cxlm) u64 offset; u8 bar; - map = kzalloc(sizeof(*map), GFP_KERNEL); - if (!map) { - ret = -ENOMEM; - goto free_maps; - } - - list_add(&map->list, ®ister_maps); - pci_read_config_dword(pdev, regloc, ®_lo); pci_read_config_dword(pdev, regloc + 4, ®_hi); @@ -1135,6 +1127,18 @@ static int cxl_mem_setup_regs(struct cxl_mem *cxlm) dev_dbg(dev, "Found register block in bar %u @ 0x%llx of type %u\n", bar, offset, reg_type); + /* Ignore unknown register block types */ + if (reg_type > CXL_REGLOC_RBI_MEMDEV) + continue; + + map = kzalloc(sizeof(*map), GFP_KERNEL); + if (!map) { + ret = -ENOMEM; + goto free_maps; + } + + list_add(&map->list, ®ister_maps); + base = cxl_mem_map_regblock(cxlm, bar, offset); if (!base) { ret = -ENOMEM; From 5b68705d1e6340127464ef0ac0e1de94f823f14e Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 16 Jul 2021 16:15:47 -0700 Subject: [PATCH 101/696] cxl/pci: Simplify register setup It is desirable to retain the mappings from the calling function. By simplifying this code, it will be much more straightforward to do that. Signed-off-by: Ben Widawsky Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20210716231548.174778-3-ben.widawsky@intel.com Signed-off-by: Dan Williams --- drivers/cxl/cxl.h | 1 - drivers/cxl/pci.c | 38 ++++++++++++-------------------------- drivers/cxl/pci.h | 1 + 3 files changed, 13 insertions(+), 27 deletions(-) diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index b6bda39a59e3..53927f9fa77e 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -140,7 +140,6 @@ struct cxl_device_reg_map { }; struct cxl_register_map { - struct list_head list; u64 block_offset; u8 reg_type; u8 barno; diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c index 90a1c895e442..47315bb2db10 100644 --- a/drivers/cxl/pci.c +++ b/drivers/cxl/pci.c @@ -1091,9 +1091,8 @@ static int cxl_mem_setup_regs(struct cxl_mem *cxlm) struct device *dev = &pdev->dev; u32 regloc_size, regblocks; void __iomem *base; - int regloc, i; - struct cxl_register_map *map, *n; - LIST_HEAD(register_maps); + int regloc, i, n_maps; + struct cxl_register_map *map, maps[CXL_REGLOC_RBI_TYPES]; int ret = 0; regloc = cxl_mem_dvsec(pdev, PCI_DVSEC_ID_CXL_REGLOC_DVSEC_ID); @@ -1112,7 +1111,7 @@ static int cxl_mem_setup_regs(struct cxl_mem *cxlm) regloc += PCI_DVSEC_ID_CXL_REGLOC_BLOCK1_OFFSET; regblocks = (regloc_size - PCI_DVSEC_ID_CXL_REGLOC_BLOCK1_OFFSET) / 8; - for (i = 0; i < regblocks; i++, regloc += 8) { + for (i = 0, n_maps = 0; i < regblocks; i++, regloc += 8) { u32 reg_lo, reg_hi; u8 reg_type; u64 offset; @@ -1131,20 +1130,11 @@ static int cxl_mem_setup_regs(struct cxl_mem *cxlm) if (reg_type > CXL_REGLOC_RBI_MEMDEV) continue; - map = kzalloc(sizeof(*map), GFP_KERNEL); - if (!map) { - ret = -ENOMEM; - goto free_maps; - } - - list_add(&map->list, ®ister_maps); - base = cxl_mem_map_regblock(cxlm, bar, offset); - if (!base) { - ret = -ENOMEM; - goto free_maps; - } + if (!base) + return -ENOMEM; + map = &maps[n_maps]; map->barno = bar; map->block_offset = offset; map->reg_type = reg_type; @@ -1155,21 +1145,17 @@ static int cxl_mem_setup_regs(struct cxl_mem *cxlm) cxl_mem_unmap_regblock(cxlm, base); if (ret) - goto free_maps; + return ret; + + n_maps++; } pci_release_mem_regions(pdev); - list_for_each_entry(map, ®ister_maps, list) { - ret = cxl_map_regs(cxlm, map); + for (i = 0; i < n_maps; i++) { + ret = cxl_map_regs(cxlm, &maps[i]); if (ret) - goto free_maps; - } - -free_maps: - list_for_each_entry_safe(map, n, ®ister_maps, list) { - list_del(&map->list); - kfree(map); + break; } return ret; diff --git a/drivers/cxl/pci.h b/drivers/cxl/pci.h index dad7a831f65f..8c1a58813816 100644 --- a/drivers/cxl/pci.h +++ b/drivers/cxl/pci.h @@ -25,6 +25,7 @@ #define CXL_REGLOC_RBI_COMPONENT 1 #define CXL_REGLOC_RBI_VIRT 2 #define CXL_REGLOC_RBI_MEMDEV 3 +#define CXL_REGLOC_RBI_TYPES CXL_REGLOC_RBI_MEMDEV + 1 #define CXL_REGLOC_ADDR_MASK GENMASK(31, 16) From 67db87dc8284070adb15b3c02c1c31d5cf51c5d6 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 30 Jul 2021 23:27:15 +0300 Subject: [PATCH 102/696] dmaengine: acpi: Avoid comparison GSI with Linux vIRQ Currently the CRST parsing relies on the fact that on most of x86 devices the IRQ mapping is 1:1 with Linux vIRQ. However, it may be not true for some. Fix this by converting GSI to Linux vIRQ before checking it. Fixes: ee8209fd026b ("dma: acpi-dma: parse CSRT to extract additional resources") Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210730202715.24375-1-andriy.shevchenko@linux.intel.com Signed-off-by: Vinod Koul --- drivers/dma/acpi-dma.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/dma/acpi-dma.c b/drivers/dma/acpi-dma.c index 235f1396f968..52768dc8ce12 100644 --- a/drivers/dma/acpi-dma.c +++ b/drivers/dma/acpi-dma.c @@ -70,10 +70,14 @@ static int acpi_dma_parse_resource_group(const struct acpi_csrt_group *grp, si = (const struct acpi_csrt_shared_info *)&grp[1]; - /* Match device by MMIO and IRQ */ + /* Match device by MMIO */ if (si->mmio_base_low != lower_32_bits(mem) || - si->mmio_base_high != upper_32_bits(mem) || - si->gsi_interrupt != irq) + si->mmio_base_high != upper_32_bits(mem)) + return 0; + + /* Match device by Linux vIRQ */ + ret = acpi_register_gsi(NULL, si->gsi_interrupt, si->interrupt_mode, si->interrupt_polarity); + if (ret != irq) return 0; dev_dbg(&adev->dev, "matches with %.4s%04X (rev %u)\n", From 15cb0321a55e12af6b8456e9ec66a11cb367a673 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 2 Aug 2021 20:55:32 +0300 Subject: [PATCH 103/696] dmaengine: acpi: Check for errors from acpi_register_gsi() separately While IRQ test agaist the returned variable in practice is a good enough there is still a room for theoretical mistake in case the vIRQ of the device contains the same error code that acpi_register_gsi() may return. Due to this, check for error code separately from matching the vIRQs. Besides that, append documentation to tell why acpi_gsi_to_irq() can't be used and we call acpi_register_gsi() instead. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210802175532.54311-1-andriy.shevchenko@linux.intel.com Signed-off-by: Vinod Koul --- drivers/dma/acpi-dma.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/dma/acpi-dma.c b/drivers/dma/acpi-dma.c index 52768dc8ce12..5906eae26e2a 100644 --- a/drivers/dma/acpi-dma.c +++ b/drivers/dma/acpi-dma.c @@ -75,8 +75,16 @@ static int acpi_dma_parse_resource_group(const struct acpi_csrt_group *grp, si->mmio_base_high != upper_32_bits(mem)) return 0; - /* Match device by Linux vIRQ */ + /* + * acpi_gsi_to_irq() can't be used because some platforms do not save + * registered IRQs in the MP table. Instead we just try to register + * the GSI, which is the core part of the above mentioned function. + */ ret = acpi_register_gsi(NULL, si->gsi_interrupt, si->interrupt_mode, si->interrupt_polarity); + if (ret < 0) + return 0; + + /* Match device by Linux vIRQ */ if (ret != irq) return 0; From 9fce3b3a0ab4cad407a27b5e36603c23f1b5b278 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Fri, 6 Aug 2021 08:36:43 -0700 Subject: [PATCH 104/696] dmaengine: idxd: remove interrupt flag for completion list spinlock The list lock is never acquired in interrupt context. Therefore there is no need to disable interrupts. Remove interrupt flags for lock operations. Reviewed-by: Dan Williams Signed-off-by: Dave Jiang Link: https://lore.kernel.org/r/162826417450.3454650.3733188117742416238.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul --- drivers/dma/idxd/irq.c | 12 +++++------- drivers/dma/idxd/submit.c | 5 ++--- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/dma/idxd/irq.c b/drivers/dma/idxd/irq.c index 11addb394793..d221c2e37460 100644 --- a/drivers/dma/idxd/irq.c +++ b/drivers/dma/idxd/irq.c @@ -176,7 +176,6 @@ static void irq_process_pending_llist(struct idxd_irq_entry *irq_entry) { struct idxd_desc *desc, *t; struct llist_node *head; - unsigned long flags; head = llist_del_all(&irq_entry->pending_llist); if (!head) @@ -197,17 +196,16 @@ static void irq_process_pending_llist(struct idxd_irq_entry *irq_entry) complete_desc(desc, IDXD_COMPLETE_NORMAL); } else { - spin_lock_irqsave(&irq_entry->list_lock, flags); + spin_lock(&irq_entry->list_lock); list_add_tail(&desc->list, &irq_entry->work_list); - spin_unlock_irqrestore(&irq_entry->list_lock, flags); + spin_unlock(&irq_entry->list_lock); } } } static void irq_process_work_list(struct idxd_irq_entry *irq_entry) { - unsigned long flags; LIST_HEAD(flist); struct idxd_desc *desc, *n; @@ -215,9 +213,9 @@ static void irq_process_work_list(struct idxd_irq_entry *irq_entry) * This lock protects list corruption from access of list outside of the irq handler * thread. */ - spin_lock_irqsave(&irq_entry->list_lock, flags); + spin_lock(&irq_entry->list_lock); if (list_empty(&irq_entry->work_list)) { - spin_unlock_irqrestore(&irq_entry->list_lock, flags); + spin_unlock(&irq_entry->list_lock); return; } @@ -228,7 +226,7 @@ static void irq_process_work_list(struct idxd_irq_entry *irq_entry) } } - spin_unlock_irqrestore(&irq_entry->list_lock, flags); + spin_unlock(&irq_entry->list_lock); list_for_each_entry(desc, &flist, list) { /* diff --git a/drivers/dma/idxd/submit.c b/drivers/dma/idxd/submit.c index 92ae9a157cc9..4b514c63af15 100644 --- a/drivers/dma/idxd/submit.c +++ b/drivers/dma/idxd/submit.c @@ -106,14 +106,13 @@ static void llist_abort_desc(struct idxd_wq *wq, struct idxd_irq_entry *ie, { struct idxd_desc *d, *t, *found = NULL; struct llist_node *head; - unsigned long flags; desc->completion->status = IDXD_COMP_DESC_ABORT; /* * Grab the list lock so it will block the irq thread handler. This allows the * abort code to locate the descriptor need to be aborted. */ - spin_lock_irqsave(&ie->list_lock, flags); + spin_lock(&ie->list_lock); head = llist_del_all(&ie->pending_llist); if (head) { llist_for_each_entry_safe(d, t, head, llnode) { @@ -127,7 +126,7 @@ static void llist_abort_desc(struct idxd_wq *wq, struct idxd_irq_entry *ie, if (!found) found = list_abort_desc(wq, ie, desc); - spin_unlock_irqrestore(&ie->list_lock, flags); + spin_unlock(&ie->list_lock); if (found) complete_desc(found, IDXD_COMPLETE_ABORT); From 0b9159d0ff21bc281dbb9ede06ad566330ac0943 Mon Sep 17 00:00:00 2001 From: Ira Weiny Date: Thu, 17 Jun 2021 15:16:18 -0700 Subject: [PATCH 105/696] cxl/pci: Store memory capacity values The Identify Memory Device command returns information about the volatile only and persistent only memory capacities. Store those values in the cxl_mem structure for later use. While at it, reuse those calculations to calculate the ram and pmem ranges. Signed-off-by: Ira Weiny Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20210617221620.1904031-2-ira.weiny@intel.com Signed-off-by: Dan Williams --- drivers/cxl/cxlmem.h | 4 ++++ drivers/cxl/pci.c | 36 +++++++++++++++++++++++++++++++++--- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h index 25345ece25f8..22344fda8ca5 100644 --- a/drivers/cxl/cxlmem.h +++ b/drivers/cxl/cxlmem.h @@ -95,5 +95,9 @@ struct cxl_mem { struct range pmem_range; struct range ram_range; + u64 total_bytes; + u64 volatile_only_bytes; + u64 persistent_only_bytes; + u64 partition_align_bytes; }; #endif /* __CXL_MEM_H__ */ diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c index 47315bb2db10..cf4f593f426e 100644 --- a/drivers/cxl/pci.c +++ b/drivers/cxl/pci.c @@ -64,6 +64,15 @@ enum opcode { CXL_MBOX_OP_MAX = 0x10000 }; +/* + * CXL 2.0 - Memory capacity multiplier + * See Section 8.2.9.5 + * + * Volatile, Persistent, and Partition capacities are specified to be in + * multiples of 256MB - define a multiplier to convert to/from bytes. + */ +#define CXL_CAPACITY_MULTIPLIER SZ_256M + /** * struct mbox_cmd - A command to be submitted to hardware. * @opcode: (input) The command set and command submitted to hardware. @@ -1350,16 +1359,37 @@ static int cxl_mem_identify(struct cxl_mem *cxlm) if (rc < 0) return rc; + cxlm->total_bytes = le64_to_cpu(id.total_capacity); + cxlm->total_bytes *= CXL_CAPACITY_MULTIPLIER; + + cxlm->volatile_only_bytes = le64_to_cpu(id.volatile_capacity); + cxlm->volatile_only_bytes *= CXL_CAPACITY_MULTIPLIER; + + cxlm->persistent_only_bytes = le64_to_cpu(id.persistent_capacity); + cxlm->persistent_only_bytes *= CXL_CAPACITY_MULTIPLIER; + + cxlm->partition_align_bytes = le64_to_cpu(id.partition_align); + cxlm->partition_align_bytes *= CXL_CAPACITY_MULTIPLIER; + + dev_dbg(&cxlm->pdev->dev, "Identify Memory Device\n" + " total_bytes = %#llx\n" + " volatile_only_bytes = %#llx\n" + " persistent_only_bytes = %#llx\n" + " partition_align_bytes = %#llx\n", + cxlm->total_bytes, + cxlm->volatile_only_bytes, + cxlm->persistent_only_bytes, + cxlm->partition_align_bytes); + /* * TODO: enumerate DPA map, as 'ram' and 'pmem' do not alias. * For now, only the capacity is exported in sysfs */ cxlm->ram_range.start = 0; - cxlm->ram_range.end = le64_to_cpu(id.volatile_capacity) * SZ_256M - 1; + cxlm->ram_range.end = cxlm->volatile_only_bytes - 1; cxlm->pmem_range.start = 0; - cxlm->pmem_range.end = - le64_to_cpu(id.persistent_capacity) * SZ_256M - 1; + cxlm->pmem_range.end = cxlm->persistent_only_bytes - 1; cxlm->lsa_size = le32_to_cpu(id.lsa_size); memcpy(cxlm->firmware_version, id.fw_revision, sizeof(id.fw_revision)); From e71ec0bc06038cdfa18cbd23f5cea71fe4785d35 Mon Sep 17 00:00:00 2001 From: Daniel Thompson Date: Fri, 30 Jul 2021 10:58:56 +0100 Subject: [PATCH 106/696] scripts: coccinelle: allow list_entry_is_head() to use pos Currently use_after_iter.cocci generates false positives for code of the following form: ~~~ list_for_each_entry(d, &ddata->irq_list, node) { if (irq == d->irq) break; } if (list_entry_is_head(d, &ddata->irq_list, node)) return IRQ_NONE; ~~~ [This specific example comes from drivers/power/supply/cpcap-battery.c] Most list macros use list_entry_is_head() as loop exit condition meaning it is not unsafe to reuse pos (a.k.a. d) in the code above. Let's avoid reporting these cases. Signed-off-by: Daniel Thompson Signed-off-by: Julia Lawall --- scripts/coccinelle/iterators/use_after_iter.cocci | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/coccinelle/iterators/use_after_iter.cocci b/scripts/coccinelle/iterators/use_after_iter.cocci index 9be48b520879..676edd562eef 100644 --- a/scripts/coccinelle/iterators/use_after_iter.cocci +++ b/scripts/coccinelle/iterators/use_after_iter.cocci @@ -123,6 +123,8 @@ hlist_for_each_entry_safe(c,...) S | list_remove_head(x,c,...) | +list_entry_is_head(c,...) +| sizeof(<+...c...+>) | &c->member From 1d1bb12a8b1805ddeef9793ebeb920179fb0fa38 Mon Sep 17 00:00:00 2001 From: Cassio Neri Date: Thu, 24 Jun 2021 21:13:43 +0100 Subject: [PATCH 107/696] rtc: Improve performance of rtc_time64_to_tm(). Add tests. The current implementation of rtc_time64_to_tm() contains unnecessary loops, branches and look-up tables. The new one uses an arithmetic-based algorithm appeared in [1] and is approximately 4.3 times faster (YMMV). The drawback is that the new code isn't intuitive and contains many 'magic numbers' (not unusual for this type of algorithm). However, [1] justifies all those numbers and, given this function's history, the code is unlikely to need much maintenance, if any at all. Add a KUnit test case that checks every day in a 160,000 years interval starting on 1970-01-01 against the expected result. Add a new config RTC_LIB_KUNIT_TEST symbol to give the option to run this test suite. [1] Neri, Schneider, "Euclidean Affine Functions and Applications to Calendar Algorithms". https://arxiv.org/abs/2102.06959 Signed-off-by: Cassio Neri Reported-by: kernel test robot Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20210624201343.85441-1-cassio.neri@gmail.com --- drivers/rtc/Kconfig | 10 ++++ drivers/rtc/Makefile | 1 + drivers/rtc/lib.c | 103 +++++++++++++++++++++++++++++++---------- drivers/rtc/lib_test.c | 79 +++++++++++++++++++++++++++++++ 4 files changed, 168 insertions(+), 25 deletions(-) create mode 100644 drivers/rtc/lib_test.c diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 12153d5801ce..b3cf3a274c05 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -10,6 +10,16 @@ config RTC_MC146818_LIB bool select RTC_LIB +config RTC_LIB_KUNIT_TEST + tristate "KUnit test for RTC lib functions" if !KUNIT_ALL_TESTS + depends on KUNIT + default KUNIT_ALL_TESTS + select RTC_LIB + help + Enable this option to test RTC library functions. + + If unsure, say N. + menuconfig RTC_CLASS bool "Real Time Clock" default n diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 2dd0dd956b0e..763d3628c603 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -178,3 +178,4 @@ obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o obj-$(CONFIG_RTC_DRV_XGENE) += rtc-xgene.o obj-$(CONFIG_RTC_DRV_ZYNQMP) += rtc-zynqmp.o +obj-$(CONFIG_RTC_LIB_KUNIT_TEST) += lib_test.o diff --git a/drivers/rtc/lib.c b/drivers/rtc/lib.c index 23284580df97..fe361652727a 100644 --- a/drivers/rtc/lib.c +++ b/drivers/rtc/lib.c @@ -6,6 +6,8 @@ * Author: Alessandro Zummo * * based on arch/arm/common/rtctime.c and other bits + * + * Author: Cassio Neri (rtc_time64_to_tm) */ #include @@ -22,8 +24,6 @@ static const unsigned short rtc_ydays[2][13] = { { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } }; -#define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400) - /* * The number of days in the month. */ @@ -42,42 +42,95 @@ int rtc_year_days(unsigned int day, unsigned int month, unsigned int year) } EXPORT_SYMBOL(rtc_year_days); -/* - * rtc_time64_to_tm - Converts time64_t to rtc_time. - * Convert seconds since 01-01-1970 00:00:00 to Gregorian date. +/** + * rtc_time64_to_tm - converts time64_t to rtc_time. + * + * @time: The number of seconds since 01-01-1970 00:00:00. + * (Must be positive.) + * @tm: Pointer to the struct rtc_time. */ void rtc_time64_to_tm(time64_t time, struct rtc_time *tm) { - unsigned int month, year, secs; + unsigned int secs; int days; + u64 u64tmp; + u32 u32tmp, udays, century, day_of_century, year_of_century, year, + day_of_year, month, day; + bool is_Jan_or_Feb, is_leap_year; + /* time must be positive */ days = div_s64_rem(time, 86400, &secs); /* day of the week, 1970-01-01 was a Thursday */ tm->tm_wday = (days + 4) % 7; - year = 1970 + days / 365; - days -= (year - 1970) * 365 - + LEAPS_THRU_END_OF(year - 1) - - LEAPS_THRU_END_OF(1970 - 1); - while (days < 0) { - year -= 1; - days += 365 + is_leap_year(year); - } - tm->tm_year = year - 1900; - tm->tm_yday = days + 1; + /* + * The following algorithm is, basically, Proposition 6.3 of Neri + * and Schneider [1]. In a few words: it works on the computational + * (fictitious) calendar where the year starts in March, month = 2 + * (*), and finishes in February, month = 13. This calendar is + * mathematically convenient because the day of the year does not + * depend on whether the year is leap or not. For instance: + * + * March 1st 0-th day of the year; + * ... + * April 1st 31-st day of the year; + * ... + * January 1st 306-th day of the year; (Important!) + * ... + * February 28th 364-th day of the year; + * February 29th 365-th day of the year (if it exists). + * + * After having worked out the date in the computational calendar + * (using just arithmetics) it's easy to convert it to the + * corresponding date in the Gregorian calendar. + * + * [1] "Euclidean Affine Functions and Applications to Calendar + * Algorithms". https://arxiv.org/abs/2102.06959 + * + * (*) The numbering of months follows rtc_time more closely and + * thus, is slightly different from [1]. + */ - for (month = 0; month < 11; month++) { - int newdays; + udays = ((u32) days) + 719468; - newdays = days - rtc_month_days(month, year); - if (newdays < 0) - break; - days = newdays; - } - tm->tm_mon = month; - tm->tm_mday = days + 1; + u32tmp = 4 * udays + 3; + century = u32tmp / 146097; + day_of_century = u32tmp % 146097 / 4; + + u32tmp = 4 * day_of_century + 3; + u64tmp = 2939745ULL * u32tmp; + year_of_century = upper_32_bits(u64tmp); + day_of_year = lower_32_bits(u64tmp) / 2939745 / 4; + + year = 100 * century + year_of_century; + is_leap_year = year_of_century != 0 ? + year_of_century % 4 == 0 : century % 4 == 0; + + u32tmp = 2141 * day_of_year + 132377; + month = u32tmp >> 16; + day = ((u16) u32tmp) / 2141; + + /* + * Recall that January 01 is the 306-th day of the year in the + * computational (not Gregorian) calendar. + */ + is_Jan_or_Feb = day_of_year >= 306; + + /* Converts to the Gregorian calendar. */ + year = year + is_Jan_or_Feb; + month = is_Jan_or_Feb ? month - 12 : month; + day = day + 1; + + day_of_year = is_Jan_or_Feb ? + day_of_year - 306 : day_of_year + 31 + 28 + is_leap_year; + + /* Converts to rtc_time's format. */ + tm->tm_year = (int) (year - 1900); + tm->tm_mon = (int) month; + tm->tm_mday = (int) day; + tm->tm_yday = (int) day_of_year + 1; tm->tm_hour = secs / 3600; secs -= tm->tm_hour * 3600; diff --git a/drivers/rtc/lib_test.c b/drivers/rtc/lib_test.c new file mode 100644 index 000000000000..2124b67a2f43 --- /dev/null +++ b/drivers/rtc/lib_test.c @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: LGPL-2.1+ + +#include +#include + +/* + * Advance a date by one day. + */ +static void advance_date(int *year, int *month, int *mday, int *yday) +{ + if (*mday != rtc_month_days(*month - 1, *year)) { + ++*mday; + ++*yday; + return; + } + + *mday = 1; + if (*month != 12) { + ++*month; + ++*yday; + return; + } + + *month = 1; + *yday = 1; + ++*year; +} + +/* + * Checks every day in a 160000 years interval starting on 1970-01-01 + * against the expected result. + */ +static void rtc_time64_to_tm_test_date_range(struct kunit *test) +{ + /* + * 160000 years = (160000 / 400) * 400 years + * = (160000 / 400) * 146097 days + * = (160000 / 400) * 146097 * 86400 seconds + */ + time64_t total_secs = ((time64_t) 160000) / 400 * 146097 * 86400; + + int year = 1970; + int month = 1; + int mday = 1; + int yday = 1; + + struct rtc_time result; + time64_t secs; + s64 days; + + for (secs = 0; secs <= total_secs; secs += 86400) { + + rtc_time64_to_tm(secs, &result); + + days = div_s64(secs, 86400); + + #define FAIL_MSG "%d/%02d/%02d (%2d) : %ld", \ + year, month, mday, yday, days + + KUNIT_ASSERT_EQ_MSG(test, year - 1900, result.tm_year, FAIL_MSG); + KUNIT_ASSERT_EQ_MSG(test, month - 1, result.tm_mon, FAIL_MSG); + KUNIT_ASSERT_EQ_MSG(test, mday, result.tm_mday, FAIL_MSG); + KUNIT_ASSERT_EQ_MSG(test, yday, result.tm_yday, FAIL_MSG); + + advance_date(&year, &month, &mday, &yday); + } +} + +static struct kunit_case rtc_lib_test_cases[] = { + KUNIT_CASE(rtc_time64_to_tm_test_date_range), + {} +}; + +static struct kunit_suite rtc_lib_test_suite = { + .name = "rtc_lib_test_cases", + .test_cases = rtc_lib_test_cases, +}; + +kunit_test_suite(rtc_lib_test_suite); From c755238d2ce0960ced9ffccc2ce14de2cd01b647 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 11 Jul 2021 23:31:43 +0100 Subject: [PATCH 108/696] ARM: 9099/1: crypto: rename 'mod_init' & 'mod_exit' functions to be module-specific Rename module_init & module_exit functions that are named "mod_init" and "mod_exit" so that they are unique in both the System.map file and in initcall_debug output instead of showing up as almost anonymous "mod_init". This is helpful for debugging and in determining how long certain module_init calls take to execute. Signed-off-by: Randy Dunlap Cc: Jason A. Donenfeld Cc: linux-arm-kernel@lists.infradead.org Cc: patches@armlinux.org.uk Signed-off-by: Russell King (Oracle) --- arch/arm/crypto/curve25519-glue.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/crypto/curve25519-glue.c b/arch/arm/crypto/curve25519-glue.c index 31eb75b6002f..9bdafd57888c 100644 --- a/arch/arm/crypto/curve25519-glue.c +++ b/arch/arm/crypto/curve25519-glue.c @@ -112,7 +112,7 @@ static struct kpp_alg curve25519_alg = { .max_size = curve25519_max_size, }; -static int __init mod_init(void) +static int __init arm_curve25519_init(void) { if (elf_hwcap & HWCAP_NEON) { static_branch_enable(&have_neon); @@ -122,14 +122,14 @@ static int __init mod_init(void) return 0; } -static void __exit mod_exit(void) +static void __exit arm_curve25519_exit(void) { if (IS_REACHABLE(CONFIG_CRYPTO_KPP) && elf_hwcap & HWCAP_NEON) crypto_unregister_kpp(&curve25519_alg); } -module_init(mod_init); -module_exit(mod_exit); +module_init(arm_curve25519_init); +module_exit(arm_curve25519_exit); MODULE_ALIAS_CRYPTO("curve25519"); MODULE_ALIAS_CRYPTO("curve25519-neon"); From b08cae33b88e5f80b419a504b9b8e5530dfc9565 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 17 Jul 2021 16:14:40 +0100 Subject: [PATCH 109/696] ARM: 9100/1: MAINTAINERS: mark all linux-arm-kernel@infradead list as moderated Consistenly mark all entries of "linux-arm-kernel@lists.infradead.org" as moderated for non-subscribers. Signed-off-by: Randy Dunlap Cc: linux-arm-kernel@lists.infradead.org Cc: patches@armlinux.org.uk Signed-off-by: Russell King (Oracle) --- MAINTAINERS | 56 ++++++++++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index a61f4f3b78a9..0d0fc0fa3b7c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2306,14 +2306,14 @@ N: oxnas ARM/PALM TREO SUPPORT M: Tomas Cech -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained W: http://hackndev.com F: arch/arm/mach-pxa/palmtreo.* ARM/PALMTX,PALMT5,PALMLD,PALMTE2,PALMTC SUPPORT M: Marek Vasut -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained W: http://hackndev.com F: arch/arm/mach-pxa/include/mach/palmld.h @@ -2327,7 +2327,7 @@ F: arch/arm/mach-pxa/palmtx.c ARM/PALMZ72 SUPPORT M: Sergey Lapin -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained W: http://hackndev.com F: arch/arm/mach-pxa/palmz72.* @@ -2497,7 +2497,7 @@ N: s5pv210 ARM/SAMSUNG S5P SERIES 2D GRAPHICS ACCELERATION (G2D) SUPPORT M: Andrzej Hajda -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-media@vger.kernel.org S: Maintained F: drivers/media/platform/s5p-g2d/ @@ -2514,14 +2514,14 @@ ARM/SAMSUNG S5P SERIES JPEG CODEC SUPPORT M: Andrzej Pietrasiewicz M: Jacek Anaszewski M: Sylwester Nawrocki -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-media@vger.kernel.org S: Maintained F: drivers/media/platform/s5p-jpeg/ ARM/SAMSUNG S5P SERIES Multi Format Codec (MFC) SUPPORT M: Andrzej Hajda -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-media@vger.kernel.org S: Maintained F: drivers/media/platform/s5p-mfc/ @@ -3539,7 +3539,7 @@ BROADCOM BCM5301X ARM ARCHITECTURE M: Hauke Mehrtens M: Rafał Miłecki M: bcm-kernel-feedback-list@broadcom.com -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: arch/arm/boot/dts/bcm470* F: arch/arm/boot/dts/bcm5301* @@ -3549,7 +3549,7 @@ F: arch/arm/mach-bcm/bcm_5301x.c BROADCOM BCM53573 ARM ARCHITECTURE M: Rafał Miłecki L: bcm-kernel-feedback-list@broadcom.com -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: arch/arm/boot/dts/bcm47189* F: arch/arm/boot/dts/bcm53573* @@ -4833,7 +4833,7 @@ CPUIDLE DRIVER - ARM BIG LITTLE M: Lorenzo Pieralisi M: Daniel Lezcano L: linux-pm@vger.kernel.org -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git F: drivers/cpuidle/cpuidle-big_little.c @@ -4853,14 +4853,14 @@ CPUIDLE DRIVER - ARM PSCI M: Lorenzo Pieralisi M: Sudeep Holla L: linux-pm@vger.kernel.org -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Supported F: drivers/cpuidle/cpuidle-psci.c CPUIDLE DRIVER - ARM PSCI PM DOMAIN M: Ulf Hansson L: linux-pm@vger.kernel.org -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Supported F: drivers/cpuidle/cpuidle-psci.h F: drivers/cpuidle/cpuidle-psci-domain.c @@ -7195,7 +7195,7 @@ F: tools/firewire/ FIRMWARE FRAMEWORK FOR ARMV8-A M: Sudeep Holla -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: drivers/firmware/arm_ffa/ F: include/linux/arm_ffa.h @@ -7374,7 +7374,7 @@ F: include/linux/platform_data/video-imxfb.h FREESCALE IMX DDR PMU DRIVER M: Frank Li -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: Documentation/admin-guide/perf/imx-ddr.rst F: Documentation/devicetree/bindings/perf/fsl-imx-ddr.yaml @@ -7466,7 +7466,7 @@ F: drivers/tty/serial/ucc_uart.c FREESCALE SOC DRIVERS M: Li Yang L: linuxppc-dev@lists.ozlabs.org -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: Documentation/devicetree/bindings/misc/fsl,dpaa2-console.yaml F: Documentation/devicetree/bindings/soc/fsl/ @@ -11091,7 +11091,7 @@ F: drivers/net/wireless/marvell/libertas/ MARVELL MACCHIATOBIN SUPPORT M: Russell King -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: arch/arm64/boot/dts/marvell/armada-8040-mcbin.dts @@ -14134,7 +14134,7 @@ F: drivers/pci/controller/pcie-altera.c PCI DRIVER FOR APPLIEDMICRO XGENE M: Toan Le L: linux-pci@vger.kernel.org -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: Documentation/devicetree/bindings/pci/xgene-pci.txt F: drivers/pci/controller/pci-xgene.c @@ -14142,7 +14142,7 @@ F: drivers/pci/controller/pci-xgene.c PCI DRIVER FOR ARM VERSATILE PLATFORM M: Rob Herring L: linux-pci@vger.kernel.org -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: Documentation/devicetree/bindings/pci/versatile.yaml F: drivers/pci/controller/pci-versatile.c @@ -14150,7 +14150,7 @@ F: drivers/pci/controller/pci-versatile.c PCI DRIVER FOR ARMADA 8K M: Thomas Petazzoni L: linux-pci@vger.kernel.org -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: Documentation/devicetree/bindings/pci/pci-armada8k.txt F: drivers/pci/controller/dwc/pcie-armada8k.c @@ -14168,7 +14168,7 @@ M: Mingkai Hu M: Roy Zang L: linuxppc-dev@lists.ozlabs.org L: linux-pci@vger.kernel.org -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: drivers/pci/controller/dwc/*layerscape* @@ -14248,7 +14248,7 @@ F: drivers/pci/controller/pci-tegra.c PCI DRIVER FOR NXP LAYERSCAPE GEN4 CONTROLLER M: Hou Zhiqiang L: linux-pci@vger.kernel.org -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: Documentation/devicetree/bindings/pci/layerscape-pcie-gen4.txt F: drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c @@ -14282,7 +14282,7 @@ PCI DRIVER FOR TI DRA7XX/J721E M: Kishon Vijay Abraham I L: linux-omap@vger.kernel.org L: linux-pci@vger.kernel.org -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Supported F: Documentation/devicetree/bindings/pci/ti-pci.txt F: drivers/pci/controller/cadence/pci-j721e.c @@ -14338,7 +14338,7 @@ F: drivers/pci/controller/pcie-altera-msi.c PCI MSI DRIVER FOR APPLIEDMICRO XGENE M: Toan Le L: linux-pci@vger.kernel.org -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: Documentation/devicetree/bindings/pci/xgene-pci-msi.txt F: drivers/pci/controller/pci-xgene-msi.c @@ -14836,7 +14836,7 @@ F: include/linux/dtpm.h POWER STATE COORDINATION INTERFACE (PSCI) M: Mark Rutland M: Lorenzo Pieralisi -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: drivers/firmware/psci/ F: include/linux/psci.h @@ -15356,7 +15356,7 @@ F: arch/hexagon/ QUALCOMM HIDMA DRIVER M: Sinan Kaya -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-arm-msm@vger.kernel.org L: dmaengine@vger.kernel.org S: Supported @@ -17044,7 +17044,7 @@ SECURE MONITOR CALL(SMC) CALLING CONVENTION (SMCCC) M: Mark Rutland M: Lorenzo Pieralisi M: Sudeep Holla -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: drivers/firmware/smccc/ F: include/linux/arm-smccc.h @@ -17161,7 +17161,7 @@ F: drivers/media/pci/solo6x10/ SOFTWARE DELEGATED EXCEPTION INTERFACE (SDEI) M: James Morse -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: Documentation/devicetree/bindings/arm/firmware/sdei.txt F: drivers/firmware/arm_sdei.c @@ -17929,7 +17929,7 @@ F: drivers/mfd/syscon.c SYSTEM CONTROL & POWER/MANAGEMENT INTERFACE (SCPI/SCMI) Message Protocol drivers M: Sudeep Holla R: Cristian Marussi -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: Documentation/devicetree/bindings/firmware/arm,sc[mp]i.yaml F: drivers/clk/clk-sc[mp]i.c @@ -18301,7 +18301,7 @@ TEXAS INSTRUMENTS' SYSTEM CONTROL INTERFACE (TISCI) PROTOCOL DRIVER M: Nishanth Menon M: Tero Kristo M: Santosh Shilimkar -L: linux-arm-kernel@lists.infradead.org +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: Documentation/devicetree/bindings/arm/keystone/ti,k3-sci-common.yaml F: Documentation/devicetree/bindings/arm/keystone/ti,sci.txt From d7bcc5e22967c96685d03dbbd167e1a1ddf9b910 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 29 Jul 2021 15:03:51 +0100 Subject: [PATCH 110/696] ARM: 9102/1: move theinstall rules to arch/arm/Makefile Currently, the (z/u)install targets in arch/arm/Makefile descend into arch/arm/boot/Makefile to invoke the shell script, but there is no good reason to do so. arch/arm/Makefile can run the shell script directly. Signed-off-by: Masahiro Yamada Signed-off-by: Russell King (Oracle) --- arch/arm/Makefile | 3 ++- arch/arm/boot/Makefile | 14 +------------- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 173da685a52e..847c31e7c368 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -308,7 +308,8 @@ $(BOOT_TARGETS): vmlinux @$(kecho) ' Kernel: $(boot)/$@ is ready' $(INSTALL_TARGETS): - $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $@ + $(CONFIG_SHELL) $(srctree)/$(boot)/install.sh "$(KERNELRELEASE)" \ + $(boot)/$(patsubst %install,%Image,$@) System.map "$(INSTALL_PATH)" PHONY += vdso_install vdso_install: diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile index 0b3cd7a33a26..54a09f9464fb 100644 --- a/arch/arm/boot/Makefile +++ b/arch/arm/boot/Makefile @@ -96,23 +96,11 @@ $(obj)/bootp/bootp: $(obj)/zImage initrd FORCE $(obj)/bootpImage: $(obj)/bootp/bootp FORCE $(call if_changed,objcopy) -PHONY += initrd install zinstall uinstall +PHONY += initrd initrd: @test "$(INITRD_PHYS)" != "" || \ (echo This machine does not support INITRD; exit -1) @test "$(INITRD)" != "" || \ (echo You must specify INITRD; exit -1) -install: - $(CONFIG_SHELL) $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" \ - $(obj)/Image System.map "$(INSTALL_PATH)" - -zinstall: - $(CONFIG_SHELL) $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" \ - $(obj)/zImage System.map "$(INSTALL_PATH)" - -uinstall: - $(CONFIG_SHELL) $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" \ - $(obj)/uImage System.map "$(INSTALL_PATH)" - subdir- := bootp compressed dts From 6fec92d9b2bfd2fb1a2a4295dc859d9bab16c8fc Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 30 Jul 2021 10:43:02 +0100 Subject: [PATCH 111/696] ARM: 9103/1: Drop ARCH_NR_GPIOS definition The conditional by the generic header is the same, hence drop unnecessary duplication. Link: https://lore.kernel.org/r/20210510114107.43006-1-andriy.shevchenko@linux.intel.com Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Signed-off-by: Linus Walleij Signed-off-by: Russell King (Oracle) --- arch/arm/include/asm/gpio.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/arm/include/asm/gpio.h b/arch/arm/include/asm/gpio.h index c50e383358c4..f3bb8a2bf788 100644 --- a/arch/arm/include/asm/gpio.h +++ b/arch/arm/include/asm/gpio.h @@ -2,10 +2,6 @@ #ifndef _ARCH_ARM_GPIO_H #define _ARCH_ARM_GPIO_H -#if CONFIG_ARCH_NR_GPIO > 0 -#define ARCH_NR_GPIOS CONFIG_ARCH_NR_GPIO -#endif - /* Note: this may rely upon the value of ARCH_NR_GPIOS set in mach/gpio.h */ #include From b30d0289de72c62516df03fdad8d53f552c69839 Mon Sep 17 00:00:00 2001 From: David Heidelberg Date: Mon, 9 Aug 2021 19:07:30 +0100 Subject: [PATCH 112/696] ARM: 9105/1: atags_to_fdt: don't warn about stack size The merge_fdt_bootargs() function by definition consumes more than 1024 bytes of stack because it has a 1024 byte command line on the stack, meaning that we always get a warning when building this file: arch/arm/boot/compressed/atags_to_fdt.c: In function 'merge_fdt_bootargs': arch/arm/boot/compressed/atags_to_fdt.c:98:1: warning: the frame size of 1032 bytes is larger than 1024 bytes [-Wframe-larger-than=] However, as this is the decompressor and we know that it has a very shallow call chain, and we do not actually risk overflowing the kernel stack at runtime here. This just shuts up the warning by disabling the warning flag for this file. Tested on Nexus 7 2012 builds. Acked-by: Nicolas Pitre Signed-off-by: David Heidelberg Signed-off-by: Arnd Bergmann Cc: Signed-off-by: Russell King (Oracle) --- arch/arm/boot/compressed/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile index 9d91ae1091b0..91265e7ff672 100644 --- a/arch/arm/boot/compressed/Makefile +++ b/arch/arm/boot/compressed/Makefile @@ -85,6 +85,8 @@ compress-$(CONFIG_KERNEL_LZ4) = lz4 libfdt_objs := fdt_rw.o fdt_ro.o fdt_wip.o fdt.o ifeq ($(CONFIG_ARM_ATAG_DTB_COMPAT),y) +CFLAGS_REMOVE_atags_to_fdt.o += -Wframe-larger-than=${CONFIG_FRAME_WARN} +CFLAGS_atags_to_fdt.o += -Wframe-larger-than=1280 OBJS += $(libfdt_objs) atags_to_fdt.o endif ifeq ($(CONFIG_USE_OF),y) From f847502ad8e3299e7ad256aa0bd7eaf184646117 Mon Sep 17 00:00:00 2001 From: Ira Weiny Date: Tue, 10 Aug 2021 11:57:59 -0700 Subject: [PATCH 113/696] cxl/mem: Account for partitionable space in ram/pmem ranges Memory devices may specify volatile only, persistent only, and partitionable space which when added together result in a total capacity. If Identify Memory Device.Partition Alignment != 0 the device supports partitionable space. This partitionable space can be split between volatile and persistent space. The total volatile and persistent sizes are reported in Get Partition Info. ie active volatile memory = volatile only + partitionable volatile active persistent memory = persistent only + partitionable persistent Define cxl_mem_get_partition(), check for partitionable support, and use cxl_mem_get_partition() if applicable. Reviewed-by: Jonathan Cameron Signed-off-by: Ira Weiny Reported-by: kernel test robot Signed-off-by: Dan Williams --- drivers/cxl/cxlmem.h | 5 +++ drivers/cxl/pci.c | 96 +++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 96 insertions(+), 5 deletions(-) diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h index 22344fda8ca5..6c0b1e2ea97c 100644 --- a/drivers/cxl/cxlmem.h +++ b/drivers/cxl/cxlmem.h @@ -99,5 +99,10 @@ struct cxl_mem { u64 volatile_only_bytes; u64 persistent_only_bytes; u64 partition_align_bytes; + + u64 active_volatile_bytes; + u64 active_persistent_bytes; + u64 next_volatile_bytes; + u64 next_persistent_bytes; }; #endif /* __CXL_MEM_H__ */ diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c index cf4f593f426e..3f5db8960098 100644 --- a/drivers/cxl/pci.c +++ b/drivers/cxl/pci.c @@ -1263,6 +1263,53 @@ static struct cxl_mbox_get_supported_logs *cxl_get_gsl(struct cxl_mem *cxlm) return ret; } +/** + * cxl_mem_get_partition_info - Get partition info + * @cxlm: The device to act on + * @active_volatile_bytes: returned active volatile capacity + * @active_persistent_bytes: returned active persistent capacity + * @next_volatile_bytes: return next volatile capacity + * @next_persistent_bytes: return next persistent capacity + * + * Retrieve the current partition info for the device specified. If not 0, the + * 'next' values are pending and take affect on next cold reset. + * + * Return: 0 if no error: or the result of the mailbox command. + * + * See CXL @8.2.9.5.2.1 Get Partition Info + */ +static int cxl_mem_get_partition_info(struct cxl_mem *cxlm, + u64 *active_volatile_bytes, + u64 *active_persistent_bytes, + u64 *next_volatile_bytes, + u64 *next_persistent_bytes) +{ + struct cxl_mbox_get_partition_info { + __le64 active_volatile_cap; + __le64 active_persistent_cap; + __le64 next_volatile_cap; + __le64 next_persistent_cap; + } __packed pi; + int rc; + + rc = cxl_mem_mbox_send_cmd(cxlm, CXL_MBOX_OP_GET_PARTITION_INFO, + NULL, 0, &pi, sizeof(pi)); + if (rc) + return rc; + + *active_volatile_bytes = le64_to_cpu(pi.active_volatile_cap); + *active_persistent_bytes = le64_to_cpu(pi.active_persistent_cap); + *next_volatile_bytes = le64_to_cpu(pi.next_volatile_cap); + *next_persistent_bytes = le64_to_cpu(pi.next_volatile_cap); + + *active_volatile_bytes *= CXL_CAPACITY_MULTIPLIER; + *active_persistent_bytes *= CXL_CAPACITY_MULTIPLIER; + *next_volatile_bytes *= CXL_CAPACITY_MULTIPLIER; + *next_persistent_bytes *= CXL_CAPACITY_MULTIPLIER; + + return 0; +} + /** * cxl_mem_enumerate_cmds() - Enumerate commands for a device. * @cxlm: The device. @@ -1381,18 +1428,53 @@ static int cxl_mem_identify(struct cxl_mem *cxlm) cxlm->persistent_only_bytes, cxlm->partition_align_bytes); + cxlm->lsa_size = le32_to_cpu(id.lsa_size); + memcpy(cxlm->firmware_version, id.fw_revision, sizeof(id.fw_revision)); + + return 0; +} + +static int cxl_mem_create_range_info(struct cxl_mem *cxlm) +{ + int rc; + + if (cxlm->partition_align_bytes == 0) { + cxlm->ram_range.start = 0; + cxlm->ram_range.end = cxlm->volatile_only_bytes - 1; + cxlm->pmem_range.start = 0; + cxlm->pmem_range.end = cxlm->persistent_only_bytes - 1; + return 0; + } + + rc = cxl_mem_get_partition_info(cxlm, + &cxlm->active_volatile_bytes, + &cxlm->active_persistent_bytes, + &cxlm->next_volatile_bytes, + &cxlm->next_persistent_bytes); + if (rc < 0) { + dev_err(&cxlm->pdev->dev, "Failed to query partition information\n"); + return rc; + } + + dev_dbg(&cxlm->pdev->dev, "Get Partition Info\n" + " active_volatile_bytes = %#llx\n" + " active_persistent_bytes = %#llx\n" + " next_volatile_bytes = %#llx\n" + " next_persistent_bytes = %#llx\n", + cxlm->active_volatile_bytes, + cxlm->active_persistent_bytes, + cxlm->next_volatile_bytes, + cxlm->next_persistent_bytes); + /* * TODO: enumerate DPA map, as 'ram' and 'pmem' do not alias. * For now, only the capacity is exported in sysfs */ cxlm->ram_range.start = 0; - cxlm->ram_range.end = cxlm->volatile_only_bytes - 1; + cxlm->ram_range.end = cxlm->active_volatile_bytes - 1; cxlm->pmem_range.start = 0; - cxlm->pmem_range.end = cxlm->persistent_only_bytes - 1; - - cxlm->lsa_size = le32_to_cpu(id.lsa_size); - memcpy(cxlm->firmware_version, id.fw_revision, sizeof(id.fw_revision)); + cxlm->pmem_range.end = cxlm->active_persistent_bytes - 1; return 0; } @@ -1427,6 +1509,10 @@ static int cxl_mem_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (rc) return rc; + rc = cxl_mem_create_range_info(cxlm); + if (rc) + return rc; + cxlmd = devm_cxl_add_memdev(&pdev->dev, cxlm, &cxl_memdev_fops); if (IS_ERR(cxlmd)) return PTR_ERR(cxlmd); From 5546e3dfb65a4389e747766ac455a50c3675fb0f Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 10 Aug 2021 23:20:06 +0200 Subject: [PATCH 114/696] rtc: lib_test: add MODULE_LICENSE As the documentation states, "The exact license information can only be determined via the license information in the corresponding source files." and the SPDX identifier has the proper information. Reported-by: Stephen Rothwell Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20210810212008.631359-1-alexandre.belloni@bootlin.com --- drivers/rtc/lib_test.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/rtc/lib_test.c b/drivers/rtc/lib_test.c index 2124b67a2f43..d5caf36c56cd 100644 --- a/drivers/rtc/lib_test.c +++ b/drivers/rtc/lib_test.c @@ -77,3 +77,5 @@ static struct kunit_suite rtc_lib_test_suite = { }; kunit_test_suite(rtc_lib_test_suite); + +MODULE_LICENSE("GPL"); From b02c96464f443e030be74ddd450c46703fe7ba8c Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 10 Aug 2021 23:20:07 +0200 Subject: [PATCH 115/696] rtc: move RTC_LIB_KUNIT_TEST to proper location Move RTC_LIB_KUNIT_TEST under RTC_LIB so it is clear in the menu this is part of the RTC subsystem. Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20210810212008.631359-2-alexandre.belloni@bootlin.com --- drivers/rtc/Kconfig | 19 +++++++++---------- drivers/rtc/Makefile | 3 ++- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index b3cf3a274c05..daff06707455 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -10,16 +10,6 @@ config RTC_MC146818_LIB bool select RTC_LIB -config RTC_LIB_KUNIT_TEST - tristate "KUnit test for RTC lib functions" if !KUNIT_ALL_TESTS - depends on KUNIT - default KUNIT_ALL_TESTS - select RTC_LIB - help - Enable this option to test RTC library functions. - - If unsure, say N. - menuconfig RTC_CLASS bool "Real Time Clock" default n @@ -85,6 +75,15 @@ config RTC_DEBUG Say yes here to enable debugging support in the RTC framework and individual RTC drivers. +config RTC_LIB_KUNIT_TEST + tristate "KUnit test for RTC lib functions" if !KUNIT_ALL_TESTS + depends on KUNIT + default KUNIT_ALL_TESTS + help + Enable this option to test RTC library functions. + + If unsure, say N. + config RTC_NVMEM bool "RTC non volatile storage support" select NVMEM diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 763d3628c603..5ceeafe4d5b2 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -15,6 +15,8 @@ rtc-core-$(CONFIG_RTC_INTF_DEV) += dev.o rtc-core-$(CONFIG_RTC_INTF_PROC) += proc.o rtc-core-$(CONFIG_RTC_INTF_SYSFS) += sysfs.o +obj-$(CONFIG_RTC_LIB_KUNIT_TEST) += lib_test.o + # Keep the list ordered. obj-$(CONFIG_RTC_DRV_88PM80X) += rtc-88pm80x.o @@ -178,4 +180,3 @@ obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o obj-$(CONFIG_RTC_DRV_XGENE) += rtc-xgene.o obj-$(CONFIG_RTC_DRV_ZYNQMP) += rtc-zynqmp.o -obj-$(CONFIG_RTC_LIB_KUNIT_TEST) += lib_test.o From ceeb0da0a0322bcba4c50ab3cf97fe9a7aa8a2e4 Mon Sep 17 00:00:00 2001 From: Ira Weiny Date: Thu, 17 Jun 2021 15:16:20 -0700 Subject: [PATCH 116/696] cxl/mem: Adjust ram/pmem range to represent DPA ranges CXL spec defines the volatile DPA range to be 0 to Volatile memory size. It further defines the persistent DPA range to follow directly after the end of the Volatile DPA through the persistent memory size. Essentially Volatile DPA range = [0, Volatile size) Persistent DPA range = [Volatile size, Volatile size + Persistent size) Adjust the pmem_range start to reflect this and remote the TODO. Signed-off-by: Ira Weiny Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20210617221620.1904031-4-ira.weiny@intel.com Signed-off-by: Dan Williams --- drivers/cxl/pci.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c index 3f5db8960098..651e8d4ec974 100644 --- a/drivers/cxl/pci.c +++ b/drivers/cxl/pci.c @@ -1441,8 +1441,9 @@ static int cxl_mem_create_range_info(struct cxl_mem *cxlm) if (cxlm->partition_align_bytes == 0) { cxlm->ram_range.start = 0; cxlm->ram_range.end = cxlm->volatile_only_bytes - 1; - cxlm->pmem_range.start = 0; - cxlm->pmem_range.end = cxlm->persistent_only_bytes - 1; + cxlm->pmem_range.start = cxlm->volatile_only_bytes; + cxlm->pmem_range.end = cxlm->volatile_only_bytes + + cxlm->persistent_only_bytes - 1; return 0; } @@ -1466,15 +1467,12 @@ static int cxl_mem_create_range_info(struct cxl_mem *cxlm) cxlm->next_volatile_bytes, cxlm->next_persistent_bytes); - /* - * TODO: enumerate DPA map, as 'ram' and 'pmem' do not alias. - * For now, only the capacity is exported in sysfs - */ cxlm->ram_range.start = 0; cxlm->ram_range.end = cxlm->active_volatile_bytes - 1; - cxlm->pmem_range.start = 0; - cxlm->pmem_range.end = cxlm->active_persistent_bytes - 1; + cxlm->pmem_range.start = cxlm->active_volatile_bytes; + cxlm->pmem_range.end = cxlm->active_volatile_bytes + + cxlm->active_persistent_bytes - 1; return 0; } From bb8c26d9387fe428068dcab35b1873ea3b881de1 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 11 Aug 2021 10:22:55 +0530 Subject: [PATCH 117/696] cpufreq: vexpress: Set CPUFREQ_IS_COOLING_DEV flag Reuse the cpufreq core's registration of cooling device by setting the CPUFREQ_IS_COOLING_DEV flag. Set this only if bL switcher isn't enabled. Signed-off-by: Viresh Kumar --- drivers/cpufreq/vexpress-spc-cpufreq.c | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/drivers/cpufreq/vexpress-spc-cpufreq.c b/drivers/cpufreq/vexpress-spc-cpufreq.c index 51dfa9ae6cf5..ab56813b7256 100644 --- a/drivers/cpufreq/vexpress-spc-cpufreq.c +++ b/drivers/cpufreq/vexpress-spc-cpufreq.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -47,7 +46,6 @@ static bool bL_switching_enabled; #define ACTUAL_FREQ(cluster, freq) ((cluster == A7_CLUSTER) ? freq << 1 : freq) #define VIRT_FREQ(cluster, freq) ((cluster == A7_CLUSTER) ? freq >> 1 : freq) -static struct thermal_cooling_device *cdev[MAX_CLUSTERS]; static struct clk *clk[MAX_CLUSTERS]; static struct cpufreq_frequency_table *freq_table[MAX_CLUSTERS + 1]; static atomic_t cluster_usage[MAX_CLUSTERS + 1]; @@ -457,11 +455,6 @@ static int ve_spc_cpufreq_exit(struct cpufreq_policy *policy) struct device *cpu_dev; int cur_cluster = cpu_to_cluster(policy->cpu); - if (cur_cluster < MAX_CLUSTERS) { - cpufreq_cooling_unregister(cdev[cur_cluster]); - cdev[cur_cluster] = NULL; - } - cpu_dev = get_cpu_device(policy->cpu); if (!cpu_dev) { pr_err("%s: failed to get cpu%d device\n", __func__, @@ -473,17 +466,6 @@ static int ve_spc_cpufreq_exit(struct cpufreq_policy *policy) return 0; } -static void ve_spc_cpufreq_ready(struct cpufreq_policy *policy) -{ - int cur_cluster = cpu_to_cluster(policy->cpu); - - /* Do not register a cpu_cooling device if we are in IKS mode */ - if (cur_cluster >= MAX_CLUSTERS) - return; - - cdev[cur_cluster] = of_cpufreq_cooling_register(policy); -} - static struct cpufreq_driver ve_spc_cpufreq_driver = { .name = "vexpress-spc", .flags = CPUFREQ_HAVE_GOVERNOR_PER_POLICY | @@ -493,7 +475,6 @@ static struct cpufreq_driver ve_spc_cpufreq_driver = { .get = ve_spc_cpufreq_get_rate, .init = ve_spc_cpufreq_init, .exit = ve_spc_cpufreq_exit, - .ready = ve_spc_cpufreq_ready, .attr = cpufreq_generic_attr, }; @@ -553,6 +534,9 @@ static int ve_spc_cpufreq_probe(struct platform_device *pdev) for (i = 0; i < MAX_CLUSTERS; i++) mutex_init(&cluster_lock[i]); + if (!is_bL_switching_enabled()) + ve_spc_cpufreq_driver.flags |= CPUFREQ_IS_COOLING_DEV; + ret = cpufreq_register_driver(&ve_spc_cpufreq_driver); if (ret) { pr_info("%s: Failed registering platform driver: %s, err: %d\n", From c17495b01b72b53bd290f442d39b060e015c7aea Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 10 Aug 2021 12:04:33 +0530 Subject: [PATCH 118/696] cpufreq: Add callback to register with energy model Many cpufreq drivers register with the energy model for each policy and do exactly the same thing. Follow the footsteps of thermal-cooling, to get it done from the cpufreq core itself. Provide a new callback, which will be called, if present, by the cpufreq core at the right moment (more on that in the code's comment). Also provide a generic implementation that uses dev_pm_opp_of_register_em(). This also allows us to register with the EM at a later point of time, compared to ->init(), from where the EM core can access cpufreq policy directly using cpufreq_cpu_get() type of helpers and perform other work, like marking few frequencies inefficient, this will be done separately. Reviewed-by: Quentin Perret Reviewed-by: Lukasz Luba Signed-off-by: Viresh Kumar --- drivers/cpufreq/cpufreq.c | 13 +++++++++++++ include/linux/cpufreq.h | 14 ++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 45f3416988f1..d301f39248a0 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1491,6 +1491,19 @@ static int cpufreq_online(unsigned int cpu) write_lock_irqsave(&cpufreq_driver_lock, flags); list_add(&policy->policy_list, &cpufreq_policy_list); write_unlock_irqrestore(&cpufreq_driver_lock, flags); + + /* + * Register with the energy model before + * sched_cpufreq_governor_change() is called, which will result + * in rebuilding of the sched domains, which should only be done + * once the energy model is properly initialized for the policy + * first. + * + * Also, this should be called before the policy is registered + * with cooling framework. + */ + if (cpufreq_driver->register_em) + cpufreq_driver->register_em(policy); } ret = cpufreq_init_policy(policy); diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 9fd719475fcd..c65a1d7385f8 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -9,10 +9,12 @@ #define _LINUX_CPUFREQ_H #include +#include #include #include #include #include +#include #include #include #include @@ -373,6 +375,12 @@ struct cpufreq_driver { /* platform specific boost support code */ bool boost_enabled; int (*set_boost)(struct cpufreq_policy *policy, int state); + + /* + * Set by drivers that want to register with the energy model after the + * policy is properly initialized, but before the governor is started. + */ + void (*register_em)(struct cpufreq_policy *policy); }; /* flags */ @@ -1046,4 +1054,10 @@ unsigned int cpufreq_generic_get(unsigned int cpu); void cpufreq_generic_init(struct cpufreq_policy *policy, struct cpufreq_frequency_table *table, unsigned int transition_latency); + +static inline void cpufreq_register_em_with_opp(struct cpufreq_policy *policy) +{ + dev_pm_opp_of_register_em(get_cpu_device(policy->cpu), + policy->related_cpus); +} #endif /* _LINUX_CPUFREQ_H */ From 94ab4c3c259c7d00746e5cafb55b5f5125f34b71 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 10 Aug 2021 12:24:36 +0530 Subject: [PATCH 119/696] cpufreq: dt: Use .register_em() to register with energy model Set the newly added .register_em() callback with cpufreq_register_em_with_opp() to register with the EM core. Signed-off-by: Viresh Kumar --- drivers/cpufreq/cpufreq-dt.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c index ece52863ba62..8fcaba541539 100644 --- a/drivers/cpufreq/cpufreq-dt.c +++ b/drivers/cpufreq/cpufreq-dt.c @@ -143,8 +143,6 @@ static int cpufreq_init(struct cpufreq_policy *policy) cpufreq_dt_attr[1] = &cpufreq_freq_attr_scaling_boost_freqs; } - dev_pm_opp_of_register_em(cpu_dev, policy->cpus); - return 0; out_clk_put: @@ -184,6 +182,7 @@ static struct cpufreq_driver dt_cpufreq_driver = { .exit = cpufreq_exit, .online = cpufreq_online, .offline = cpufreq_offline, + .register_em = cpufreq_register_em_with_opp, .name = "cpufreq-dt", .attr = cpufreq_dt_attr, .suspend = cpufreq_generic_suspend, From fcd300c685d5152e76a811c492b0e6eccde29717 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 10 Aug 2021 12:24:36 +0530 Subject: [PATCH 120/696] cpufreq: imx6q: Use .register_em() to register with energy model Set the newly added .register_em() callback with cpufreq_register_em_with_opp() to register with the EM core. Signed-off-by: Viresh Kumar --- drivers/cpufreq/imx6q-cpufreq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c index 5bf5fc759881..90beb26ed34e 100644 --- a/drivers/cpufreq/imx6q-cpufreq.c +++ b/drivers/cpufreq/imx6q-cpufreq.c @@ -192,7 +192,6 @@ static int imx6q_cpufreq_init(struct cpufreq_policy *policy) policy->clk = clks[ARM].clk; cpufreq_generic_init(policy, freq_table, transition_latency); policy->suspend_freq = max_freq; - dev_pm_opp_of_register_em(cpu_dev, policy->cpus); return 0; } @@ -204,6 +203,7 @@ static struct cpufreq_driver imx6q_cpufreq_driver = { .target_index = imx6q_set_target, .get = cpufreq_generic_get, .init = imx6q_cpufreq_init, + .register_em = cpufreq_register_em_with_opp, .name = "imx6q-cpufreq", .attr = cpufreq_generic_attr, .suspend = cpufreq_generic_suspend, From 3701fd64a3fb947fc805ca0d108ab87562a9659b Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 10 Aug 2021 12:24:36 +0530 Subject: [PATCH 121/696] cpufreq: mediatek: Use .register_em() to register with energy model Set the newly added .register_em() callback with cpufreq_register_em_with_opp() to register with the EM core. Signed-off-by: Viresh Kumar --- drivers/cpufreq/mediatek-cpufreq.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/cpufreq/mediatek-cpufreq.c b/drivers/cpufreq/mediatek-cpufreq.c index 87019d5a9547..866163883b48 100644 --- a/drivers/cpufreq/mediatek-cpufreq.c +++ b/drivers/cpufreq/mediatek-cpufreq.c @@ -448,8 +448,6 @@ static int mtk_cpufreq_init(struct cpufreq_policy *policy) policy->driver_data = info; policy->clk = info->cpu_clk; - dev_pm_opp_of_register_em(info->cpu_dev, policy->cpus); - return 0; } @@ -471,6 +469,7 @@ static struct cpufreq_driver mtk_cpufreq_driver = { .get = cpufreq_generic_get, .init = mtk_cpufreq_init, .exit = mtk_cpufreq_exit, + .register_em = cpufreq_register_em_with_opp, .name = "mtk-cpufreq", .attr = cpufreq_generic_attr, }; From 361a172d230964807c0b479738749c50d95d7b50 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 10 Aug 2021 12:24:36 +0530 Subject: [PATCH 122/696] cpufreq: omap: Use .register_em() to register with energy model Set the newly added .register_em() callback with cpufreq_register_em_with_opp() to register with the EM core. Signed-off-by: Viresh Kumar --- drivers/cpufreq/omap-cpufreq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c index e035ee216b0f..1b50df06c6bc 100644 --- a/drivers/cpufreq/omap-cpufreq.c +++ b/drivers/cpufreq/omap-cpufreq.c @@ -131,7 +131,6 @@ static int omap_cpu_init(struct cpufreq_policy *policy) /* FIXME: what's the actual transition time? */ cpufreq_generic_init(policy, freq_table, 300 * 1000); - dev_pm_opp_of_register_em(mpu_dev, policy->cpus); return 0; } @@ -150,6 +149,7 @@ static struct cpufreq_driver omap_driver = { .get = cpufreq_generic_get, .init = omap_cpu_init, .exit = omap_cpu_exit, + .register_em = cpufreq_register_em_with_opp, .name = "omap", .attr = cpufreq_generic_attr, }; From e96c2153d0fc0a1c218bf5ba149ccdf75d19a275 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 10 Aug 2021 12:24:36 +0530 Subject: [PATCH 123/696] cpufreq: qcom-cpufreq-hw: Use .register_em() to register with energy model Set the newly added .register_em() callback with cpufreq_register_em_with_opp() to register with the EM core. Signed-off-by: Viresh Kumar --- drivers/cpufreq/qcom-cpufreq-hw.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/cpufreq/qcom-cpufreq-hw.c b/drivers/cpufreq/qcom-cpufreq-hw.c index f86859bf76f1..c2e71c430fbf 100644 --- a/drivers/cpufreq/qcom-cpufreq-hw.c +++ b/drivers/cpufreq/qcom-cpufreq-hw.c @@ -362,8 +362,6 @@ static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy) goto error; } - dev_pm_opp_of_register_em(cpu_dev, policy->cpus); - if (policy_has_boost_freq(policy)) { ret = cpufreq_enable_boost_support(); if (ret) @@ -412,6 +410,7 @@ static struct cpufreq_driver cpufreq_qcom_hw_driver = { .get = qcom_cpufreq_hw_get, .init = qcom_cpufreq_hw_cpu_init, .exit = qcom_cpufreq_hw_cpu_exit, + .register_em = cpufreq_register_em_with_opp, .fast_switch = qcom_cpufreq_hw_fast_switch, .name = "qcom-cpufreq-hw", .attr = qcom_cpufreq_hw_attr, From ca8c1c53b03b3b1aef5a6efdab7f1af86be0e6d7 Mon Sep 17 00:00:00 2001 From: Wen Yang Date: Thu, 29 Jul 2021 17:32:28 +0800 Subject: [PATCH 124/696] ipmi: rate limit ipmi smi_event failure message Sometimes we can't get a valid si_sm_data, and we print an error message accordingly. But the ipmi module seem to like retrying a lot, in which case we flood the kernel log with a lot of messages, eg: [46318019.164726] ipmi_si IPI0001:00: Could not set the global enables: 0xc1. [46318020.109700] ipmi_si IPI0001:00: Could not set the global enables: 0xc1. [46318021.158677] ipmi_si IPI0001:00: Could not set the global enables: 0xc1. [46318022.212598] ipmi_si IPI0001:00: Could not set the global enables: 0xc1. [46318023.258564] ipmi_si IPI0001:00: Could not set the global enables: 0xc1. [46318024.210455] ipmi_si IPI0001:00: Could not set the global enables: 0xc1. [46318025.260473] ipmi_si IPI0001:00: Could not set the global enables: 0xc1. [46318026.308445] ipmi_si IPI0001:00: Could not set the global enables: 0xc1. [46318027.356389] ipmi_si IPI0001:00: Could not set the global enables: 0xc1. [46318028.298288] ipmi_si IPI0001:00: Could not set the global enables: 0xc1. [46318029.363302] ipmi_si IPI0001:00: Could not set the global enables: 0xc1. Signed-off-by: Wen Yang Cc: Baoyou Xie Cc: Corey Minyard Cc: openipmi-developer@lists.sourceforge.net Cc: linux-kernel@vger.kernel.org Message-Id: <20210729093228.77098-1-wenyang@linux.alibaba.com> [Added a missing comma] Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_si_intf.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 62929a3e397e..46137a4a5620 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -591,7 +591,7 @@ static void handle_transaction_done(struct smi_info *smi_info) smi_info->handlers->get_result(smi_info->si_sm, msg, 3); if (msg[2] != 0) { /* Error clearing flags */ - dev_warn(smi_info->io.dev, + dev_warn_ratelimited(smi_info->io.dev, "Error clearing flags: %2.2x\n", msg[2]); } smi_info->si_state = SI_NORMAL; @@ -683,10 +683,10 @@ static void handle_transaction_done(struct smi_info *smi_info) /* We got the flags from the SMI, now handle them. */ smi_info->handlers->get_result(smi_info->si_sm, msg, 4); if (msg[2] != 0) { - dev_warn(smi_info->io.dev, - "Couldn't get irq info: %x.\n", msg[2]); - dev_warn(smi_info->io.dev, - "Maybe ok, but ipmi might run very slowly.\n"); + dev_warn_ratelimited(smi_info->io.dev, + "Couldn't get irq info: %x,\n" + "Maybe ok, but ipmi might run very slowly.\n", + msg[2]); smi_info->si_state = SI_NORMAL; break; } @@ -721,7 +721,7 @@ static void handle_transaction_done(struct smi_info *smi_info) smi_info->handlers->get_result(smi_info->si_sm, msg, 4); if (msg[2] != 0) - dev_warn(smi_info->io.dev, + dev_warn_ratelimited(smi_info->io.dev, "Could not set the global enables: 0x%x.\n", msg[2]); @@ -1343,7 +1343,7 @@ retry: if (cc != IPMI_CC_NO_ERROR && ++retry_count <= GET_DEVICE_ID_MAX_RETRY) { - dev_warn(smi_info->io.dev, + dev_warn_ratelimited(smi_info->io.dev, "BMC returned 0x%2.2x, retry get bmc device id\n", cc); goto retry; From bf064c7bec3bfe7e28889774dc9e0ca4f7236775 Mon Sep 17 00:00:00 2001 From: Dwaipayan Ray Date: Fri, 30 Jul 2021 11:59:51 +0530 Subject: [PATCH 125/696] char: ipmi: use DEVICE_ATTR helper macro Instead of open coding DEVICE_ATTR, use the helper macro DEVICE_ATTR_RO to replace DEVICE_ATTR with 0444 octal permissions. This was detected as a part of checkpatch evaluation investigating all reports of DEVICE_ATTR_RO warning type. Signed-off-by: Dwaipayan Ray Message-Id: <20210730062951.84876-1-dwaipayanray1@gmail.com> Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_si_intf.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 46137a4a5620..5bf927104259 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1605,7 +1605,7 @@ static ssize_t name##_show(struct device *dev, \ \ return snprintf(buf, 10, "%u\n", smi_get_stat(smi_info, name)); \ } \ -static DEVICE_ATTR(name, 0444, name##_show, NULL) +static DEVICE_ATTR_RO(name) static ssize_t type_show(struct device *dev, struct device_attribute *attr, @@ -1615,7 +1615,7 @@ static ssize_t type_show(struct device *dev, return snprintf(buf, 10, "%s\n", si_to_str[smi_info->io.si_type]); } -static DEVICE_ATTR(type, 0444, type_show, NULL); +static DEVICE_ATTR_RO(type); static ssize_t interrupts_enabled_show(struct device *dev, struct device_attribute *attr, @@ -1626,8 +1626,7 @@ static ssize_t interrupts_enabled_show(struct device *dev, return snprintf(buf, 10, "%d\n", enabled); } -static DEVICE_ATTR(interrupts_enabled, 0444, - interrupts_enabled_show, NULL); +static DEVICE_ATTR_RO(interrupts_enabled); IPMI_SI_ATTR(short_timeouts); IPMI_SI_ATTR(long_timeouts); @@ -1658,7 +1657,7 @@ static ssize_t params_show(struct device *dev, smi_info->io.irq, smi_info->io.slave_addr); } -static DEVICE_ATTR(params, 0444, params_show, NULL); +static DEVICE_ATTR_RO(params); static struct attribute *ipmi_si_dev_attrs[] = { &dev_attr_type.attr, From 7bb698f09bdd01fbb6d48c14bb1dde556dc1af00 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Wed, 28 Jul 2021 07:47:33 -0500 Subject: [PATCH 126/696] fs: Move notify_change permission checks into may_setattr Move the permission checks in notify_change into a separate function to make them available to filesystems. When notify_change is called, the vfs performs those checks before calling into iop->setattr. However, a filesystem like gfs2 can only lock and revalidate the inode inside ->setattr, and it must then repeat those checks to err on the safe side. It would be nice to get rid of the double checking, but moving the permission check into iop->setattr altogether isn't really an option. Signed-off-by: Andreas Gruenbacher Signed-off-by: Bob Peterson Signed-off-by: Al Viro --- fs/attr.c | 50 ++++++++++++++++++++++++++++------------------ include/linux/fs.h | 2 ++ 2 files changed, 33 insertions(+), 19 deletions(-) diff --git a/fs/attr.c b/fs/attr.c index 87ef39db1c34..473d21b3a86d 100644 --- a/fs/attr.c +++ b/fs/attr.c @@ -249,6 +249,34 @@ void setattr_copy(struct user_namespace *mnt_userns, struct inode *inode, } EXPORT_SYMBOL(setattr_copy); +int may_setattr(struct user_namespace *mnt_userns, struct inode *inode, + unsigned int ia_valid) +{ + int error; + + if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | ATTR_TIMES_SET)) { + if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) + return -EPERM; + } + + /* + * If utimes(2) and friends are called with times == NULL (or both + * times are UTIME_NOW), then we need to check for write permission + */ + if (ia_valid & ATTR_TOUCH) { + if (IS_IMMUTABLE(inode)) + return -EPERM; + + if (!inode_owner_or_capable(mnt_userns, inode)) { + error = inode_permission(mnt_userns, inode, MAY_WRITE); + if (error) + return error; + } + } + return 0; +} +EXPORT_SYMBOL(may_setattr); + /** * notify_change - modify attributes of a filesytem object * @mnt_userns: user namespace of the mount the inode was found from @@ -290,25 +318,9 @@ int notify_change(struct user_namespace *mnt_userns, struct dentry *dentry, WARN_ON_ONCE(!inode_is_locked(inode)); - if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | ATTR_TIMES_SET)) { - if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) - return -EPERM; - } - - /* - * If utimes(2) and friends are called with times == NULL (or both - * times are UTIME_NOW), then we need to check for write permission - */ - if (ia_valid & ATTR_TOUCH) { - if (IS_IMMUTABLE(inode)) - return -EPERM; - - if (!inode_owner_or_capable(mnt_userns, inode)) { - error = inode_permission(mnt_userns, inode, MAY_WRITE); - if (error) - return error; - } - } + error = may_setattr(mnt_userns, inode, ia_valid); + if (error) + return error; if ((ia_valid & ATTR_MODE)) { umode_t amode = attr->ia_mode; diff --git a/include/linux/fs.h b/include/linux/fs.h index 640574294216..50192964bf6b 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -3469,6 +3469,8 @@ extern int buffer_migrate_page_norefs(struct address_space *, #define buffer_migrate_page_norefs NULL #endif +int may_setattr(struct user_namespace *mnt_userns, struct inode *inode, + unsigned int ia_valid); int setattr_prepare(struct user_namespace *, struct dentry *, struct iattr *); extern int inode_newsize_ok(const struct inode *, loff_t offset); void setattr_copy(struct user_namespace *, struct inode *inode, From d75b9fa053e4cd278281386d860c26fdbfbe9d03 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Wed, 28 Jul 2021 07:47:34 -0500 Subject: [PATCH 127/696] gfs2: Switch to may_setattr in gfs2_setattr The permission check in gfs2_setattr is an old and outdated version of may_setattr(). Switch to the updated version. Fixes fstest generic/079. Signed-off-by: Andreas Gruenbacher Signed-off-by: Bob Peterson Signed-off-by: Al Viro --- fs/gfs2/inode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 6e15434b23ac..3130f85d2b3f 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -1985,8 +1985,8 @@ static int gfs2_setattr(struct user_namespace *mnt_userns, if (error) goto out; - error = -EPERM; - if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) + error = may_setattr(&init_user_ns, inode, attr->ia_valid); + if (error) goto error; error = setattr_prepare(&init_user_ns, dentry, attr); From 3747e4263ff6d6085507a32946f8236c62dd2495 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 16 Jun 2021 22:04:14 +0300 Subject: [PATCH 128/696] thermal/drivers/tegra: Add driver for Tegra30 thermal sensor All NVIDIA Tegra30 SoCs have a two-channel on-chip sensor unit which monitors temperature and voltage of the SoC. Sensors control CPU frequency throttling, which is activated by hardware once preprogrammed temperature level is breached, they also send signal to Power Management controller to perform emergency shutdown on a critical overheat of the SoC die. Add driver for the Tegra30 TSENSOR module, exposing it as a thermal sensor. Tested-by: Andreas Westman Dorcsak # Asus TF700T Tested-by: Maxim Schwalm # Asus TF700T Tested-by: Svyatoslav Ryhel # Asus TF201T Tested-by: Ihor Didenko # Asus TF300T Tested-by: Ion Agorria # Asus TF201T Tested-by: Matt Merhar # Ouya Tested-by: Peter Geis # Ouya Acked-by: Thierry Reding Signed-off-by: Dmitry Osipenko Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20210616190417.32214-4-digetx@gmail.com --- drivers/thermal/tegra/Kconfig | 7 + drivers/thermal/tegra/Makefile | 1 + drivers/thermal/tegra/tegra30-tsensor.c | 673 ++++++++++++++++++++++++ 3 files changed, 681 insertions(+) create mode 100644 drivers/thermal/tegra/tegra30-tsensor.c diff --git a/drivers/thermal/tegra/Kconfig b/drivers/thermal/tegra/Kconfig index 46c2215867cd..019e3a2eb69e 100644 --- a/drivers/thermal/tegra/Kconfig +++ b/drivers/thermal/tegra/Kconfig @@ -18,4 +18,11 @@ config TEGRA_BPMP_THERMAL Enable this option for support for sensing system temperature of NVIDIA Tegra systems-on-chip with the BPMP coprocessor (Tegra186). +config TEGRA30_TSENSOR + tristate "Tegra30 Thermal Sensor" + depends on ARCH_TEGRA_3x_SOC || COMPILE_TEST + help + Enable this option to support thermal management of NVIDIA Tegra30 + system-on-chip. + endmenu diff --git a/drivers/thermal/tegra/Makefile b/drivers/thermal/tegra/Makefile index 0f2b66edf0d2..eb27d194c583 100644 --- a/drivers/thermal/tegra/Makefile +++ b/drivers/thermal/tegra/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_TEGRA_SOCTHERM) += tegra-soctherm.o obj-$(CONFIG_TEGRA_BPMP_THERMAL) += tegra-bpmp-thermal.o +obj-$(CONFIG_TEGRA30_TSENSOR) += tegra30-tsensor.o tegra-soctherm-y := soctherm.o soctherm-fuse.o tegra-soctherm-$(CONFIG_ARCH_TEGRA_124_SOC) += tegra124-soctherm.o diff --git a/drivers/thermal/tegra/tegra30-tsensor.c b/drivers/thermal/tegra/tegra30-tsensor.c new file mode 100644 index 000000000000..9b6b693cbcf8 --- /dev/null +++ b/drivers/thermal/tegra/tegra30-tsensor.c @@ -0,0 +1,673 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Tegra30 SoC Thermal Sensor driver + * + * Based on downstream HWMON driver from NVIDIA. + * Copyright (C) 2011 NVIDIA Corporation + * + * Author: Dmitry Osipenko + * Copyright (C) 2021 GRATE-DRIVER project + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "../thermal_core.h" +#include "../thermal_hwmon.h" + +#define TSENSOR_SENSOR0_CONFIG0 0x0 +#define TSENSOR_SENSOR0_CONFIG0_SENSOR_STOP BIT(0) +#define TSENSOR_SENSOR0_CONFIG0_HW_FREQ_DIV_EN BIT(1) +#define TSENSOR_SENSOR0_CONFIG0_THERMAL_RST_EN BIT(2) +#define TSENSOR_SENSOR0_CONFIG0_DVFS_EN BIT(3) +#define TSENSOR_SENSOR0_CONFIG0_INTR_OVERFLOW_EN BIT(4) +#define TSENSOR_SENSOR0_CONFIG0_INTR_HW_FREQ_DIV_EN BIT(5) +#define TSENSOR_SENSOR0_CONFIG0_INTR_THERMAL_RST_EN BIT(6) +#define TSENSOR_SENSOR0_CONFIG0_M GENMASK(23, 8) +#define TSENSOR_SENSOR0_CONFIG0_N GENMASK(31, 24) + +#define TSENSOR_SENSOR0_CONFIG1 0x8 +#define TSENSOR_SENSOR0_CONFIG1_TH1 GENMASK(15, 0) +#define TSENSOR_SENSOR0_CONFIG1_TH2 GENMASK(31, 16) + +#define TSENSOR_SENSOR0_CONFIG2 0xc +#define TSENSOR_SENSOR0_CONFIG2_TH3 GENMASK(15, 0) + +#define TSENSOR_SENSOR0_STATUS0 0x18 +#define TSENSOR_SENSOR0_STATUS0_STATE GENMASK(2, 0) +#define TSENSOR_SENSOR0_STATUS0_INTR BIT(8) +#define TSENSOR_SENSOR0_STATUS0_CURRENT_VALID BIT(9) + +#define TSENSOR_SENSOR0_TS_STATUS1 0x1c +#define TSENSOR_SENSOR0_TS_STATUS1_CURRENT_COUNT GENMASK(31, 16) + +#define TEGRA30_FUSE_TEST_PROG_VER 0x28 + +#define TEGRA30_FUSE_TSENSOR_CALIB 0x98 +#define TEGRA30_FUSE_TSENSOR_CALIB_LOW GENMASK(15, 0) +#define TEGRA30_FUSE_TSENSOR_CALIB_HIGH GENMASK(31, 16) + +#define TEGRA30_FUSE_SPARE_BIT 0x144 + +struct tegra_tsensor; + +struct tegra_tsensor_calibration_data { + int a, b, m, n, p, r; +}; + +struct tegra_tsensor_channel { + void __iomem *regs; + unsigned int id; + struct tegra_tsensor *ts; + struct thermal_zone_device *tzd; +}; + +struct tegra_tsensor { + void __iomem *regs; + bool swap_channels; + struct clk *clk; + struct device *dev; + struct reset_control *rst; + struct tegra_tsensor_channel ch[2]; + struct tegra_tsensor_calibration_data calib; +}; + +static int tegra_tsensor_hw_enable(const struct tegra_tsensor *ts) +{ + u32 val; + int err; + + err = reset_control_assert(ts->rst); + if (err) { + dev_err(ts->dev, "failed to assert hardware reset: %d\n", err); + return err; + } + + err = clk_prepare_enable(ts->clk); + if (err) { + dev_err(ts->dev, "failed to enable clock: %d\n", err); + return err; + } + + fsleep(1000); + + err = reset_control_deassert(ts->rst); + if (err) { + dev_err(ts->dev, "failed to deassert hardware reset: %d\n", err); + goto disable_clk; + } + + /* + * Sensors are enabled after reset by default, but not gauging + * until clock counter is programmed. + * + * M: number of reference clock pulses after which every + * temperature / voltage measurement is made + * + * N: number of reference clock counts for which the counter runs + */ + val = FIELD_PREP(TSENSOR_SENSOR0_CONFIG0_M, 12500); + val |= FIELD_PREP(TSENSOR_SENSOR0_CONFIG0_N, 255); + + /* apply the same configuration to both channels */ + writel_relaxed(val, ts->regs + 0x40 + TSENSOR_SENSOR0_CONFIG0); + writel_relaxed(val, ts->regs + 0x80 + TSENSOR_SENSOR0_CONFIG0); + + return 0; + +disable_clk: + clk_disable_unprepare(ts->clk); + + return err; +} + +static int tegra_tsensor_hw_disable(const struct tegra_tsensor *ts) +{ + int err; + + err = reset_control_assert(ts->rst); + if (err) { + dev_err(ts->dev, "failed to assert hardware reset: %d\n", err); + return err; + } + + clk_disable_unprepare(ts->clk); + + return 0; +} + +static void devm_tegra_tsensor_hw_disable(void *data) +{ + const struct tegra_tsensor *ts = data; + + tegra_tsensor_hw_disable(ts); +} + +static int tegra_tsensor_get_temp(void *data, int *temp) +{ + const struct tegra_tsensor_channel *tsc = data; + const struct tegra_tsensor *ts = tsc->ts; + int err, c1, c2, c3, c4, counter; + u32 val; + + /* + * Counter will be invalid if hardware is misprogrammed or not enough + * time passed since the time when sensor was enabled. + */ + err = readl_relaxed_poll_timeout(tsc->regs + TSENSOR_SENSOR0_STATUS0, val, + val & TSENSOR_SENSOR0_STATUS0_CURRENT_VALID, + 21 * USEC_PER_MSEC, + 21 * USEC_PER_MSEC * 50); + if (err) { + dev_err_once(ts->dev, "ch%u: counter invalid\n", tsc->id); + return err; + } + + val = readl_relaxed(tsc->regs + TSENSOR_SENSOR0_TS_STATUS1); + counter = FIELD_GET(TSENSOR_SENSOR0_TS_STATUS1_CURRENT_COUNT, val); + + /* + * This shouldn't happen with a valid counter status, nevertheless + * lets verify the value since it's in a separate (from status) + * register. + */ + if (counter == 0xffff) { + dev_err_once(ts->dev, "ch%u: counter overflow\n", tsc->id); + return -EINVAL; + } + + /* + * temperature = a * counter + b + * temperature = m * (temperature ^ 2) + n * temperature + p + */ + c1 = DIV_ROUND_CLOSEST(ts->calib.a * counter + ts->calib.b, 1000000); + c1 = c1 ?: 1; + c2 = DIV_ROUND_CLOSEST(ts->calib.p, c1); + c3 = c1 * ts->calib.m; + c4 = ts->calib.n; + + *temp = DIV_ROUND_CLOSEST(c1 * (c2 + c3 + c4), 1000); + + return 0; +} + +static int tegra_tsensor_temp_to_counter(const struct tegra_tsensor *ts, int temp) +{ + int c1, c2; + + c1 = DIV_ROUND_CLOSEST(ts->calib.p - temp * 1000, ts->calib.m); + c2 = -ts->calib.r - int_sqrt(ts->calib.r * ts->calib.r - c1); + + return DIV_ROUND_CLOSEST(c2 * 1000000 - ts->calib.b, ts->calib.a); +} + +static int tegra_tsensor_set_trips(void *data, int low, int high) +{ + const struct tegra_tsensor_channel *tsc = data; + const struct tegra_tsensor *ts = tsc->ts; + u32 val; + + /* + * TSENSOR doesn't trigger interrupt on the "low" temperature breach, + * hence bail out if high temperature is unspecified. + */ + if (high == INT_MAX) + return 0; + + val = readl_relaxed(tsc->regs + TSENSOR_SENSOR0_CONFIG1); + val &= ~TSENSOR_SENSOR0_CONFIG1_TH1; + + high = tegra_tsensor_temp_to_counter(ts, high); + val |= FIELD_PREP(TSENSOR_SENSOR0_CONFIG1_TH1, high); + writel_relaxed(val, tsc->regs + TSENSOR_SENSOR0_CONFIG1); + + return 0; +} + +static const struct thermal_zone_of_device_ops ops = { + .get_temp = tegra_tsensor_get_temp, + .set_trips = tegra_tsensor_set_trips, +}; + +static bool +tegra_tsensor_handle_channel_interrupt(const struct tegra_tsensor *ts, + unsigned int id) +{ + const struct tegra_tsensor_channel *tsc = &ts->ch[id]; + u32 val; + + val = readl_relaxed(tsc->regs + TSENSOR_SENSOR0_STATUS0); + writel_relaxed(val, tsc->regs + TSENSOR_SENSOR0_STATUS0); + + if (FIELD_GET(TSENSOR_SENSOR0_STATUS0_STATE, val) == 5) + dev_err_ratelimited(ts->dev, "ch%u: counter overflowed\n", id); + + if (!FIELD_GET(TSENSOR_SENSOR0_STATUS0_INTR, val)) + return false; + + thermal_zone_device_update(tsc->tzd, THERMAL_EVENT_UNSPECIFIED); + + return true; +} + +static irqreturn_t tegra_tsensor_isr(int irq, void *data) +{ + const struct tegra_tsensor *ts = data; + bool handled = false; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(ts->ch); i++) + handled |= tegra_tsensor_handle_channel_interrupt(ts, i); + + return handled ? IRQ_HANDLED : IRQ_NONE; +} + +static int tegra_tsensor_disable_hw_channel(const struct tegra_tsensor *ts, + unsigned int id) +{ + const struct tegra_tsensor_channel *tsc = &ts->ch[id]; + struct thermal_zone_device *tzd = tsc->tzd; + u32 val; + int err; + + if (!tzd) + goto stop_channel; + + err = thermal_zone_device_disable(tzd); + if (err) { + dev_err(ts->dev, "ch%u: failed to disable zone: %d\n", id, err); + return err; + } + +stop_channel: + /* stop channel gracefully */ + val = readl_relaxed(tsc->regs + TSENSOR_SENSOR0_CONFIG0); + val |= FIELD_PREP(TSENSOR_SENSOR0_CONFIG0_SENSOR_STOP, 1); + writel_relaxed(val, tsc->regs + TSENSOR_SENSOR0_CONFIG0); + + return 0; +} + +static void tegra_tsensor_get_hw_channel_trips(struct thermal_zone_device *tzd, + int *hot_trip, int *crit_trip) +{ + unsigned int i; + + /* + * 90C is the maximal critical temperature of all Tegra30 SoC variants, + * use it for the default trip if unspecified in a device-tree. + */ + *hot_trip = 85000; + *crit_trip = 90000; + + for (i = 0; i < tzd->trips; i++) { + enum thermal_trip_type type; + int trip_temp; + + tzd->ops->get_trip_temp(tzd, i, &trip_temp); + tzd->ops->get_trip_type(tzd, i, &type); + + if (type == THERMAL_TRIP_HOT) + *hot_trip = trip_temp; + + if (type == THERMAL_TRIP_CRITICAL) + *crit_trip = trip_temp; + } + + /* clamp hardware trips to the calibration limits */ + *hot_trip = clamp(*hot_trip, 25000, 90000); + + /* + * Kernel will perform a normal system shut down if it will + * see that critical temperature is breached, hence set the + * hardware limit by 5C higher in order to allow system to + * shut down gracefully before sending signal to the Power + * Management controller. + */ + *crit_trip = clamp(*crit_trip + 5000, 25000, 90000); +} + +static int tegra_tsensor_enable_hw_channel(const struct tegra_tsensor *ts, + unsigned int id) +{ + const struct tegra_tsensor_channel *tsc = &ts->ch[id]; + struct thermal_zone_device *tzd = tsc->tzd; + int err, hot_trip = 0, crit_trip = 0; + u32 val; + + if (!tzd) { + val = readl_relaxed(tsc->regs + TSENSOR_SENSOR0_CONFIG0); + val &= ~TSENSOR_SENSOR0_CONFIG0_SENSOR_STOP; + writel_relaxed(val, tsc->regs + TSENSOR_SENSOR0_CONFIG0); + + return 0; + } + + tegra_tsensor_get_hw_channel_trips(tzd, &hot_trip, &crit_trip); + + /* prevent potential racing with tegra_tsensor_set_trips() */ + mutex_lock(&tzd->lock); + + dev_info_once(ts->dev, "ch%u: PMC emergency shutdown trip set to %dC\n", + id, DIV_ROUND_CLOSEST(crit_trip, 1000)); + + hot_trip = tegra_tsensor_temp_to_counter(ts, hot_trip); + crit_trip = tegra_tsensor_temp_to_counter(ts, crit_trip); + + /* program LEVEL2 counter threshold */ + val = readl_relaxed(tsc->regs + TSENSOR_SENSOR0_CONFIG1); + val &= ~TSENSOR_SENSOR0_CONFIG1_TH2; + val |= FIELD_PREP(TSENSOR_SENSOR0_CONFIG1_TH2, hot_trip); + writel_relaxed(val, tsc->regs + TSENSOR_SENSOR0_CONFIG1); + + /* program LEVEL3 counter threshold */ + val = readl_relaxed(tsc->regs + TSENSOR_SENSOR0_CONFIG2); + val &= ~TSENSOR_SENSOR0_CONFIG2_TH3; + val |= FIELD_PREP(TSENSOR_SENSOR0_CONFIG2_TH3, crit_trip); + writel_relaxed(val, tsc->regs + TSENSOR_SENSOR0_CONFIG2); + + /* + * Enable sensor, emergency shutdown, interrupts for level 1/2/3 + * breaches and counter overflow condition. + * + * Disable DIV2 throttle for now since we need to figure out how + * to integrate it properly with the thermal framework. + * + * Thermal levels supported by hardware: + * + * Level 0 = cold + * Level 1 = passive cooling (cpufreq DVFS) + * Level 2 = passive cooling assisted by hardware (DIV2) + * Level 3 = emergency shutdown assisted by hardware (PMC) + */ + val = readl_relaxed(tsc->regs + TSENSOR_SENSOR0_CONFIG0); + val &= ~TSENSOR_SENSOR0_CONFIG0_SENSOR_STOP; + val |= FIELD_PREP(TSENSOR_SENSOR0_CONFIG0_DVFS_EN, 1); + val |= FIELD_PREP(TSENSOR_SENSOR0_CONFIG0_HW_FREQ_DIV_EN, 0); + val |= FIELD_PREP(TSENSOR_SENSOR0_CONFIG0_THERMAL_RST_EN, 1); + val |= FIELD_PREP(TSENSOR_SENSOR0_CONFIG0_INTR_OVERFLOW_EN, 1); + val |= FIELD_PREP(TSENSOR_SENSOR0_CONFIG0_INTR_HW_FREQ_DIV_EN, 1); + val |= FIELD_PREP(TSENSOR_SENSOR0_CONFIG0_INTR_THERMAL_RST_EN, 1); + writel_relaxed(val, tsc->regs + TSENSOR_SENSOR0_CONFIG0); + + mutex_unlock(&tzd->lock); + + err = thermal_zone_device_enable(tzd); + if (err) { + dev_err(ts->dev, "ch%u: failed to enable zone: %d\n", id, err); + return err; + } + + return 0; +} + +static bool tegra_tsensor_fuse_read_spare(unsigned int spare) +{ + u32 val = 0; + + tegra_fuse_readl(TEGRA30_FUSE_SPARE_BIT + spare * 4, &val); + + return !!val; +} + +static int tegra_tsensor_nvmem_setup(struct tegra_tsensor *ts) +{ + u32 i, ate_ver = 0, cal = 0, t1_25C = 0, t2_90C = 0; + int err, c1_25C, c2_90C; + + err = tegra_fuse_readl(TEGRA30_FUSE_TEST_PROG_VER, &ate_ver); + if (err) { + dev_err_probe(ts->dev, err, "failed to get ATE version\n"); + return err; + } + + if (ate_ver < 8) { + dev_info(ts->dev, "unsupported ATE version: %u\n", ate_ver); + return -ENODEV; + } + + /* + * We have two TSENSOR channels in a two different spots on SoC. + * Second channel provides more accurate data on older SoC versions, + * use it as a primary channel. + */ + if (ate_ver <= 21) { + dev_info_once(ts->dev, + "older ATE version detected, channels remapped\n"); + ts->swap_channels = true; + } + + err = tegra_fuse_readl(TEGRA30_FUSE_TSENSOR_CALIB, &cal); + if (err) { + dev_err(ts->dev, "failed to get calibration data: %d\n", err); + return err; + } + + /* get calibrated counter values for 25C/90C thresholds */ + c1_25C = FIELD_GET(TEGRA30_FUSE_TSENSOR_CALIB_LOW, cal); + c2_90C = FIELD_GET(TEGRA30_FUSE_TSENSOR_CALIB_HIGH, cal); + + /* and calibrated temperatures corresponding to the counter values */ + for (i = 0; i < 7; i++) { + t1_25C |= tegra_tsensor_fuse_read_spare(14 + i) << i; + t1_25C |= tegra_tsensor_fuse_read_spare(21 + i) << i; + + t2_90C |= tegra_tsensor_fuse_read_spare(0 + i) << i; + t2_90C |= tegra_tsensor_fuse_read_spare(7 + i) << i; + } + + if (c2_90C - c1_25C <= t2_90C - t1_25C) { + dev_err(ts->dev, "invalid calibration data: %d %d %u %u\n", + c2_90C, c1_25C, t2_90C, t1_25C); + return -EINVAL; + } + + /* all calibration coefficients are premultiplied by 1000000 */ + + ts->calib.a = DIV_ROUND_CLOSEST((t2_90C - t1_25C) * 1000000, + (c2_90C - c1_25C)); + + ts->calib.b = t1_25C * 1000000 - ts->calib.a * c1_25C; + + if (tegra_sku_info.revision == TEGRA_REVISION_A01) { + ts->calib.m = -2775; + ts->calib.n = 1338811; + ts->calib.p = -7300000; + } else { + ts->calib.m = -3512; + ts->calib.n = 1528943; + ts->calib.p = -11100000; + } + + /* except the coefficient of a reduced quadratic equation */ + ts->calib.r = DIV_ROUND_CLOSEST(ts->calib.n, ts->calib.m * 2); + + dev_info_once(ts->dev, + "calibration: %d %d %u %u ATE ver: %u SoC rev: %u\n", + c2_90C, c1_25C, t2_90C, t1_25C, ate_ver, + tegra_sku_info.revision); + + return 0; +} + +static int tegra_tsensor_register_channel(struct tegra_tsensor *ts, + unsigned int id) +{ + struct tegra_tsensor_channel *tsc = &ts->ch[id]; + unsigned int hw_id = ts->swap_channels ? !id : id; + + tsc->ts = ts; + tsc->id = id; + tsc->regs = ts->regs + 0x40 * (hw_id + 1); + + tsc->tzd = devm_thermal_zone_of_sensor_register(ts->dev, id, tsc, &ops); + if (IS_ERR(tsc->tzd)) { + if (PTR_ERR(tsc->tzd) != -ENODEV) + return dev_err_probe(ts->dev, PTR_ERR(tsc->tzd), + "failed to register thermal zone\n"); + + /* + * It's okay if sensor isn't assigned to any thermal zone + * in a device-tree. + */ + tsc->tzd = NULL; + return 0; + } + + if (devm_thermal_add_hwmon_sysfs(tsc->tzd)) + dev_warn(ts->dev, "failed to add hwmon sysfs attributes\n"); + + return 0; +} + +static int tegra_tsensor_probe(struct platform_device *pdev) +{ + struct tegra_tsensor *ts; + unsigned int i; + int err, irq; + + ts = devm_kzalloc(&pdev->dev, sizeof(*ts), GFP_KERNEL); + if (!ts) + return -ENOMEM; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + ts->dev = &pdev->dev; + platform_set_drvdata(pdev, ts); + + ts->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(ts->regs)) + return PTR_ERR(ts->regs); + + ts->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(ts->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(ts->clk), + "failed to get clock\n"); + + ts->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL); + if (IS_ERR(ts->rst)) + return dev_err_probe(&pdev->dev, PTR_ERR(ts->rst), + "failed to get reset control\n"); + + err = tegra_tsensor_nvmem_setup(ts); + if (err) + return err; + + err = tegra_tsensor_hw_enable(ts); + if (err) + return err; + + err = devm_add_action_or_reset(&pdev->dev, + devm_tegra_tsensor_hw_disable, + ts); + if (err) + return err; + + for (i = 0; i < ARRAY_SIZE(ts->ch); i++) { + err = tegra_tsensor_register_channel(ts, i); + if (err) + return err; + } + + err = devm_request_threaded_irq(&pdev->dev, irq, NULL, + tegra_tsensor_isr, IRQF_ONESHOT, + "tegra_tsensor", ts); + if (err) + return dev_err_probe(&pdev->dev, err, + "failed to request interrupt\n"); + + for (i = 0; i < ARRAY_SIZE(ts->ch); i++) { + err = tegra_tsensor_enable_hw_channel(ts, i); + if (err) + return err; + } + + return 0; +} + +static int __maybe_unused tegra_tsensor_suspend(struct device *dev) +{ + struct tegra_tsensor *ts = dev_get_drvdata(dev); + unsigned int i; + int err; + + for (i = 0; i < ARRAY_SIZE(ts->ch); i++) { + err = tegra_tsensor_disable_hw_channel(ts, i); + if (err) + goto enable_channel; + } + + err = tegra_tsensor_hw_disable(ts); + if (err) + goto enable_channel; + + return 0; + +enable_channel: + while (i--) + tegra_tsensor_enable_hw_channel(ts, i); + + return err; +} + +static int __maybe_unused tegra_tsensor_resume(struct device *dev) +{ + struct tegra_tsensor *ts = dev_get_drvdata(dev); + unsigned int i; + int err; + + err = tegra_tsensor_hw_enable(ts); + if (err) + return err; + + for (i = 0; i < ARRAY_SIZE(ts->ch); i++) { + err = tegra_tsensor_enable_hw_channel(ts, i); + if (err) + return err; + } + + return 0; +} + +static const struct dev_pm_ops tegra_tsensor_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(tegra_tsensor_suspend, + tegra_tsensor_resume) +}; + +static const struct of_device_id tegra_tsensor_of_match[] = { + { .compatible = "nvidia,tegra30-tsensor", }, + {}, +}; +MODULE_DEVICE_TABLE(of, tegra_tsensor_of_match); + +static struct platform_driver tegra_tsensor_driver = { + .probe = tegra_tsensor_probe, + .driver = { + .name = "tegra30-tsensor", + .of_match_table = tegra_tsensor_of_match, + .pm = &tegra_tsensor_pm_ops, + }, +}; +module_platform_driver(tegra_tsensor_driver); + +MODULE_DESCRIPTION("NVIDIA Tegra30 Thermal Sensor driver"); +MODULE_AUTHOR("Dmitry Osipenko "); +MODULE_LICENSE("GPL"); From 8f8d8b0334cc4e7908b78e73936a7673bbef0411 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Thu, 17 Jun 2021 10:24:03 +0300 Subject: [PATCH 129/696] thermal/drivers/tegra: Correct compile-testing of drivers All Tegra thermal drivers support compile-testing, but the drivers are not available for compile-testing because the whole Kconfig meny entry depends on ARCH_TEGRA, missing the alternative COMPILE_TEST dependency option. Correct the Kconfig entry. Signed-off-by: Dmitry Osipenko Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20210617072403.3487-1-digetx@gmail.com --- drivers/thermal/tegra/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/thermal/tegra/Kconfig b/drivers/thermal/tegra/Kconfig index 019e3a2eb69e..cfa41d87a794 100644 --- a/drivers/thermal/tegra/Kconfig +++ b/drivers/thermal/tegra/Kconfig @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only menu "NVIDIA Tegra thermal drivers" -depends on ARCH_TEGRA +depends on ARCH_TEGRA || COMPILE_TEST config TEGRA_SOCTHERM tristate "Tegra SOCTHERM thermal management" From 02d438f62c05f0d055ceeedf12a2f8796b258c08 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 10 Aug 2021 11:44:13 +0300 Subject: [PATCH 130/696] thermal/drivers/exynos: Fix an error code in exynos_tmu_probe() This error path return success but it should propagate the negative error code from devm_clk_get(). Fixes: 6c247393cfdd ("thermal: exynos: Add TMU support for Exynos7 SoC") Signed-off-by: Dan Carpenter Reviewed-by: Krzysztof Kozlowski Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20210810084413.GA23810@kili --- drivers/thermal/samsung/exynos_tmu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c index e9a90bc23b11..f4ab4c5b4b62 100644 --- a/drivers/thermal/samsung/exynos_tmu.c +++ b/drivers/thermal/samsung/exynos_tmu.c @@ -1073,6 +1073,7 @@ static int exynos_tmu_probe(struct platform_device *pdev) data->sclk = devm_clk_get(&pdev->dev, "tmu_sclk"); if (IS_ERR(data->sclk)) { dev_err(&pdev->dev, "Failed to get sclk\n"); + ret = PTR_ERR(data->sclk); goto err_clk; } else { ret = clk_prepare_enable(data->sclk); From a414a08aefe6343492b812a50a1b2f3a30ce8b6e Mon Sep 17 00:00:00 2001 From: Sumeet Pawnikar Date: Mon, 9 Aug 2021 17:26:35 +0530 Subject: [PATCH 131/696] drivers/thermal/intel: Add TCC cooling support for AlderLake platform Add tcc cooling support for the AlderLake platform. Signed-off-by: Sumeet Pawnikar Reviewed-by: Zhang Rui Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20210809115635.10100-1-sumeet.r.pawnikar@intel.com --- drivers/thermal/intel/intel_tcc_cooling.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/thermal/intel/intel_tcc_cooling.c b/drivers/thermal/intel/intel_tcc_cooling.c index 8ec10d55d421..cd80c7db4073 100644 --- a/drivers/thermal/intel/intel_tcc_cooling.c +++ b/drivers/thermal/intel/intel_tcc_cooling.c @@ -79,6 +79,8 @@ static const struct x86_cpu_id tcc_ids[] __initconst = { X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE, NULL), X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE_L, NULL), X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE, NULL), + X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE, NULL), + X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_L, NULL), {} }; From 47cf09e0f4fc51200ecea15387bec3584562f55d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Date: Wed, 4 Aug 2021 11:18:17 +0200 Subject: [PATCH 132/696] thermal/drivers/rcar_gen3_thermal: Add support for hardware trip points MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All supported hardware except V3U is capable of generating interrupts to the CPU when the temperature go below or above a set value. Use this to implement support for the set_trip() feature of the thermal core on supported hardware. The V3U have its interrupts routed to the ECM module and therefore can not be used to implement set_trip() as the driver can't be made aware of when the interrupt triggers. Each TSC is capable of tracking up-to three different temperatures while only two are needed to implement the tracking of the thermal window. Signed-off-by: Niklas Söderlund Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20210804091818.2196806-2-niklas.soderlund+renesas@ragnatech.se --- drivers/thermal/rcar_gen3_thermal.c | 103 ++++++++++++++++++++++++++-- 1 file changed, 99 insertions(+), 4 deletions(-) diff --git a/drivers/thermal/rcar_gen3_thermal.c b/drivers/thermal/rcar_gen3_thermal.c index fdf16aa34eb4..e49593437ede 100644 --- a/drivers/thermal/rcar_gen3_thermal.c +++ b/drivers/thermal/rcar_gen3_thermal.c @@ -190,10 +190,64 @@ static int rcar_gen3_thermal_get_temp(void *devdata, int *temp) return 0; } -static const struct thermal_zone_of_device_ops rcar_gen3_tz_of_ops = { +static int rcar_gen3_thermal_mcelsius_to_temp(struct rcar_gen3_thermal_tsc *tsc, + int mcelsius) +{ + int celsius, val; + + celsius = DIV_ROUND_CLOSEST(mcelsius, 1000); + if (celsius <= INT_FIXPT(tsc->tj_t)) + val = celsius * tsc->coef.a1 + tsc->coef.b1; + else + val = celsius * tsc->coef.a2 + tsc->coef.b2; + + return INT_FIXPT(val); +} + +static int rcar_gen3_thermal_set_trips(void *devdata, int low, int high) +{ + struct rcar_gen3_thermal_tsc *tsc = devdata; + u32 irqmsk = 0; + + if (low != -INT_MAX) { + irqmsk |= IRQ_TEMPD1; + rcar_gen3_thermal_write(tsc, REG_GEN3_IRQTEMP1, + rcar_gen3_thermal_mcelsius_to_temp(tsc, low)); + } + + if (high != INT_MAX) { + irqmsk |= IRQ_TEMP2; + rcar_gen3_thermal_write(tsc, REG_GEN3_IRQTEMP2, + rcar_gen3_thermal_mcelsius_to_temp(tsc, high)); + } + + rcar_gen3_thermal_write(tsc, REG_GEN3_IRQMSK, irqmsk); + + return 0; +} + +static struct thermal_zone_of_device_ops rcar_gen3_tz_of_ops = { .get_temp = rcar_gen3_thermal_get_temp, + .set_trips = rcar_gen3_thermal_set_trips, }; +static irqreturn_t rcar_gen3_thermal_irq(int irq, void *data) +{ + struct rcar_gen3_thermal_priv *priv = data; + unsigned int i; + u32 status; + + for (i = 0; i < priv->num_tscs; i++) { + status = rcar_gen3_thermal_read(priv->tscs[i], REG_GEN3_IRQSTR); + rcar_gen3_thermal_write(priv->tscs[i], REG_GEN3_IRQSTR, 0); + if (status) + thermal_zone_device_update(priv->tscs[i]->zone, + THERMAL_EVENT_UNSPECIFIED); + } + + return IRQ_HANDLED; +} + static const struct soc_device_attribute r8a7795es1[] = { { .soc_id = "r8a7795", .revision = "ES1.*" }, { /* sentinel */ } @@ -210,6 +264,9 @@ static void rcar_gen3_thermal_init_r8a7795es1(struct rcar_gen3_thermal_tsc *tsc) rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0x3F); rcar_gen3_thermal_write(tsc, REG_GEN3_IRQMSK, 0); + if (tsc->zone->ops->set_trips) + rcar_gen3_thermal_write(tsc, REG_GEN3_IRQEN, + IRQ_TEMPD1 | IRQ_TEMP2); rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR, CTSR_PONM | CTSR_AOUT | CTSR_THBGR | CTSR_VMEN); @@ -235,6 +292,9 @@ static void rcar_gen3_thermal_init(struct rcar_gen3_thermal_tsc *tsc) rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0); rcar_gen3_thermal_write(tsc, REG_GEN3_IRQMSK, 0); + if (tsc->zone->ops->set_trips) + rcar_gen3_thermal_write(tsc, REG_GEN3_IRQEN, + IRQ_TEMPD1 | IRQ_TEMP2); reg_val = rcar_gen3_thermal_read(tsc, REG_GEN3_THCTR); reg_val |= THCTR_THSST; @@ -303,6 +363,34 @@ static void rcar_gen3_hwmon_action(void *data) thermal_remove_hwmon_sysfs(zone); } +static int rcar_gen3_thermal_request_irqs(struct rcar_gen3_thermal_priv *priv, + struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + unsigned int i; + char *irqname; + int ret, irq; + + for (i = 0; i < 2; i++) { + irq = platform_get_irq_optional(pdev, i); + if (irq < 0) + return irq; + + irqname = devm_kasprintf(dev, GFP_KERNEL, "%s:ch%d", + dev_name(dev), i); + if (!irqname) + return -ENOMEM; + + ret = devm_request_threaded_irq(dev, irq, NULL, + rcar_gen3_thermal_irq, + IRQF_ONESHOT, irqname, priv); + if (ret) + return ret; + } + + return 0; +} + static int rcar_gen3_thermal_probe(struct platform_device *pdev) { struct rcar_gen3_thermal_priv *priv; @@ -326,6 +414,9 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) platform_set_drvdata(pdev, priv); + if (rcar_gen3_thermal_request_irqs(priv, pdev)) + rcar_gen3_tz_of_ops.set_trips = NULL; + pm_runtime_enable(dev); pm_runtime_get_sync(dev); @@ -351,9 +442,6 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) priv->tscs[i] = tsc; - priv->thermal_init(tsc); - rcar_gen3_thermal_calc_coefs(tsc, ptat, thcodes[i], *ths_tj_1); - zone = devm_thermal_zone_of_sensor_register(dev, i, tsc, &rcar_gen3_tz_of_ops); if (IS_ERR(zone)) { @@ -363,6 +451,9 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) } tsc->zone = zone; + priv->thermal_init(tsc); + rcar_gen3_thermal_calc_coefs(tsc, ptat, thcodes[i], *ths_tj_1); + tsc->zone->tzp->no_hwmon = false; ret = thermal_add_hwmon_sysfs(tsc->zone); if (ret) @@ -401,8 +492,12 @@ static int __maybe_unused rcar_gen3_thermal_resume(struct device *dev) for (i = 0; i < priv->num_tscs; i++) { struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i]; + struct thermal_zone_device *zone = tsc->zone; priv->thermal_init(tsc); + if (zone->ops->set_trips) + rcar_gen3_thermal_set_trips(tsc, zone->prev_low_trip, + zone->prev_high_trip); } return 0; From d3a2328e741bf6e9e6bda750e0a63832fa365a74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20S=C3=B6derlund?= Date: Wed, 4 Aug 2021 11:18:18 +0200 Subject: [PATCH 133/696] thermal/drivers/rcar_gen3_thermal: Store TSC id as unsigned int MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The TSC id and number of TSC ids should be stored as unsigned int as they can't be negative. Fix the datatype of the loop counter 'i' and rcar_gen3_thermal_tsc.id to reflect this. Signed-off-by: Niklas Söderlund Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20210804091818.2196806-3-niklas.soderlund+renesas@ragnatech.se --- drivers/thermal/rcar_gen3_thermal.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/thermal/rcar_gen3_thermal.c b/drivers/thermal/rcar_gen3_thermal.c index e49593437ede..85228d308dd3 100644 --- a/drivers/thermal/rcar_gen3_thermal.c +++ b/drivers/thermal/rcar_gen3_thermal.c @@ -84,7 +84,7 @@ struct rcar_gen3_thermal_tsc { struct thermal_zone_device *zone; struct equation_coefs coef; int tj_t; - int id; /* thermal channel id */ + unsigned int id; /* thermal channel id */ }; struct rcar_gen3_thermal_priv { @@ -398,7 +398,8 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) const int *ths_tj_1 = of_device_get_match_data(dev); struct resource *res; struct thermal_zone_device *zone; - int ret, i; + unsigned int i; + int ret; /* default values if FUSEs are missing */ /* TODO: Read values from hardware on supported platforms */ @@ -467,7 +468,7 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) if (ret < 0) goto error_unregister; - dev_info(dev, "TSC%d: Loaded %d trip points\n", i, ret); + dev_info(dev, "TSC%u: Loaded %d trip points\n", i, ret); } priv->num_tscs = i; From d31eb7c1a2288f61df75558f59328be01a264300 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Tue, 3 Aug 2021 16:16:02 +0200 Subject: [PATCH 134/696] thermal/drivers/intel_powerclamp: Replace deprecated CPU-hotplug functions. The functions get_online_cpus() and put_online_cpus() have been deprecated during the CPU hotplug rework. They map directly to cpus_read_lock() and cpus_read_unlock(). Replace deprecated CPU-hotplug functions with the official version. The behavior remains unchanged. Cc: Zhang Rui Cc: Daniel Lezcano Cc: Amit Kucheria Cc: linux-pm@vger.kernel.org Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20210803141621.780504-20-bigeasy@linutronix.de --- drivers/thermal/intel/intel_powerclamp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/thermal/intel/intel_powerclamp.c b/drivers/thermal/intel/intel_powerclamp.c index b0eb5ece9243..a5b58ea89cc6 100644 --- a/drivers/thermal/intel/intel_powerclamp.c +++ b/drivers/thermal/intel/intel_powerclamp.c @@ -528,7 +528,7 @@ static int start_power_clamp(void) set_target_ratio = clamp(set_target_ratio, 0U, MAX_TARGET_RATIO - 1); /* prevent cpu hotplug */ - get_online_cpus(); + cpus_read_lock(); /* prefer BSP */ control_cpu = 0; @@ -542,7 +542,7 @@ static int start_power_clamp(void) for_each_online_cpu(cpu) { start_power_clamp_worker(cpu); } - put_online_cpus(); + cpus_read_unlock(); return 0; } From 21c1e439fd864828b58f783641b3736197ccc813 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Sat, 14 Aug 2021 13:14:07 +0200 Subject: [PATCH 135/696] MAINTAINERS: Add missing userspace thermal tools to the thermal section Patches related to the tmon which is in tools/thermal are floating around since years because it is unclear who takes care of it. Add the missing userspace tools directory related to thermal to fix the situation. Signed-off-by: Daniel Lezcano --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index a61f4f3b78a9..a78f490fd128 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18358,6 +18358,7 @@ F: drivers/thermal/ F: include/linux/cpu_cooling.h F: include/linux/thermal.h F: include/uapi/linux/thermal.h +F: tools/thermal/ THERMAL DRIVER FOR AMLOGIC SOCS M: Guillaume La Roque From 99d88c30055376b56316d3c431c9873e88208348 Mon Sep 17 00:00:00 2001 From: Rolf Eike Beer Date: Fri, 30 Jul 2021 13:49:04 +0200 Subject: [PATCH 136/696] thermal/tools/tmon: Improve the Makefile - Remove empty macros assignments - Use directory creation parameter for the install tool - Use $OBJ instead of building the list of object for the 'clean' target [dlezcano] : Changed title and description Signed-off-by: Rolf Eike Beer Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/1951386.ZPQrlMDjM2@devpool47 --- tools/thermal/tmon/Makefile | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tools/thermal/tmon/Makefile b/tools/thermal/tmon/Makefile index 9db867df7679..3e650878ea82 100644 --- a/tools/thermal/tmon/Makefile +++ b/tools/thermal/tmon/Makefile @@ -13,7 +13,6 @@ CC?= $(CROSS_COMPILE)gcc PKG_CONFIG?= pkg-config override CFLAGS+=-D VERSION=\"$(VERSION)\" -LDFLAGS+= TARGET=tmon INSTALL_PROGRAM=install -m 755 -p @@ -33,7 +32,6 @@ override CFLAGS += $(shell $(PKG_CONFIG) --cflags $(STATIC) panelw ncursesw 2> / $(PKG_CONFIG) --cflags $(STATIC) panel ncurses 2> /dev/null) OBJS = tmon.o tui.o sysfs.o pid.o -OBJS += tmon: $(OBJS) Makefile tmon.h $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) -o $(TARGET) $(TMON_LIBS) @@ -42,15 +40,13 @@ valgrind: tmon sudo valgrind -v --track-origins=yes --tool=memcheck --leak-check=yes --show-reachable=yes --num-callers=20 --track-fds=yes ./$(TARGET) 1> /dev/null install: - - mkdir -p $(INSTALL_ROOT)/$(BINDIR) - - $(INSTALL_PROGRAM) "$(TARGET)" "$(INSTALL_ROOT)/$(BINDIR)/$(TARGET)" + - $(INSTALL_PROGRAM) -D "$(TARGET)" "$(INSTALL_ROOT)/$(BINDIR)/$(TARGET)" uninstall: $(DEL_FILE) "$(INSTALL_ROOT)/$(BINDIR)/$(TARGET)" clean: - find . -name "*.o" | xargs $(DEL_FILE) - rm -f $(TARGET) + rm -f $(TARGET) $(OBJS) dist: git tag v$(VERSION) From b5f7912bb604b47a0fe024560488a7556dce8ee7 Mon Sep 17 00:00:00 2001 From: Rolf Eike Beer Date: Fri, 30 Jul 2021 13:51:54 +0200 Subject: [PATCH 137/696] tools/thermal/tmon: Add cross compiling support Default to prefixed pkg-config when crosscompiling, this matches what other parts of the tools/ directory already do. [dlezcano] : Reworked description Signed-off-by: Rolf Eike Beer Cc: stable@vger.kernel.org Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/31302992.qZodDJZGDc@devpool47 --- tools/thermal/tmon/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/thermal/tmon/Makefile b/tools/thermal/tmon/Makefile index 3e650878ea82..f9c52b7fab7b 100644 --- a/tools/thermal/tmon/Makefile +++ b/tools/thermal/tmon/Makefile @@ -10,7 +10,7 @@ override CFLAGS+= $(call cc-option,-O3,-O1) ${WARNFLAGS} # Add "-fstack-protector" only if toolchain supports it. override CFLAGS+= $(call cc-option,-fstack-protector-strong) CC?= $(CROSS_COMPILE)gcc -PKG_CONFIG?= pkg-config +PKG_CONFIG?= $(CROSS_COMPILE)pkg-config override CFLAGS+=-D VERSION=\"$(VERSION)\" TARGET=tmon From f1b07a14694be02b2b87e2fe6def6cff2f4bd452 Mon Sep 17 00:00:00 2001 From: Sumeet Pawnikar Date: Fri, 16 Jul 2021 22:09:46 +0530 Subject: [PATCH 138/696] thermal/drivers/int340x: Use IMOK independently Some chrome platform requires IMOK method in coreboot. But these platforms don't use GDDV data vault in coreboot. As per current code flow, to enable and use IMOK only, we need to have GDDV support as well in coreboot. This patch removes the dependency for IMOK from GDDV to enable and use IMOK independently. Signed-off-by: Sumeet Pawnikar Acked-by: Srinivas Pandruvada Acked-by: Zhang Rui Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20210716163946.3142-1-sumeet.r.pawnikar@intel.com --- .../intel/int340x_thermal/int3400_thermal.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c index 823354a1a91a..19926beeb3b7 100644 --- a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c +++ b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c @@ -108,9 +108,12 @@ static struct attribute *imok_attr[] = { NULL }; +static const struct attribute_group imok_attribute_group = { + .attrs = imok_attr, +}; + static const struct attribute_group data_attribute_group = { .bin_attrs = data_attributes, - .attrs = imok_attr, }; static ssize_t available_uuids_show(struct device *dev, @@ -522,6 +525,12 @@ static int int3400_thermal_probe(struct platform_device *pdev) if (result) goto free_rel_misc; + if (acpi_has_method(priv->adev->handle, "IMOK")) { + result = sysfs_create_group(&pdev->dev.kobj, &imok_attribute_group); + if (result) + goto free_imok; + } + if (priv->data_vault) { result = sysfs_create_group(&pdev->dev.kobj, &data_attribute_group); @@ -545,6 +554,8 @@ free_sysfs: } free_uuid: sysfs_remove_group(&pdev->dev.kobj, &uuid_attribute_group); +free_imok: + sysfs_remove_group(&pdev->dev.kobj, &imok_attribute_group); free_rel_misc: if (!priv->rel_misc_dev_res) acpi_thermal_rel_misc_device_remove(priv->adev->handle); @@ -573,6 +584,7 @@ static int int3400_thermal_remove(struct platform_device *pdev) if (priv->data_vault) sysfs_remove_group(&pdev->dev.kobj, &data_attribute_group); sysfs_remove_group(&pdev->dev.kobj, &uuid_attribute_group); + sysfs_remove_group(&pdev->dev.kobj, &imok_attribute_group); thermal_zone_device_unregister(priv->thermal); kfree(priv->data_vault); kfree(priv->trts); From fb83610762dd5927212aa62a468dd3b756b57a88 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 22 Jul 2021 11:06:44 +0200 Subject: [PATCH 139/696] thermal/core: Fix thermal_cooling_device_register() prototype There are two pairs of declarations for thermal_cooling_device_register() and thermal_of_cooling_device_register(), and only one set was changed in a recent patch, so the other one now causes a compile-time warning: drivers/net/wireless/mediatek/mt76/mt7915/init.c: In function 'mt7915_thermal_init': drivers/net/wireless/mediatek/mt76/mt7915/init.c:134:48: error: passing argument 1 of 'thermal_cooling_device_register' discards 'const' qualifier from pointer target type [-Werror=discarded-qualifiers] 134 | cdev = thermal_cooling_device_register(wiphy_name(wiphy), phy, | ^~~~~~~~~~~~~~~~~ In file included from drivers/net/wireless/mediatek/mt76/mt7915/init.c:7: include/linux/thermal.h:407:39: note: expected 'char *' but argument is of type 'const char *' 407 | thermal_cooling_device_register(char *type, void *devdata, | ~~~~~~^~~~ Change the dummy helper functions to have the same arguments as the normal version. Fixes: f991de53a8ab ("thermal: make device_register's type argument const") Signed-off-by: Arnd Bergmann Reviewed-by: Jean-Francois Dagenais Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20210722090717.1116748-1-arnd@kernel.org --- include/linux/thermal.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/linux/thermal.h b/include/linux/thermal.h index d296f3b88fb9..8050d929a5b4 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h @@ -404,12 +404,13 @@ static inline void thermal_zone_device_unregister( struct thermal_zone_device *tz) { } static inline struct thermal_cooling_device * -thermal_cooling_device_register(char *type, void *devdata, +thermal_cooling_device_register(const char *type, void *devdata, const struct thermal_cooling_device_ops *ops) { return ERR_PTR(-ENODEV); } static inline struct thermal_cooling_device * thermal_of_cooling_device_register(struct device_node *np, - char *type, void *devdata, const struct thermal_cooling_device_ops *ops) + const char *type, void *devdata, + const struct thermal_cooling_device_ops *ops) { return ERR_PTR(-ENODEV); } static inline struct thermal_cooling_device * devm_thermal_of_cooling_device_register(struct device *dev, From 22fc857538c3a256563bb796f978b6d4693f5aa3 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 21 Jul 2021 16:04:03 +0200 Subject: [PATCH 140/696] dt-bindings: thermal: Make trips node optional Even though the previous binding made it a required child node, the implementation in Linux never made it mandatory and just ignored thermal zones without trip points. This was even effectively encouraged, since the thermal core wouldn't allow a thermal sensor to probe without a thermal zone. In the case where you had a thermal device that had multiple sensors but with enough knowledge to provide trip points for only a few of them, this meant that the only way to make that driver probe was to provide a thermal zone without the trips node required by the binding. This obviously led to a fair number of device trees doing exactly that, making the initial binding requirement ineffective. Let's make it clear by dropping that requirement. Cc: Amit Kucheria Cc: Daniel Lezcano Cc: linux-pm@vger.kernel.org Cc: Zhang Rui Signed-off-by: Maxime Ripard Reviewed-by: Rob Herring Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20210721140424.725744-34-maxime@cerno.tech --- Documentation/devicetree/bindings/thermal/thermal-zones.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/thermal/thermal-zones.yaml b/Documentation/devicetree/bindings/thermal/thermal-zones.yaml index 164f71598c59..a07de5ed0ca6 100644 --- a/Documentation/devicetree/bindings/thermal/thermal-zones.yaml +++ b/Documentation/devicetree/bindings/thermal/thermal-zones.yaml @@ -215,7 +215,7 @@ patternProperties: - polling-delay - polling-delay-passive - thermal-sensors - - trips + additionalProperties: false additionalProperties: false From 454f2ed4b34f9ef5726d080b1eb5dc47a7f36d6f Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 14 Jul 2021 13:27:01 +0200 Subject: [PATCH 141/696] thermal: Spelling s/scallbacks/callbacks/ Fix a misspelling of the word "callbacks". Signed-off-by: Geert Uytterhoeven Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/ae38372996a23bb67769e2d62ca170ae9457c4df.1626261946.git.geert+renesas@glider.be --- include/linux/thermal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/thermal.h b/include/linux/thermal.h index 8050d929a5b4..c314893970b3 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h @@ -285,7 +285,7 @@ struct thermal_zone_params { }; /** - * struct thermal_zone_of_device_ops - scallbacks for handling DT based zones + * struct thermal_zone_of_device_ops - callbacks for handling DT based zones * * Mandatory: * @get_temp: a pointer to a function that reads the sensor temperature. From 16f944291a4ab896895e78934623b9d33af810cf Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 12 Jul 2021 03:23:53 +0300 Subject: [PATCH 142/696] thermal/drivers/tegra-soctherm: Silence message about clamped temperature The Tegra soctherm driver prints message about the clamped temperature trip each time when thermal core disables the low/high trip. The message is confusing and creates illusion that driver is malfunctioning. Turn that noisy info message into a debug message. Signed-off-by: Dmitry Osipenko Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20210712002353.17276-1-digetx@gmail.com --- drivers/thermal/tegra/soctherm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/thermal/tegra/soctherm.c b/drivers/thermal/tegra/soctherm.c index 8e303e9d1dc0..210325f92559 100644 --- a/drivers/thermal/tegra/soctherm.c +++ b/drivers/thermal/tegra/soctherm.c @@ -450,8 +450,8 @@ static int enforce_temp_range(struct device *dev, int trip_temp) temp = clamp_val(trip_temp, min_low_temp, max_high_temp); if (temp != trip_temp) - dev_info(dev, "soctherm: trip temperature %d forced to %d\n", - trip_temp, temp); + dev_dbg(dev, "soctherm: trip temperature %d forced to %d\n", + trip_temp, temp); return temp; } From bd4dadaf04ceafe02f0f397a31f18a5018418e9b Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Thu, 12 Aug 2021 15:34:42 -0500 Subject: [PATCH 143/696] drm/ttm: ttm_bo_device is now ttm_device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These names were changed in commit 8af8a109b34fa88b8b91f25d11485b37d37549c3 Author: Christian König Date: Thu Oct 1 14:51:40 2020 +0200 drm/ttm: device naming cleanup But he missed a couple of them. Signed-off-by: Jason Ekstrand Cc: Christian König Fixes: 8af8a109b34f ("drm/ttm: device naming cleanup") Link: https://patchwork.freedesktop.org/patch/msgid/20210812203443.1725307-1-jason@jlekstrand.net Reviewed-by: Christian König Signed-off-by: Christian König --- Documentation/gpu/drm-mm.rst | 2 +- include/drm/ttm/ttm_tt.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/gpu/drm-mm.rst b/Documentation/gpu/drm-mm.rst index d5a73fa2c9ef..8126beadc7df 100644 --- a/Documentation/gpu/drm-mm.rst +++ b/Documentation/gpu/drm-mm.rst @@ -37,7 +37,7 @@ TTM initialization This section is outdated. Drivers wishing to support TTM must pass a filled :c:type:`ttm_bo_driver -` structure to ttm_bo_device_init, together with an +` structure to ttm_device_init, together with an initialized global reference to the memory manager. The ttm_bo_driver structure contains several fields with function pointers for initializing the TTM, allocating and freeing memory, waiting for command diff --git a/include/drm/ttm/ttm_tt.h b/include/drm/ttm/ttm_tt.h index 818680c6a8ed..0d97967bf955 100644 --- a/include/drm/ttm/ttm_tt.h +++ b/include/drm/ttm/ttm_tt.h @@ -31,7 +31,7 @@ #include #include -struct ttm_bo_device; +struct ttm_device; struct ttm_tt; struct ttm_resource; struct ttm_buffer_object; From 80cbd8808f85017b8aff4b223db68926b470be12 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Thu, 12 Aug 2021 15:34:43 -0500 Subject: [PATCH 144/696] drm/ttm: Include pagemap.h from ttm_tt.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's needed for pgprot_t which is used in the header. Signed-off-by: Jason Ekstrand Cc: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20210812203443.1725307-2-jason@jlekstrand.net Reviewed-by: Christian König Signed-off-by: Christian König --- drivers/gpu/drm/ttm/ttm_tt.c | 1 - include/drm/ttm/ttm_tt.h | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index 24031a8acd2d..d5cd8b5dc0bf 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -32,7 +32,6 @@ #define pr_fmt(fmt) "[TTM] " fmt #include -#include #include #include #include diff --git a/include/drm/ttm/ttm_tt.h b/include/drm/ttm/ttm_tt.h index 0d97967bf955..b20e89d321b0 100644 --- a/include/drm/ttm/ttm_tt.h +++ b/include/drm/ttm/ttm_tt.h @@ -27,6 +27,7 @@ #ifndef _TTM_TT_H_ #define _TTM_TT_H_ +#include #include #include #include From 8d448fa0a8bb1c8d94eef7647edffe9ac81a281e Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sun, 8 Aug 2021 19:00:30 +0300 Subject: [PATCH 145/696] rtc: tps65910: Correct driver module alias The TPS65910 RTC driver module doesn't auto-load because of the wrong module alias that doesn't match the device name, fix it. Cc: stable@vger.kernel.org Reported-by: Anton Bambura Tested-by: Anton Bambura Signed-off-by: Dmitry Osipenko Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20210808160030.8556-1-digetx@gmail.com --- drivers/rtc/rtc-tps65910.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c index bc89c62ccb9b..75e4c2d777b9 100644 --- a/drivers/rtc/rtc-tps65910.c +++ b/drivers/rtc/rtc-tps65910.c @@ -467,6 +467,6 @@ static struct platform_driver tps65910_rtc_driver = { }; module_platform_driver(tps65910_rtc_driver); -MODULE_ALIAS("platform:rtc-tps65910"); +MODULE_ALIAS("platform:tps65910-rtc"); MODULE_AUTHOR("Venu Byravarasu "); MODULE_LICENSE("GPL"); From e1aba37569f0aa9c993f740828871e48eea79f98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Jo=C5=84czyk?= Date: Fri, 16 Jul 2021 23:04:37 +0200 Subject: [PATCH 146/696] rtc: cmos: remove stale REVISIT comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It appears mc146818_get_time() and mc146818_set_time() now correctly use the century register as specified in the ACPI FADT table. It is not clear what else could be done here. These comments were introduced by commit 7be2c7c96aff ("[PATCH] RTC framework driver for CMOS RTCs") in 2007, which originally referenced function get_rtc_time() in include/asm-generic/rtc.h . Signed-off-by: Mateusz Jończyk Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20210716210437.29622-1-mat.jonczyk@o2.pl --- drivers/rtc/rtc-cmos.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index 670fd8a2970e..eb15067a605e 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -229,19 +229,13 @@ static int cmos_read_time(struct device *dev, struct rtc_time *t) if (!pm_trace_rtc_valid()) return -EIO; - /* REVISIT: if the clock has a "century" register, use - * that instead of the heuristic in mc146818_get_time(). - * That'll make Y3K compatility (year > 2070) easy! - */ mc146818_get_time(t); return 0; } static int cmos_set_time(struct device *dev, struct rtc_time *t) { - /* REVISIT: set the "century" register if available - * - * NOTE: this ignores the issue whereby updating the seconds + /* NOTE: this ignores the issue whereby updating the seconds * takes effect exactly 500ms after we write the register. * (Also queueing and other delays before we get this far.) */ From f120e2e33ac8ba1adac4f59eaf1ae1705305158f Mon Sep 17 00:00:00 2001 From: Mathew McBride Date: Fri, 9 Jul 2021 04:45:17 +0000 Subject: [PATCH 147/696] rtc: rx8025: implement RX-8035 support The RX-8035 is a newer RTC from EPSON that is very similar to the RX-8025. The key difference is in the oscillation stop (XSTP) bit which is inverted on the RX-8035. Signed-off-by: Mathew McBride Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20210709044518.28769-2-matt@traverse.com.au --- drivers/rtc/rtc-rx8025.c | 46 +++++++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index c914091819ba..d38aaf08108c 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -60,14 +60,23 @@ #define RX8025_ADJ_DATA_MAX 62 #define RX8025_ADJ_DATA_MIN -62 +enum rx_model { + model_rx_unknown, + model_rx_8025, + model_rx_8035, + model_last +}; + static const struct i2c_device_id rx8025_id[] = { - { "rx8025", 0 }, + { "rx8025", model_rx_8025 }, + { "rx8035", model_rx_8035 }, { } }; MODULE_DEVICE_TABLE(i2c, rx8025_id); struct rx8025_data { struct rtc_device *rtc; + enum rx_model model; u8 ctrl1; }; @@ -100,10 +109,26 @@ static s32 rx8025_write_regs(const struct i2c_client *client, length, values); } +static int rx8025_is_osc_stopped(enum rx_model model, int ctrl2) +{ + int xstp = ctrl2 & RX8025_BIT_CTRL2_XST; + /* XSTP bit has different polarity on RX-8025 vs RX-8035. + * RX-8025: 0 == oscillator stopped + * RX-8035: 1 == oscillator stopped + */ + + if (model == model_rx_8025) + xstp = !xstp; + + return xstp; +} + static int rx8025_check_validity(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); + struct rx8025_data *drvdata = dev_get_drvdata(dev); int ctrl2; + int xstp; ctrl2 = rx8025_read_reg(client, RX8025_REG_CTRL2); if (ctrl2 < 0) @@ -117,7 +142,8 @@ static int rx8025_check_validity(struct device *dev) return -EINVAL; } - if (!(ctrl2 & RX8025_BIT_CTRL2_XST)) { + xstp = rx8025_is_osc_stopped(drvdata->model, ctrl2); + if (xstp) { dev_warn(dev, "crystal stopped, date is invalid\n"); return -EINVAL; } @@ -127,6 +153,7 @@ static int rx8025_check_validity(struct device *dev) static int rx8025_reset_validity(struct i2c_client *client) { + struct rx8025_data *drvdata = i2c_get_clientdata(client); int ctrl2 = rx8025_read_reg(client, RX8025_REG_CTRL2); if (ctrl2 < 0) @@ -134,22 +161,28 @@ static int rx8025_reset_validity(struct i2c_client *client) ctrl2 &= ~(RX8025_BIT_CTRL2_PON | RX8025_BIT_CTRL2_VDET); + if (drvdata->model == model_rx_8025) + ctrl2 |= RX8025_BIT_CTRL2_XST; + else + ctrl2 &= ~(RX8025_BIT_CTRL2_XST); + return rx8025_write_reg(client, RX8025_REG_CTRL2, - ctrl2 | RX8025_BIT_CTRL2_XST); + ctrl2); } static irqreturn_t rx8025_handle_irq(int irq, void *dev_id) { struct i2c_client *client = dev_id; struct rx8025_data *rx8025 = i2c_get_clientdata(client); - int status; + int status, xstp; rtc_lock(rx8025->rtc); status = rx8025_read_reg(client, RX8025_REG_CTRL2); if (status < 0) goto out; - if (!(status & RX8025_BIT_CTRL2_XST)) + xstp = rx8025_is_osc_stopped(rx8025->model, status); + if (xstp) dev_warn(&client->dev, "Oscillation stop was detected," "you may have to readjust the clock\n"); @@ -519,6 +552,9 @@ static int rx8025_probe(struct i2c_client *client, i2c_set_clientdata(client, rx8025); + if (id) + rx8025->model = id->driver_data; + err = rx8025_init_client(client); if (err) return err; From 8158da6a33f2656c2a98c30eb9185a44e215a6b6 Mon Sep 17 00:00:00 2001 From: Mathew McBride Date: Fri, 9 Jul 2021 04:45:18 +0000 Subject: [PATCH 148/696] dt-bindings: rtc: add Epson RX-8025 and RX-8035 These are supported by the rtc-rx8025 module. RX-8025 also has support in ds1307 due to compatible time registers. Signed-off-by: Mathew McBride Reviewed-by: Nobuhiro Iwamatsu Acked-by: Rob Herring Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20210709044518.28769-3-matt@traverse.com.au --- Documentation/devicetree/bindings/rtc/trivial-rtc.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml b/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml index 7548d8714871..13925bb78ec7 100644 --- a/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml +++ b/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml @@ -32,6 +32,9 @@ properties: - dallas,ds3232 # I2C-BUS INTERFACE REAL TIME CLOCK MODULE - epson,rx8010 + # I2C-BUS INTERFACE REAL TIME CLOCK MODULE + - epson,rx8025 + - epson,rx8035 # I2C-BUS INTERFACE REAL TIME CLOCK MODULE with Battery Backed RAM - epson,rx8571 # I2C-BUS INTERFACE REAL TIME CLOCK MODULE From de3438c47a8ddc75548e62a03736a9321c2b7bac Mon Sep 17 00:00:00 2001 From: Thara Gopinath Date: Mon, 9 Aug 2021 15:15:59 -0400 Subject: [PATCH 149/696] firmware: qcom_scm: Introduce SCM calls to access LMh Introduce SCM calls to access/configure limits management hardware(LMH). Reviewed-by: Bjorn Andersson Signed-off-by: Thara Gopinath Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20210809191605.3742979-2-thara.gopinath@linaro.org --- drivers/firmware/qcom_scm.c | 58 +++++++++++++++++++++++++++++++++++++ drivers/firmware/qcom_scm.h | 4 +++ include/linux/qcom_scm.h | 14 +++++++++ 3 files changed, 76 insertions(+) diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index 47ea2bd42b10..8a503753fe2a 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -1147,6 +1147,64 @@ int qcom_scm_qsmmu500_wait_safe_toggle(bool en) } EXPORT_SYMBOL(qcom_scm_qsmmu500_wait_safe_toggle); +bool qcom_scm_lmh_dcvsh_available(void) +{ + return __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_LMH, QCOM_SCM_LMH_LIMIT_DCVSH); +} +EXPORT_SYMBOL(qcom_scm_lmh_dcvsh_available); + +int qcom_scm_lmh_profile_change(u32 profile_id) +{ + struct qcom_scm_desc desc = { + .svc = QCOM_SCM_SVC_LMH, + .cmd = QCOM_SCM_LMH_LIMIT_PROFILE_CHANGE, + .arginfo = QCOM_SCM_ARGS(1, QCOM_SCM_VAL), + .args[0] = profile_id, + .owner = ARM_SMCCC_OWNER_SIP, + }; + + return qcom_scm_call(__scm->dev, &desc, NULL); +} +EXPORT_SYMBOL(qcom_scm_lmh_profile_change); + +int qcom_scm_lmh_dcvsh(u32 payload_fn, u32 payload_reg, u32 payload_val, + u64 limit_node, u32 node_id, u64 version) +{ + dma_addr_t payload_phys; + u32 *payload_buf; + int ret, payload_size = 5 * sizeof(u32); + + struct qcom_scm_desc desc = { + .svc = QCOM_SCM_SVC_LMH, + .cmd = QCOM_SCM_LMH_LIMIT_DCVSH, + .arginfo = QCOM_SCM_ARGS(5, QCOM_SCM_RO, QCOM_SCM_VAL, QCOM_SCM_VAL, + QCOM_SCM_VAL, QCOM_SCM_VAL), + .args[1] = payload_size, + .args[2] = limit_node, + .args[3] = node_id, + .args[4] = version, + .owner = ARM_SMCCC_OWNER_SIP, + }; + + payload_buf = dma_alloc_coherent(__scm->dev, payload_size, &payload_phys, GFP_KERNEL); + if (!payload_buf) + return -ENOMEM; + + payload_buf[0] = payload_fn; + payload_buf[1] = 0; + payload_buf[2] = payload_reg; + payload_buf[3] = 1; + payload_buf[4] = payload_val; + + desc.args[0] = payload_phys; + + ret = qcom_scm_call(__scm->dev, &desc, NULL); + + dma_free_coherent(__scm->dev, payload_size, payload_buf, payload_phys); + return ret; +} +EXPORT_SYMBOL(qcom_scm_lmh_dcvsh); + static int qcom_scm_find_dload_address(struct device *dev, u64 *addr) { struct device_node *tcsr; diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h index 632fe3142462..d92156ceb3ac 100644 --- a/drivers/firmware/qcom_scm.h +++ b/drivers/firmware/qcom_scm.h @@ -114,6 +114,10 @@ extern int scm_legacy_call(struct device *dev, const struct qcom_scm_desc *desc, #define QCOM_SCM_SVC_HDCP 0x11 #define QCOM_SCM_HDCP_INVOKE 0x01 +#define QCOM_SCM_SVC_LMH 0x13 +#define QCOM_SCM_LMH_LIMIT_PROFILE_CHANGE 0x01 +#define QCOM_SCM_LMH_LIMIT_DCVSH 0x10 + #define QCOM_SCM_SVC_SMMU_PROGRAM 0x15 #define QCOM_SCM_SMMU_CONFIG_ERRATA1 0x03 #define QCOM_SCM_SMMU_CONFIG_ERRATA1_CLIENT_ALL 0x02 diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h index 0165824c5128..c0475d1c9885 100644 --- a/include/linux/qcom_scm.h +++ b/include/linux/qcom_scm.h @@ -109,6 +109,12 @@ extern int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp); extern int qcom_scm_qsmmu500_wait_safe_toggle(bool en); + +extern int qcom_scm_lmh_dcvsh(u32 payload_fn, u32 payload_reg, u32 payload_val, + u64 limit_node, u32 node_id, u64 version); +extern int qcom_scm_lmh_profile_change(u32 profile_id); +extern bool qcom_scm_lmh_dcvsh_available(void); + #else #include @@ -170,5 +176,13 @@ static inline int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, static inline int qcom_scm_qsmmu500_wait_safe_toggle(bool en) { return -ENODEV; } + +static inline int qcom_scm_lmh_dcvsh(u32 payload_fn, u32 payload_reg, u32 payload_val, + u64 limit_node, u32 node_id, u64 version) + { return -ENODEV; } + +static inline int qcom_scm_lmh_profile_change(u32 profile_id) { return -ENODEV; } + +static inline bool qcom_scm_lmh_dcvsh_available(void) { return -ENODEV; } #endif #endif From 53bca371cdf7addc1e93e1b99285b3d3935685ec Mon Sep 17 00:00:00 2001 From: Thara Gopinath Date: Mon, 9 Aug 2021 15:16:00 -0400 Subject: [PATCH 150/696] thermal/drivers/qcom: Add support for LMh driver Driver enabling various pieces of Limits Management Hardware(LMh) for cpu cluster0 and cpu cluster1 namely kick starting monitoring of temperature, current, battery current violations, enabling reliability algorithm and setting up various temperature limits. The following has been explained in the cover letter. I am including this here so that this remains in the commit message as well. LMh is a hardware infrastructure on some Qualcomm SoCs that can enforce temperature and current limits as programmed by software for certain IPs like CPU. On many newer LMh is configured by firmware/TZ and no programming is needed from the kernel side. But on certain SoCs like sdm845 the firmware does not do a complete programming of the h/w. On such soc's kernel software has to explicitly set up the temperature limits and turn on various monitoring and enforcing algorithms on the hardware. Tested-by: Steev Klimaszewski # Lenovo Yoga C630 Signed-off-by: Thara Gopinath Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20210809191605.3742979-3-thara.gopinath@linaro.org --- drivers/thermal/qcom/Kconfig | 10 ++ drivers/thermal/qcom/Makefile | 1 + drivers/thermal/qcom/lmh.c | 232 ++++++++++++++++++++++++++++++++++ 3 files changed, 243 insertions(+) create mode 100644 drivers/thermal/qcom/lmh.c diff --git a/drivers/thermal/qcom/Kconfig b/drivers/thermal/qcom/Kconfig index 8d5ac2df26dc..7d942f71e532 100644 --- a/drivers/thermal/qcom/Kconfig +++ b/drivers/thermal/qcom/Kconfig @@ -31,3 +31,13 @@ config QCOM_SPMI_TEMP_ALARM trip points. The temperature reported by the thermal sensor reflects the real time die temperature if an ADC is present or an estimate of the temperature based upon the over temperature stage value. + +config QCOM_LMH + tristate "Qualcomm Limits Management Hardware" + depends on ARCH_QCOM + help + This enables initialization of Qualcomm limits management + hardware(LMh). LMh allows for hardware-enforced mitigation for cpus based on + input from temperature and current sensors. On many newer Qualcomm SoCs + LMh is configured in the firmware and this feature need not be enabled. + However, on certain SoCs like sdm845 LMh has to be configured from kernel. diff --git a/drivers/thermal/qcom/Makefile b/drivers/thermal/qcom/Makefile index 252ea7d9da0b..0fa2512042e7 100644 --- a/drivers/thermal/qcom/Makefile +++ b/drivers/thermal/qcom/Makefile @@ -5,3 +5,4 @@ qcom_tsens-y += tsens.o tsens-v2.o tsens-v1.o tsens-v0_1.o \ tsens-8960.o obj-$(CONFIG_QCOM_SPMI_ADC_TM5) += qcom-spmi-adc-tm5.o obj-$(CONFIG_QCOM_SPMI_TEMP_ALARM) += qcom-spmi-temp-alarm.o +obj-$(CONFIG_QCOM_LMH) += lmh.o diff --git a/drivers/thermal/qcom/lmh.c b/drivers/thermal/qcom/lmh.c new file mode 100644 index 000000000000..eafa7526eb8b --- /dev/null +++ b/drivers/thermal/qcom/lmh.c @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/* + * Copyright (C) 2021, Linaro Limited. All rights reserved. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define LMH_NODE_DCVS 0x44435653 +#define LMH_CLUSTER0_NODE_ID 0x6370302D +#define LMH_CLUSTER1_NODE_ID 0x6370312D + +#define LMH_SUB_FN_THERMAL 0x54484D4C +#define LMH_SUB_FN_CRNT 0x43524E54 +#define LMH_SUB_FN_REL 0x52454C00 +#define LMH_SUB_FN_BCL 0x42434C00 + +#define LMH_ALGO_MODE_ENABLE 0x454E424C +#define LMH_TH_HI_THRESHOLD 0x48494748 +#define LMH_TH_LOW_THRESHOLD 0x4C4F5700 +#define LMH_TH_ARM_THRESHOLD 0x41524D00 + +#define LMH_REG_DCVS_INTR_CLR 0x8 + +struct lmh_hw_data { + void __iomem *base; + struct irq_domain *domain; + int irq; +}; + +static irqreturn_t lmh_handle_irq(int hw_irq, void *data) +{ + struct lmh_hw_data *lmh_data = data; + int irq = irq_find_mapping(lmh_data->domain, 0); + + /* Call the cpufreq driver to handle the interrupt */ + if (irq) + generic_handle_irq(irq); + + return 0; +} + +static void lmh_enable_interrupt(struct irq_data *d) +{ + struct lmh_hw_data *lmh_data = irq_data_get_irq_chip_data(d); + + /* Clear the existing interrupt */ + writel(0xff, lmh_data->base + LMH_REG_DCVS_INTR_CLR); + enable_irq(lmh_data->irq); +} + +static void lmh_disable_interrupt(struct irq_data *d) +{ + struct lmh_hw_data *lmh_data = irq_data_get_irq_chip_data(d); + + disable_irq_nosync(lmh_data->irq); +} + +static struct irq_chip lmh_irq_chip = { + .name = "lmh", + .irq_enable = lmh_enable_interrupt, + .irq_disable = lmh_disable_interrupt +}; + +static int lmh_irq_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) +{ + struct lmh_hw_data *lmh_data = d->host_data; + + irq_set_chip_and_handler(irq, &lmh_irq_chip, handle_simple_irq); + irq_set_chip_data(irq, lmh_data); + + return 0; +} + +static const struct irq_domain_ops lmh_irq_ops = { + .map = lmh_irq_map, + .xlate = irq_domain_xlate_onecell, +}; + +static int lmh_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct device_node *cpu_node; + struct lmh_hw_data *lmh_data; + int temp_low, temp_high, temp_arm, cpu_id, ret; + u32 node_id; + + lmh_data = devm_kzalloc(dev, sizeof(*lmh_data), GFP_KERNEL); + if (!lmh_data) + return -ENOMEM; + + lmh_data->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(lmh_data->base)) + return PTR_ERR(lmh_data->base); + + cpu_node = of_parse_phandle(np, "cpus", 0); + if (!cpu_node) + return -EINVAL; + cpu_id = of_cpu_node_to_id(cpu_node); + of_node_put(cpu_node); + + ret = of_property_read_u32(np, "qcom,lmh-temp-high-millicelsius", &temp_high); + if (ret) { + dev_err(dev, "missing qcom,lmh-temp-high-millicelsius property\n"); + return ret; + } + + ret = of_property_read_u32(np, "qcom,lmh-temp-low-millicelsius", &temp_low); + if (ret) { + dev_err(dev, "missing qcom,lmh-temp-low-millicelsius property\n"); + return ret; + } + + ret = of_property_read_u32(np, "qcom,lmh-temp-arm-millicelsius", &temp_arm); + if (ret) { + dev_err(dev, "missing qcom,lmh-temp-arm-millicelsius property\n"); + return ret; + } + + /* + * Only sdm845 has lmh hardware currently enabled from hlos. If this is needed + * for other platforms, revisit this to check if the should be part + * of a dt match table. + */ + if (cpu_id == 0) { + node_id = LMH_CLUSTER0_NODE_ID; + } else if (cpu_id == 4) { + node_id = LMH_CLUSTER1_NODE_ID; + } else { + dev_err(dev, "Wrong CPU id associated with LMh node\n"); + return -EINVAL; + } + + if (!qcom_scm_lmh_dcvsh_available()) + return -EINVAL; + + ret = qcom_scm_lmh_dcvsh(LMH_SUB_FN_CRNT, LMH_ALGO_MODE_ENABLE, 1, + LMH_NODE_DCVS, node_id, 0); + if (ret) + dev_err(dev, "Error %d enabling current subfunction\n", ret); + + ret = qcom_scm_lmh_dcvsh(LMH_SUB_FN_REL, LMH_ALGO_MODE_ENABLE, 1, + LMH_NODE_DCVS, node_id, 0); + if (ret) + dev_err(dev, "Error %d enabling reliability subfunction\n", ret); + + ret = qcom_scm_lmh_dcvsh(LMH_SUB_FN_BCL, LMH_ALGO_MODE_ENABLE, 1, + LMH_NODE_DCVS, node_id, 0); + if (ret) + dev_err(dev, "Error %d enabling BCL subfunction\n", ret); + + ret = qcom_scm_lmh_dcvsh(LMH_SUB_FN_THERMAL, LMH_ALGO_MODE_ENABLE, 1, + LMH_NODE_DCVS, node_id, 0); + if (ret) { + dev_err(dev, "Error %d enabling thermal subfunction\n", ret); + return ret; + } + + ret = qcom_scm_lmh_profile_change(0x1); + if (ret) { + dev_err(dev, "Error %d changing profile\n", ret); + return ret; + } + + /* Set default thermal trips */ + ret = qcom_scm_lmh_dcvsh(LMH_SUB_FN_THERMAL, LMH_TH_ARM_THRESHOLD, temp_arm, + LMH_NODE_DCVS, node_id, 0); + if (ret) { + dev_err(dev, "Error setting thermal ARM threshold%d\n", ret); + return ret; + } + + ret = qcom_scm_lmh_dcvsh(LMH_SUB_FN_THERMAL, LMH_TH_HI_THRESHOLD, temp_high, + LMH_NODE_DCVS, node_id, 0); + if (ret) { + dev_err(dev, "Error setting thermal HI threshold%d\n", ret); + return ret; + } + + ret = qcom_scm_lmh_dcvsh(LMH_SUB_FN_THERMAL, LMH_TH_LOW_THRESHOLD, temp_low, + LMH_NODE_DCVS, node_id, 0); + if (ret) { + dev_err(dev, "Error setting thermal ARM threshold%d\n", ret); + return ret; + } + + lmh_data->irq = platform_get_irq(pdev, 0); + lmh_data->domain = irq_domain_add_linear(np, 1, &lmh_irq_ops, lmh_data); + if (!lmh_data->domain) { + dev_err(dev, "Error adding irq_domain\n"); + return -EINVAL; + } + + /* Disable the irq and let cpufreq enable it when ready to handle the interrupt */ + irq_set_status_flags(lmh_data->irq, IRQ_NOAUTOEN); + ret = devm_request_irq(dev, lmh_data->irq, lmh_handle_irq, + IRQF_ONESHOT | IRQF_NO_SUSPEND, + "lmh-irq", lmh_data); + if (ret) { + dev_err(dev, "Error %d registering irq %x\n", ret, lmh_data->irq); + irq_domain_remove(lmh_data->domain); + return ret; + } + + return 0; +} + +static const struct of_device_id lmh_table[] = { + { .compatible = "qcom,sdm845-lmh", }, + {} +}; +MODULE_DEVICE_TABLE(of, lmh_table); + +static struct platform_driver lmh_driver = { + .probe = lmh_probe, + .driver = { + .name = "qcom-lmh", + .of_match_table = lmh_table, + .suppress_bind_attrs = true, + }, +}; +module_platform_driver(lmh_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("QCOM LMh driver"); From 17d3d3a6146c72c7b2e1aa97191bbefce167e0ad Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Fri, 30 Jul 2021 18:26:34 +0800 Subject: [PATCH 151/696] drm/vc4: hdmi: make vc4_hdmi_codec_pdata static This symbol is not used outside of vc4_hdmi.c, so marks it static. Fix the following sparse warning: drivers/gpu/drm/vc4/vc4_hdmi.c:1479:25: warning: symbol 'vc4_hdmi_codec_pdata' was not declared. Should it be static? Reported-by: Abaci Robot Signed-off-by: Jiapeng Chong Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/1627640794-15718-1-git-send-email-jiapeng.chong@linux.alibaba.com --- drivers/gpu/drm/vc4/vc4_hdmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index b7dc32a0c9bb..4a1115043114 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -1462,7 +1462,7 @@ static const struct hdmi_codec_ops vc4_hdmi_codec_ops = { .audio_startup = vc4_hdmi_audio_startup, }; -struct hdmi_codec_pdata vc4_hdmi_codec_pdata = { +static struct hdmi_codec_pdata vc4_hdmi_codec_pdata = { .ops = &vc4_hdmi_codec_ops, .max_i2s_channels = 8, .i2s = 1, From 0284b52e85341e3cd4b70c8b2423fd23b8a003a8 Mon Sep 17 00:00:00 2001 From: Thara Gopinath Date: Mon, 9 Aug 2021 15:16:05 -0400 Subject: [PATCH 152/696] dt-bindings: thermal: Add dt binding for QCOM LMh Add dt binding documentation to describe Qualcomm Limits Management Hardware node. Signed-off-by: Thara Gopinath Reviewed-by: Rob Herring Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20210809191605.3742979-8-thara.gopinath@linaro.org --- .../devicetree/bindings/thermal/qcom-lmh.yaml | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 Documentation/devicetree/bindings/thermal/qcom-lmh.yaml diff --git a/Documentation/devicetree/bindings/thermal/qcom-lmh.yaml b/Documentation/devicetree/bindings/thermal/qcom-lmh.yaml new file mode 100644 index 000000000000..289e9a845600 --- /dev/null +++ b/Documentation/devicetree/bindings/thermal/qcom-lmh.yaml @@ -0,0 +1,82 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright 2021 Linaro Ltd. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/thermal/qcom-lmh.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Limits Management Hardware(LMh) + +maintainers: + - Thara Gopinath + +description: + Limits Management Hardware(LMh) is a hardware infrastructure on some + Qualcomm SoCs that can enforce temperature and current limits as + programmed by software for certain IPs like CPU. + +properties: + compatible: + enum: + - qcom,sdm845-lmh + + reg: + items: + - description: core registers + + interrupts: + maxItems: 1 + + '#interrupt-cells': + const: 1 + + interrupt-controller: true + + cpus: + description: + phandle of the first cpu in the LMh cluster + $ref: /schemas/types.yaml#/definitions/phandle + + qcom,lmh-temp-arm-millicelsius: + description: + An integer expressing temperature threshold at which the LMh thermal + FSM is engaged. + + qcom,lmh-temp-low-millicelsius: + description: + An integer expressing temperature threshold at which the state machine + will attempt to remove frequency throttling. + + qcom,lmh-temp-high-millicelsius: + description: + An integer expressing temperature threshold at which the state machine + will attempt to throttle the frequency. + +required: + - compatible + - reg + - interrupts + - '#interrupt-cells' + - interrupt-controller + - cpus + - qcom,lmh-temp-arm-millicelsius + - qcom,lmh-temp-low-millicelsius + - qcom,lmh-temp-high-millicelsius + +additionalProperties: false + +examples: + - | + #include + + lmh@17d70800 { + compatible = "qcom,sdm845-lmh"; + reg = <0x17d70800 0x400>; + interrupts = ; + cpus = <&CPU4>; + qcom,lmh-temp-arm-millicelsius = <65000>; + qcom,lmh-temp-low-millicelsius = <94500>; + qcom,lmh-temp-high-millicelsius = <95000>; + interrupt-controller; + #interrupt-cells = <1>; + }; From d03a493f6782b94b7002388d470cb583e061816a Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 17 Aug 2021 17:32:04 +0100 Subject: [PATCH 153/696] drm/mgag200: Fix uninitialized variable delta The variable delta is not initialized and this will cause unexpected behaviour with the comparison of tmpdelta < delta. Fix this by setting it to 0xffffffff. This matches the behaviour as in the similar function mgag200_pixpll_compute_g200se_04. v2: * move fix up by one line to align style with other functions * add additional tags from similar patch Signed-off-by: Colin Ian King Fixes: 2545ac960364 ("drm/mgag200: Abstract pixel PLL via struct mgag200_pll") Addresses-Coverity: ("Uninitialized scalar variable") Reviewed-by: Daniel Vetter Reviewed-by: Thomas Zimmermann Reported-by: kernel test robot Reported-by: Dan Carpenter Signed-off-by: Thomas Zimmermann Cc: Sam Ravnborg Cc: Dave Airlie Cc: dri-devel@lists.freedesktop.org Link: https://patchwork.freedesktop.org/patch/msgid/20210817163204.494166-1-colin.king@canonical.com --- drivers/gpu/drm/mgag200/mgag200_pll.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/mgag200/mgag200_pll.c b/drivers/gpu/drm/mgag200/mgag200_pll.c index 7c903cf19c0d..e9ae22b4f813 100644 --- a/drivers/gpu/drm/mgag200/mgag200_pll.c +++ b/drivers/gpu/drm/mgag200/mgag200_pll.c @@ -124,6 +124,7 @@ static int mgag200_pixpll_compute_g200se_00(struct mgag200_pll *pixpll, long clo unsigned int computed; m = n = p = s = 0; + delta = 0xffffffff; permitteddelta = clock * 5 / 1000; for (testp = 8; testp > 0; testp /= 2) { From 2423de2e6f4d8676b6f6e43dee437461023ca6a1 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 11 Aug 2021 08:30:18 +0100 Subject: [PATCH 154/696] ARM: 9115/1: mm/maccess: fix unaligned copy_{from,to}_kernel_nofault On machines such as ARMv5 that trap unaligned accesses, these two functions can be slow when each access needs to be emulated, or they might not work at all. Change them so that each loop is only used when both the src and dst pointers are naturally aligned. Reviewed-by: Christoph Hellwig Reviewed-by: Linus Walleij Signed-off-by: Arnd Bergmann Signed-off-by: Russell King (Oracle) --- mm/maccess.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/mm/maccess.c b/mm/maccess.c index 3bd70405f2d8..d3f1a1f0b1c1 100644 --- a/mm/maccess.c +++ b/mm/maccess.c @@ -24,13 +24,21 @@ bool __weak copy_from_kernel_nofault_allowed(const void *unsafe_src, long copy_from_kernel_nofault(void *dst, const void *src, size_t size) { + unsigned long align = 0; + + if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)) + align = (unsigned long)dst | (unsigned long)src; + if (!copy_from_kernel_nofault_allowed(src, size)) return -ERANGE; pagefault_disable(); - copy_from_kernel_nofault_loop(dst, src, size, u64, Efault); - copy_from_kernel_nofault_loop(dst, src, size, u32, Efault); - copy_from_kernel_nofault_loop(dst, src, size, u16, Efault); + if (!(align & 7)) + copy_from_kernel_nofault_loop(dst, src, size, u64, Efault); + if (!(align & 3)) + copy_from_kernel_nofault_loop(dst, src, size, u32, Efault); + if (!(align & 1)) + copy_from_kernel_nofault_loop(dst, src, size, u16, Efault); copy_from_kernel_nofault_loop(dst, src, size, u8, Efault); pagefault_enable(); return 0; @@ -50,10 +58,18 @@ EXPORT_SYMBOL_GPL(copy_from_kernel_nofault); long copy_to_kernel_nofault(void *dst, const void *src, size_t size) { + unsigned long align = 0; + + if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)) + align = (unsigned long)dst | (unsigned long)src; + pagefault_disable(); - copy_to_kernel_nofault_loop(dst, src, size, u64, Efault); - copy_to_kernel_nofault_loop(dst, src, size, u32, Efault); - copy_to_kernel_nofault_loop(dst, src, size, u16, Efault); + if (!(align & 7)) + copy_to_kernel_nofault_loop(dst, src, size, u64, Efault); + if (!(align & 3)) + copy_to_kernel_nofault_loop(dst, src, size, u32, Efault); + if (!(align & 1)) + copy_to_kernel_nofault_loop(dst, src, size, u16, Efault); copy_to_kernel_nofault_loop(dst, src, size, u8, Efault); pagefault_enable(); return 0; From 344179fc7ef427910de438affbf3703fed51fe5a Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 11 Aug 2021 08:30:19 +0100 Subject: [PATCH 155/696] ARM: 9106/1: traps: use get_kernel_nofault instead of set_fs() ARM uses set_fs() and __get_user() to allow the stack dumping code to access possibly invalid pointers carefully. These can be changed to the simpler get_kernel_nofault(), and allow the eventual removal of set_fs(). dump_instr() will print either kernel or user space pointers, depending on how it was called. For dump_mem(), I assume we are only interested in kernel pointers, and the only time that this is called with user_mode(regs)==true is when the regs themselves are unreliable as a result of the condition that caused the trap. Reviewed-by: Christoph Hellwig Reviewed-by: Linus Walleij Signed-off-by: Arnd Bergmann Signed-off-by: Russell King (Oracle) --- arch/arm/kernel/traps.c | 47 ++++++++++++++--------------------------- 1 file changed, 16 insertions(+), 31 deletions(-) diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 64308e3a5d0c..10dd3ef1f398 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -122,17 +122,8 @@ static void dump_mem(const char *lvl, const char *str, unsigned long bottom, unsigned long top) { unsigned long first; - mm_segment_t fs; int i; - /* - * We need to switch to kernel mode so that we can use __get_user - * to safely read from kernel space. Note that we now dump the - * code first, just in case the backtrace kills us. - */ - fs = get_fs(); - set_fs(KERNEL_DS); - printk("%s%s(0x%08lx to 0x%08lx)\n", lvl, str, bottom, top); for (first = bottom & ~31; first < top; first += 32) { @@ -145,7 +136,7 @@ static void dump_mem(const char *lvl, const char *str, unsigned long bottom, for (p = first, i = 0; i < 8 && p < top; i++, p += 4) { if (p >= bottom && p < top) { unsigned long val; - if (__get_user(val, (unsigned long *)p) == 0) + if (get_kernel_nofault(val, (unsigned long *)p)) sprintf(str + i * 9, " %08lx", val); else sprintf(str + i * 9, " ????????"); @@ -153,11 +144,9 @@ static void dump_mem(const char *lvl, const char *str, unsigned long bottom, } printk("%s%04lx:%s\n", lvl, first & 0xffff, str); } - - set_fs(fs); } -static void __dump_instr(const char *lvl, struct pt_regs *regs) +static void dump_instr(const char *lvl, struct pt_regs *regs) { unsigned long addr = instruction_pointer(regs); const int thumb = thumb_mode(regs); @@ -173,10 +162,20 @@ static void __dump_instr(const char *lvl, struct pt_regs *regs) for (i = -4; i < 1 + !!thumb; i++) { unsigned int val, bad; - if (thumb) - bad = get_user(val, &((u16 *)addr)[i]); - else - bad = get_user(val, &((u32 *)addr)[i]); + if (!user_mode(regs)) { + if (thumb) { + u16 val16; + bad = get_kernel_nofault(val16, &((u16 *)addr)[i]); + val = val16; + } else { + bad = get_kernel_nofault(val, &((u32 *)addr)[i]); + } + } else { + if (thumb) + bad = get_user(val, &((u16 *)addr)[i]); + else + bad = get_user(val, &((u32 *)addr)[i]); + } if (!bad) p += sprintf(p, i == 0 ? "(%0*x) " : "%0*x ", @@ -189,20 +188,6 @@ static void __dump_instr(const char *lvl, struct pt_regs *regs) printk("%sCode: %s\n", lvl, str); } -static void dump_instr(const char *lvl, struct pt_regs *regs) -{ - mm_segment_t fs; - - if (!user_mode(regs)) { - fs = get_fs(); - set_fs(KERNEL_DS); - __dump_instr(lvl, regs); - set_fs(fs); - } else { - __dump_instr(lvl, regs); - } -} - #ifdef CONFIG_ARM_UNWIND static inline void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk, const char *loglvl) From b6e47f3c11c17965acb2a12001af3b1cd5658f37 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 11 Aug 2021 08:30:20 +0100 Subject: [PATCH 156/696] ARM: 9109/1: oabi-compat: add epoll_pwait handler The epoll_wait() syscall has a special version for OABI compat mode to convert the arguments to the EABI structure layout of the kernel. However, the later epoll_pwait() syscall was added in arch/arm in linux-2.6.32 without this conversion. Use the same kind of handler for both. Fixes: 369842658a36 ("ARM: 5677/1: ARM support for TIF_RESTORE_SIGMASK/pselect6/ppoll/epoll_pwait") Cc: stable@vger.kernel.org Reviewed-by: Christoph Hellwig Signed-off-by: Arnd Bergmann Signed-off-by: Russell King (Oracle) --- arch/arm/kernel/sys_oabi-compat.c | 38 ++++++++++++++++++++++++++++--- arch/arm/tools/syscall.tbl | 2 +- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/arch/arm/kernel/sys_oabi-compat.c b/arch/arm/kernel/sys_oabi-compat.c index 075a2e0ed2c1..443203fafb6b 100644 --- a/arch/arm/kernel/sys_oabi-compat.c +++ b/arch/arm/kernel/sys_oabi-compat.c @@ -265,9 +265,8 @@ asmlinkage long sys_oabi_epoll_ctl(int epfd, int op, int fd, return do_epoll_ctl(epfd, op, fd, &kernel, false); } -asmlinkage long sys_oabi_epoll_wait(int epfd, - struct oabi_epoll_event __user *events, - int maxevents, int timeout) +static long do_oabi_epoll_wait(int epfd, struct oabi_epoll_event __user *events, + int maxevents, int timeout) { struct epoll_event *kbuf; struct oabi_epoll_event e; @@ -314,6 +313,39 @@ asmlinkage long sys_oabi_epoll_wait(int epfd, } #endif +SYSCALL_DEFINE4(oabi_epoll_wait, int, epfd, + struct oabi_epoll_event __user *, events, + int, maxevents, int, timeout) +{ + return do_oabi_epoll_wait(epfd, events, maxevents, timeout); +} + +/* + * Implement the event wait interface for the eventpoll file. It is the kernel + * part of the user space epoll_pwait(2). + */ +SYSCALL_DEFINE6(oabi_epoll_pwait, int, epfd, + struct oabi_epoll_event __user *, events, int, maxevents, + int, timeout, const sigset_t __user *, sigmask, + size_t, sigsetsize) +{ + int error; + + /* + * If the caller wants a certain signal mask to be set during the wait, + * we apply it here. + */ + error = set_user_sigmask(sigmask, sigsetsize); + if (error) + return error; + + error = do_oabi_epoll_wait(epfd, events, maxevents, timeout); + restore_saved_sigmask_unless(error == -EINTR); + + return error; +} +#endif + struct oabi_sembuf { unsigned short sem_num; short sem_op; diff --git a/arch/arm/tools/syscall.tbl b/arch/arm/tools/syscall.tbl index c5df1179fc5d..11d0b960b2c2 100644 --- a/arch/arm/tools/syscall.tbl +++ b/arch/arm/tools/syscall.tbl @@ -360,7 +360,7 @@ 343 common vmsplice sys_vmsplice 344 common move_pages sys_move_pages 345 common getcpu sys_getcpu -346 common epoll_pwait sys_epoll_pwait +346 common epoll_pwait sys_epoll_pwait sys_oabi_epoll_pwait 347 common kexec_load sys_kexec_load 348 common utimensat sys_utimensat_time32 349 common signalfd sys_signalfd From 4e57a4ddf6b0d9cce1cf2ffd153df1ad3c2c9cc2 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 11 Aug 2021 08:30:21 +0100 Subject: [PATCH 157/696] ARM: 9107/1: syscall: always store thread_info->abi_syscall The system call number is used in a a couple of places, in particular ptrace, seccomp and /proc//syscall. The last one apparently never worked reliably on ARM for tasks that are not currently getting traced. Storing the syscall number in the normal entry path makes it work, as well as allowing us to see if the current system call is for OABI compat mode, which is the next thing I want to hook into. Since the thread_info->syscall field is not just the number any more, it is now renamed to abi_syscall. In kernels that enable both OABI and EABI, the upper bits of this field encode 0x900000 (__NR_OABI_SYSCALL_BASE) for OABI tasks, while normal EABI tasks do not set the upper bits. This makes it possible to implement the in_oabi_syscall() helper later. All other users of thread_info->syscall go through the syscall_get_nr() helper, which in turn filters out the ABI bits. Note that the ABI information is lost with PTRACE_SET_SYSCALL, so one cannot set the internal number to a particular version, but this was already the case. We could change it to let gdb encode the ABI type along with the syscall in a CONFIG_OABI_COMPAT-enabled kernel, but that itself would be a (backwards-compatible) ABI change, so I don't do it here. Acked-by: Christoph Hellwig Signed-off-by: Arnd Bergmann Signed-off-by: Russell King (Oracle) --- arch/arm/include/asm/syscall.h | 5 ++++- arch/arm/include/asm/thread_info.h | 2 +- arch/arm/include/uapi/asm/unistd.h | 1 + arch/arm/kernel/asm-offsets.c | 1 + arch/arm/kernel/entry-common.S | 8 ++++++-- arch/arm/kernel/ptrace.c | 14 ++++++++------ 6 files changed, 21 insertions(+), 10 deletions(-) diff --git a/arch/arm/include/asm/syscall.h b/arch/arm/include/asm/syscall.h index fd02761ba06c..f055e846a5cc 100644 --- a/arch/arm/include/asm/syscall.h +++ b/arch/arm/include/asm/syscall.h @@ -22,7 +22,10 @@ extern const unsigned long sys_call_table[]; static inline int syscall_get_nr(struct task_struct *task, struct pt_regs *regs) { - return task_thread_info(task)->syscall; + if (IS_ENABLED(CONFIG_AEABI) && !IS_ENABLED(CONFIG_OABI_COMPAT)) + return task_thread_info(task)->abi_syscall; + + return task_thread_info(task)->abi_syscall & __NR_SYSCALL_MASK; } static inline void syscall_rollback(struct task_struct *task, diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h index 70d4cbc49ae1..17c56051747b 100644 --- a/arch/arm/include/asm/thread_info.h +++ b/arch/arm/include/asm/thread_info.h @@ -62,7 +62,7 @@ struct thread_info { unsigned long stack_canary; #endif struct cpu_context_save cpu_context; /* cpu context */ - __u32 syscall; /* syscall number */ + __u32 abi_syscall; /* ABI type and syscall nr */ __u8 used_cp[16]; /* thread used copro */ unsigned long tp_value[2]; /* TLS registers */ #ifdef CONFIG_CRUNCH diff --git a/arch/arm/include/uapi/asm/unistd.h b/arch/arm/include/uapi/asm/unistd.h index ae7749e15726..a1149911464c 100644 --- a/arch/arm/include/uapi/asm/unistd.h +++ b/arch/arm/include/uapi/asm/unistd.h @@ -15,6 +15,7 @@ #define _UAPI__ASM_ARM_UNISTD_H #define __NR_OABI_SYSCALL_BASE 0x900000 +#define __NR_SYSCALL_MASK 0x0fffff #if defined(__thumb__) || defined(__ARM_EABI__) #define __NR_SYSCALL_BASE 0 diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c index 70993af22d80..a0945b898ca3 100644 --- a/arch/arm/kernel/asm-offsets.c +++ b/arch/arm/kernel/asm-offsets.c @@ -48,6 +48,7 @@ int main(void) DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); DEFINE(TI_CPU_DOMAIN, offsetof(struct thread_info, cpu_domain)); DEFINE(TI_CPU_SAVE, offsetof(struct thread_info, cpu_context)); + DEFINE(TI_ABI_SYSCALL, offsetof(struct thread_info, abi_syscall)); DEFINE(TI_USED_CP, offsetof(struct thread_info, used_cp)); DEFINE(TI_TP_VALUE, offsetof(struct thread_info, tp_value)); DEFINE(TI_FPSTATE, offsetof(struct thread_info, fpstate)); diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 7f0b7aba1498..e837af90cd44 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -226,6 +226,7 @@ ENTRY(vector_swi) /* saved_psr and saved_pc are now dead */ uaccess_disable tbl + get_thread_info tsk adr tbl, sys_call_table @ load syscall table pointer @@ -237,13 +238,17 @@ ENTRY(vector_swi) * get the old ABI syscall table address. */ bics r10, r10, #0xff000000 + strne r10, [tsk, #TI_ABI_SYSCALL] + streq scno, [tsk, #TI_ABI_SYSCALL] eorne scno, r10, #__NR_OABI_SYSCALL_BASE ldrne tbl, =sys_oabi_call_table #elif !defined(CONFIG_AEABI) bic scno, scno, #0xff000000 @ mask off SWI op-code + str scno, [tsk, #TI_ABI_SYSCALL] eor scno, scno, #__NR_SYSCALL_BASE @ check OS number +#else + str scno, [tsk, #TI_ABI_SYSCALL] #endif - get_thread_info tsk /* * Reload the registers that may have been corrupted on entry to * the syscall assembly (by tracing or context tracking.) @@ -288,7 +293,6 @@ ENDPROC(vector_swi) * context switches, and waiting for our parent to respond. */ __sys_trace: - mov r1, scno add r0, sp, #S_OFF bl syscall_trace_enter mov scno, r0 diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index 2771e682220b..d886ea8910cb 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -25,6 +25,7 @@ #include #include +#include #include #define CREATE_TRACE_POINTS @@ -811,7 +812,8 @@ long arch_ptrace(struct task_struct *child, long request, break; case PTRACE_SET_SYSCALL: - task_thread_info(child)->syscall = data; + task_thread_info(child)->abi_syscall = data & + __NR_SYSCALL_MASK; ret = 0; break; @@ -880,14 +882,14 @@ static void tracehook_report_syscall(struct pt_regs *regs, if (dir == PTRACE_SYSCALL_EXIT) tracehook_report_syscall_exit(regs, 0); else if (tracehook_report_syscall_entry(regs)) - current_thread_info()->syscall = -1; + current_thread_info()->abi_syscall = -1; regs->ARM_ip = ip; } -asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno) +asmlinkage int syscall_trace_enter(struct pt_regs *regs) { - current_thread_info()->syscall = scno; + int scno; if (test_thread_flag(TIF_SYSCALL_TRACE)) tracehook_report_syscall(regs, PTRACE_SYSCALL_ENTER); @@ -898,11 +900,11 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno) return -1; #else /* XXX: remove this once OABI gets fixed */ - secure_computing_strict(current_thread_info()->syscall); + secure_computing_strict(syscall_get_nr(current, regs)); #endif /* Tracer or seccomp may have changed syscall. */ - scno = current_thread_info()->syscall; + scno = syscall_get_nr(current, regs); if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) trace_sys_enter(regs, scno); From 249dbe74d3c4b568a623fb55c56cddf19fdf0b89 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 11 Aug 2021 08:30:22 +0100 Subject: [PATCH 158/696] ARM: 9108/1: oabi-compat: rework epoll_wait/epoll_pwait emulation The epoll_wait() system call wrapper is one of the remaining users of the set_fs() infrasturcture for Arm. Changing it to not require set_fs() is rather complex unfortunately. The approach I'm taking here is to allow architectures to override the code that copies the output to user space, and let the oabi-compat implementation check whether it is getting called from an EABI or OABI system call based on the thread_info->syscall value. The in_oabi_syscall() check here mirrors the in_compat_syscall() and in_x32_syscall() helpers for 32-bit compat implementations on other architectures. Overall, the amount of code goes down, at least with the newly added sys_oabi_epoll_pwait() helper getting removed again. The downside is added complexity in the source code for the native implementation. There should be no difference in runtime performance except for Arm kernels with CONFIG_OABI_COMPAT enabled that now have to go through an external function call to check which of the two variants to use. Acked-by: Christoph Hellwig Signed-off-by: Arnd Bergmann Signed-off-by: Russell King (Oracle) --- arch/arm/include/asm/syscall.h | 11 ++++ arch/arm/kernel/sys_oabi-compat.c | 91 +++++++------------------------ arch/arm/tools/syscall.tbl | 4 +- fs/eventpoll.c | 5 +- include/linux/eventpoll.h | 18 ++++++ 5 files changed, 53 insertions(+), 76 deletions(-) diff --git a/arch/arm/include/asm/syscall.h b/arch/arm/include/asm/syscall.h index f055e846a5cc..24c19d63ff0a 100644 --- a/arch/arm/include/asm/syscall.h +++ b/arch/arm/include/asm/syscall.h @@ -28,6 +28,17 @@ static inline int syscall_get_nr(struct task_struct *task, return task_thread_info(task)->abi_syscall & __NR_SYSCALL_MASK; } +static inline bool __in_oabi_syscall(struct task_struct *task) +{ + return IS_ENABLED(CONFIG_OABI_COMPAT) && + (task_thread_info(task)->abi_syscall & __NR_OABI_SYSCALL_BASE); +} + +static inline bool in_oabi_syscall(void) +{ + return __in_oabi_syscall(current); +} + static inline void syscall_rollback(struct task_struct *task, struct pt_regs *regs) { diff --git a/arch/arm/kernel/sys_oabi-compat.c b/arch/arm/kernel/sys_oabi-compat.c index 443203fafb6b..1f6a433200f1 100644 --- a/arch/arm/kernel/sys_oabi-compat.c +++ b/arch/arm/kernel/sys_oabi-compat.c @@ -83,6 +83,8 @@ #include #include +#include + struct oldabi_stat64 { unsigned long long st_dev; unsigned int __pad1; @@ -264,88 +266,35 @@ asmlinkage long sys_oabi_epoll_ctl(int epfd, int op, int fd, return do_epoll_ctl(epfd, op, fd, &kernel, false); } - -static long do_oabi_epoll_wait(int epfd, struct oabi_epoll_event __user *events, - int maxevents, int timeout) -{ - struct epoll_event *kbuf; - struct oabi_epoll_event e; - mm_segment_t fs; - long ret, err, i; - - if (maxevents <= 0 || - maxevents > (INT_MAX/sizeof(*kbuf)) || - maxevents > (INT_MAX/sizeof(*events))) - return -EINVAL; - if (!access_ok(events, sizeof(*events) * maxevents)) - return -EFAULT; - kbuf = kmalloc_array(maxevents, sizeof(*kbuf), GFP_KERNEL); - if (!kbuf) - return -ENOMEM; - fs = get_fs(); - set_fs(KERNEL_DS); - ret = sys_epoll_wait(epfd, kbuf, maxevents, timeout); - set_fs(fs); - err = 0; - for (i = 0; i < ret; i++) { - e.events = kbuf[i].events; - e.data = kbuf[i].data; - err = __copy_to_user(events, &e, sizeof(e)); - if (err) - break; - events++; - } - kfree(kbuf); - return err ? -EFAULT : ret; -} #else asmlinkage long sys_oabi_epoll_ctl(int epfd, int op, int fd, struct oabi_epoll_event __user *event) { return -EINVAL; } - -asmlinkage long sys_oabi_epoll_wait(int epfd, - struct oabi_epoll_event __user *events, - int maxevents, int timeout) -{ - return -EINVAL; -} #endif -SYSCALL_DEFINE4(oabi_epoll_wait, int, epfd, - struct oabi_epoll_event __user *, events, - int, maxevents, int, timeout) +struct epoll_event __user * +epoll_put_uevent(__poll_t revents, __u64 data, + struct epoll_event __user *uevent) { - return do_oabi_epoll_wait(epfd, events, maxevents, timeout); + if (in_oabi_syscall()) { + struct oabi_epoll_event __user *oevent = (void __user *)uevent; + + if (__put_user(revents, &oevent->events) || + __put_user(data, &oevent->data)) + return NULL; + + return (void __user *)(oevent+1); + } + + if (__put_user(revents, &uevent->events) || + __put_user(data, &uevent->data)) + return NULL; + + return uevent+1; } -/* - * Implement the event wait interface for the eventpoll file. It is the kernel - * part of the user space epoll_pwait(2). - */ -SYSCALL_DEFINE6(oabi_epoll_pwait, int, epfd, - struct oabi_epoll_event __user *, events, int, maxevents, - int, timeout, const sigset_t __user *, sigmask, - size_t, sigsetsize) -{ - int error; - - /* - * If the caller wants a certain signal mask to be set during the wait, - * we apply it here. - */ - error = set_user_sigmask(sigmask, sigsetsize); - if (error) - return error; - - error = do_oabi_epoll_wait(epfd, events, maxevents, timeout); - restore_saved_sigmask_unless(error == -EINTR); - - return error; -} -#endif - struct oabi_sembuf { unsigned short sem_num; short sem_op; diff --git a/arch/arm/tools/syscall.tbl b/arch/arm/tools/syscall.tbl index 11d0b960b2c2..344424a9611f 100644 --- a/arch/arm/tools/syscall.tbl +++ b/arch/arm/tools/syscall.tbl @@ -266,7 +266,7 @@ 249 common lookup_dcookie sys_lookup_dcookie 250 common epoll_create sys_epoll_create 251 common epoll_ctl sys_epoll_ctl sys_oabi_epoll_ctl -252 common epoll_wait sys_epoll_wait sys_oabi_epoll_wait +252 common epoll_wait sys_epoll_wait 253 common remap_file_pages sys_remap_file_pages # 254 for set_thread_area # 255 for get_thread_area @@ -360,7 +360,7 @@ 343 common vmsplice sys_vmsplice 344 common move_pages sys_move_pages 345 common getcpu sys_getcpu -346 common epoll_pwait sys_epoll_pwait sys_oabi_epoll_pwait +346 common epoll_pwait sys_epoll_pwait 347 common kexec_load sys_kexec_load 348 common utimensat sys_utimensat_time32 349 common signalfd sys_signalfd diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 1e596e1d0bba..c90c4352325e 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -1684,8 +1684,8 @@ static int ep_send_events(struct eventpoll *ep, if (!revents) continue; - if (__put_user(revents, &events->events) || - __put_user(epi->event.data, &events->data)) { + events = epoll_put_uevent(revents, epi->event.data, events); + if (!events) { list_add(&epi->rdllink, &txlist); ep_pm_stay_awake(epi); if (!res) @@ -1693,7 +1693,6 @@ static int ep_send_events(struct eventpoll *ep, break; } res++; - events++; if (epi->event.events & EPOLLONESHOT) epi->event.events &= EP_PRIVATE_BITS; else if (!(epi->event.events & EPOLLET)) { diff --git a/include/linux/eventpoll.h b/include/linux/eventpoll.h index 593322c946e6..3337745d81bd 100644 --- a/include/linux/eventpoll.h +++ b/include/linux/eventpoll.h @@ -68,4 +68,22 @@ static inline void eventpoll_release(struct file *file) {} #endif +#if defined(CONFIG_ARM) && defined(CONFIG_OABI_COMPAT) +/* ARM OABI has an incompatible struct layout and needs a special handler */ +extern struct epoll_event __user * +epoll_put_uevent(__poll_t revents, __u64 data, + struct epoll_event __user *uevent); +#else +static inline struct epoll_event __user * +epoll_put_uevent(__poll_t revents, __u64 data, + struct epoll_event __user *uevent) +{ + if (__put_user(revents, &uevent->events) || + __put_user(data, &uevent->data)) + return NULL; + + return uevent+1; +} +#endif + #endif /* #ifndef _LINUX_EVENTPOLL_H */ From bdec0145286f7e6be9b3134aa35f0f335fa27c38 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 11 Aug 2021 08:30:23 +0100 Subject: [PATCH 159/696] ARM: 9114/1: oabi-compat: rework sys_semtimedop emulation sys_oabi_semtimedop() is one of the last users of set_fs() on Arm. To remove this one, expose the internal code of the actual implementation that operates on a kernel pointer and call it directly after copying. There should be no measurable impact on the normal execution of this function, and it makes the overly long function a little shorter, which may help readability. While reworking the oabi version, make it behave a little more like the native one, using kvmalloc_array() and restructure the code flow in a similar way. The naming of __do_semtimedop() is not very good, I hope someone can come up with a better name. One regression was spotted by kernel test robot and fixed before the first mailing list submission. Acked-by: Christoph Hellwig Signed-off-by: Arnd Bergmann Signed-off-by: Russell King (Oracle) --- arch/arm/kernel/sys_oabi-compat.c | 60 ++++++++++++++++------ include/linux/syscalls.h | 3 ++ ipc/sem.c | 84 +++++++++++++++++++------------ 3 files changed, 99 insertions(+), 48 deletions(-) diff --git a/arch/arm/kernel/sys_oabi-compat.c b/arch/arm/kernel/sys_oabi-compat.c index 1f6a433200f1..5ea365c35ca5 100644 --- a/arch/arm/kernel/sys_oabi-compat.c +++ b/arch/arm/kernel/sys_oabi-compat.c @@ -80,6 +80,7 @@ #include #include #include +#include #include #include @@ -302,46 +303,52 @@ struct oabi_sembuf { unsigned short __pad; }; +#define sc_semopm sem_ctls[2] + +#ifdef CONFIG_SYSVIPC asmlinkage long sys_oabi_semtimedop(int semid, struct oabi_sembuf __user *tsops, unsigned nsops, const struct old_timespec32 __user *timeout) { + struct ipc_namespace *ns; struct sembuf *sops; - struct old_timespec32 local_timeout; long err; int i; + ns = current->nsproxy->ipc_ns; + if (nsops > ns->sc_semopm) + return -E2BIG; if (nsops < 1 || nsops > SEMOPM) return -EINVAL; - if (!access_ok(tsops, sizeof(*tsops) * nsops)) - return -EFAULT; - sops = kmalloc_array(nsops, sizeof(*sops), GFP_KERNEL); + sops = kvmalloc_array(nsops, sizeof(*sops), GFP_KERNEL); if (!sops) return -ENOMEM; err = 0; for (i = 0; i < nsops; i++) { struct oabi_sembuf osb; - err |= __copy_from_user(&osb, tsops, sizeof(osb)); + err |= copy_from_user(&osb, tsops, sizeof(osb)); sops[i].sem_num = osb.sem_num; sops[i].sem_op = osb.sem_op; sops[i].sem_flg = osb.sem_flg; tsops++; } - if (timeout) { - /* copy this as well before changing domain protection */ - err |= copy_from_user(&local_timeout, timeout, sizeof(*timeout)); - timeout = &local_timeout; - } if (err) { err = -EFAULT; - } else { - mm_segment_t fs = get_fs(); - set_fs(KERNEL_DS); - err = sys_semtimedop_time32(semid, sops, nsops, timeout); - set_fs(fs); + goto out; } - kfree(sops); + + if (timeout) { + struct timespec64 ts; + err = get_old_timespec32(&ts, timeout); + if (err) + goto out; + err = __do_semtimedop(semid, sops, nsops, &ts, ns); + goto out; + } + err = __do_semtimedop(semid, sops, nsops, NULL, ns); +out: + kvfree(sops); return err; } @@ -368,6 +375,27 @@ asmlinkage int sys_oabi_ipc(uint call, int first, int second, int third, return sys_ipc(call, first, second, third, ptr, fifth); } } +#else +asmlinkage long sys_oabi_semtimedop(int semid, + struct oabi_sembuf __user *tsops, + unsigned nsops, + const struct old_timespec32 __user *timeout) +{ + return -ENOSYS; +} + +asmlinkage long sys_oabi_semop(int semid, struct oabi_sembuf __user *tsops, + unsigned nsops) +{ + return -ENOSYS; +} + +asmlinkage int sys_oabi_ipc(uint call, int first, int second, int third, + void __user *ptr, long fifth) +{ + return -ENOSYS; +} +#endif asmlinkage long sys_oabi_bind(int fd, struct sockaddr __user *addr, int addrlen) { diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 69c9a7010081..6c6fc3fd5b72 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -1373,6 +1373,9 @@ long ksys_old_shmctl(int shmid, int cmd, struct shmid_ds __user *buf); long compat_ksys_semtimedop(int semid, struct sembuf __user *tsems, unsigned int nsops, const struct old_timespec32 __user *timeout); +long __do_semtimedop(int semid, struct sembuf *tsems, unsigned int nsops, + const struct timespec64 *timeout, + struct ipc_namespace *ns); int __sys_getsockopt(int fd, int level, int optname, char __user *optval, int __user *optlen); diff --git a/ipc/sem.c b/ipc/sem.c index 971e75d28364..ae8d9104b0a0 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -1984,46 +1984,34 @@ out: return un; } -static long do_semtimedop(int semid, struct sembuf __user *tsops, - unsigned nsops, const struct timespec64 *timeout) +long __do_semtimedop(int semid, struct sembuf *sops, + unsigned nsops, const struct timespec64 *timeout, + struct ipc_namespace *ns) { int error = -EINVAL; struct sem_array *sma; - struct sembuf fast_sops[SEMOPM_FAST]; - struct sembuf *sops = fast_sops, *sop; + struct sembuf *sop; struct sem_undo *un; int max, locknum; bool undos = false, alter = false, dupsop = false; struct sem_queue queue; unsigned long dup = 0, jiffies_left = 0; - struct ipc_namespace *ns; - - ns = current->nsproxy->ipc_ns; if (nsops < 1 || semid < 0) return -EINVAL; if (nsops > ns->sc_semopm) return -E2BIG; - if (nsops > SEMOPM_FAST) { - sops = kvmalloc_array(nsops, sizeof(*sops), GFP_KERNEL); - if (sops == NULL) - return -ENOMEM; - } - - if (copy_from_user(sops, tsops, nsops * sizeof(*tsops))) { - error = -EFAULT; - goto out_free; - } if (timeout) { if (timeout->tv_sec < 0 || timeout->tv_nsec < 0 || timeout->tv_nsec >= 1000000000L) { error = -EINVAL; - goto out_free; + goto out; } jiffies_left = timespec64_to_jiffies(timeout); } + max = 0; for (sop = sops; sop < sops + nsops; sop++) { unsigned long mask = 1ULL << ((sop->sem_num) % BITS_PER_LONG); @@ -2052,7 +2040,7 @@ static long do_semtimedop(int semid, struct sembuf __user *tsops, un = find_alloc_undo(ns, semid); if (IS_ERR(un)) { error = PTR_ERR(un); - goto out_free; + goto out; } } else { un = NULL; @@ -2063,25 +2051,25 @@ static long do_semtimedop(int semid, struct sembuf __user *tsops, if (IS_ERR(sma)) { rcu_read_unlock(); error = PTR_ERR(sma); - goto out_free; + goto out; } error = -EFBIG; if (max >= sma->sem_nsems) { rcu_read_unlock(); - goto out_free; + goto out; } error = -EACCES; if (ipcperms(ns, &sma->sem_perm, alter ? S_IWUGO : S_IRUGO)) { rcu_read_unlock(); - goto out_free; + goto out; } error = security_sem_semop(&sma->sem_perm, sops, nsops, alter); if (error) { rcu_read_unlock(); - goto out_free; + goto out; } error = -EIDRM; @@ -2095,7 +2083,7 @@ static long do_semtimedop(int semid, struct sembuf __user *tsops, * entangled here and why it's RMID race safe on comments at sem_lock() */ if (!ipc_valid_object(&sma->sem_perm)) - goto out_unlock_free; + goto out_unlock; /* * semid identifiers are not unique - find_alloc_undo may have * allocated an undo structure, it was invalidated by an RMID @@ -2104,7 +2092,7 @@ static long do_semtimedop(int semid, struct sembuf __user *tsops, * "un" itself is guaranteed by rcu. */ if (un && un->semid == -1) - goto out_unlock_free; + goto out_unlock; queue.sops = sops; queue.nsops = nsops; @@ -2130,10 +2118,10 @@ static long do_semtimedop(int semid, struct sembuf __user *tsops, rcu_read_unlock(); wake_up_q(&wake_q); - goto out_free; + goto out; } if (error < 0) /* non-blocking error path */ - goto out_unlock_free; + goto out_unlock; /* * We need to sleep on this operation, so we put the current @@ -2198,14 +2186,14 @@ static long do_semtimedop(int semid, struct sembuf __user *tsops, if (error != -EINTR) { /* see SEM_BARRIER_2 for purpose/pairing */ smp_acquire__after_ctrl_dep(); - goto out_free; + goto out; } rcu_read_lock(); locknum = sem_lock(sma, sops, nsops); if (!ipc_valid_object(&sma->sem_perm)) - goto out_unlock_free; + goto out_unlock; /* * No necessity for any barrier: We are protect by sem_lock() @@ -2217,7 +2205,7 @@ static long do_semtimedop(int semid, struct sembuf __user *tsops, * Leave without unlink_queue(), but with sem_unlock(). */ if (error != -EINTR) - goto out_unlock_free; + goto out_unlock; /* * If an interrupt occurred we have to clean up the queue. @@ -2228,13 +2216,45 @@ static long do_semtimedop(int semid, struct sembuf __user *tsops, unlink_queue(sma, &queue); -out_unlock_free: +out_unlock: sem_unlock(sma, locknum); rcu_read_unlock(); +out: + return error; +} + +static long do_semtimedop(int semid, struct sembuf __user *tsops, + unsigned nsops, const struct timespec64 *timeout) +{ + struct sembuf fast_sops[SEMOPM_FAST]; + struct sembuf *sops = fast_sops; + struct ipc_namespace *ns; + int ret; + + ns = current->nsproxy->ipc_ns; + if (nsops > ns->sc_semopm) + return -E2BIG; + if (nsops < 1) + return -EINVAL; + + if (nsops > SEMOPM_FAST) { + sops = kvmalloc_array(nsops, sizeof(*sops), GFP_KERNEL); + if (sops == NULL) + return -ENOMEM; + } + + if (copy_from_user(sops, tsops, nsops * sizeof(*tsops))) { + ret = -EFAULT; + goto out_free; + } + + ret = __do_semtimedop(semid, sops, nsops, timeout, ns); + out_free: if (sops != fast_sops) kvfree(sops); - return error; + + return ret; } long ksys_semtimedop(int semid, struct sembuf __user *tsops, From 7e2d8c29ecdd86afbcedb9d9a977bab8af527add Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 11 Aug 2021 08:30:24 +0100 Subject: [PATCH 160/696] ARM: 9111/1: oabi-compat: rework fcntl64() emulation This is one of the last users of get_fs(), and this is fairly easy to change, since the infrastructure for it is already there. The replacement here is essentially a copy of the existing fcntl64() syscall entry function. Acked-by: Christoph Hellwig Signed-off-by: Arnd Bergmann Signed-off-by: Russell King (Oracle) --- arch/arm/kernel/sys_oabi-compat.c | 89 ++++++++++++++++++++----------- 1 file changed, 58 insertions(+), 31 deletions(-) diff --git a/arch/arm/kernel/sys_oabi-compat.c b/arch/arm/kernel/sys_oabi-compat.c index 5ea365c35ca5..223ee46b6e75 100644 --- a/arch/arm/kernel/sys_oabi-compat.c +++ b/arch/arm/kernel/sys_oabi-compat.c @@ -194,56 +194,83 @@ struct oabi_flock64 { pid_t l_pid; } __attribute__ ((packed,aligned(4))); -static long do_locks(unsigned int fd, unsigned int cmd, - unsigned long arg) +static int get_oabi_flock(struct flock64 *kernel, struct oabi_flock64 __user *arg) { - struct flock64 kernel; struct oabi_flock64 user; - mm_segment_t fs; - long ret; if (copy_from_user(&user, (struct oabi_flock64 __user *)arg, sizeof(user))) return -EFAULT; - kernel.l_type = user.l_type; - kernel.l_whence = user.l_whence; - kernel.l_start = user.l_start; - kernel.l_len = user.l_len; - kernel.l_pid = user.l_pid; - fs = get_fs(); - set_fs(KERNEL_DS); - ret = sys_fcntl64(fd, cmd, (unsigned long)&kernel); - set_fs(fs); + kernel->l_type = user.l_type; + kernel->l_whence = user.l_whence; + kernel->l_start = user.l_start; + kernel->l_len = user.l_len; + kernel->l_pid = user.l_pid; - if (!ret && (cmd == F_GETLK64 || cmd == F_OFD_GETLK)) { - user.l_type = kernel.l_type; - user.l_whence = kernel.l_whence; - user.l_start = kernel.l_start; - user.l_len = kernel.l_len; - user.l_pid = kernel.l_pid; - if (copy_to_user((struct oabi_flock64 __user *)arg, - &user, sizeof(user))) - ret = -EFAULT; - } - return ret; + return 0; +} + +static int put_oabi_flock(struct flock64 *kernel, struct oabi_flock64 __user *arg) +{ + struct oabi_flock64 user; + + user.l_type = kernel->l_type; + user.l_whence = kernel->l_whence; + user.l_start = kernel->l_start; + user.l_len = kernel->l_len; + user.l_pid = kernel->l_pid; + + if (copy_to_user((struct oabi_flock64 __user *)arg, + &user, sizeof(user))) + return -EFAULT; + + return 0; } asmlinkage long sys_oabi_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg) { + void __user *argp = (void __user *)arg; + struct fd f = fdget_raw(fd); + struct flock64 flock; + long err = -EBADF; + + if (!f.file) + goto out; + switch (cmd) { - case F_OFD_GETLK: - case F_OFD_SETLK: - case F_OFD_SETLKW: case F_GETLK64: + case F_OFD_GETLK: + err = security_file_fcntl(f.file, cmd, arg); + if (err) + break; + err = get_oabi_flock(&flock, argp); + if (err) + break; + err = fcntl_getlk64(f.file, cmd, &flock); + if (!err) + err = put_oabi_flock(&flock, argp); + break; case F_SETLK64: case F_SETLKW64: - return do_locks(fd, cmd, arg); - + case F_OFD_SETLK: + case F_OFD_SETLKW: + err = security_file_fcntl(f.file, cmd, arg); + if (err) + break; + err = get_oabi_flock(&flock, argp); + if (err) + break; + err = fcntl_setlk64(fd, f.file, cmd, &flock); + break; default: - return sys_fcntl64(fd, cmd, arg); + err = sys_fcntl64(fd, cmd, arg); + break; } + fdput(f); +out: + return err; } struct oabi_epoll_event { From 2df4c9a741a0b5e2883cc356c1b724d1f739fb55 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 11 Aug 2021 08:30:25 +0100 Subject: [PATCH 161/696] ARM: 9112/1: uaccess: add __{get,put}_kernel_nofault These mimic the behavior of get_user and put_user, except for domain switching, address limit checking and handling of mismatched sizes, none of which are relevant here. To work with pre-Armv6 kernels, this has to avoid TUSER() inside of the new macros, the new approach passes the "t" string along with the opcode, which is a bit uglier but avoids duplicating more code. As there is no __get_user_asm_dword(), I work around it by copying 32 bit at a time, which is possible because the output size is known. Acked-by: Christoph Hellwig Signed-off-by: Arnd Bergmann Signed-off-by: Russell King (Oracle) --- arch/arm/include/asm/uaccess.h | 123 ++++++++++++++++++++++----------- 1 file changed, 83 insertions(+), 40 deletions(-) diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h index a13d90206472..4f60638755c4 100644 --- a/arch/arm/include/asm/uaccess.h +++ b/arch/arm/include/asm/uaccess.h @@ -308,11 +308,11 @@ static inline void set_fs(mm_segment_t fs) #define __get_user(x, ptr) \ ({ \ long __gu_err = 0; \ - __get_user_err((x), (ptr), __gu_err); \ + __get_user_err((x), (ptr), __gu_err, TUSER()); \ __gu_err; \ }) -#define __get_user_err(x, ptr, err) \ +#define __get_user_err(x, ptr, err, __t) \ do { \ unsigned long __gu_addr = (unsigned long)(ptr); \ unsigned long __gu_val; \ @@ -321,18 +321,19 @@ do { \ might_fault(); \ __ua_flags = uaccess_save_and_enable(); \ switch (sizeof(*(ptr))) { \ - case 1: __get_user_asm_byte(__gu_val, __gu_addr, err); break; \ - case 2: __get_user_asm_half(__gu_val, __gu_addr, err); break; \ - case 4: __get_user_asm_word(__gu_val, __gu_addr, err); break; \ + case 1: __get_user_asm_byte(__gu_val, __gu_addr, err, __t); break; \ + case 2: __get_user_asm_half(__gu_val, __gu_addr, err, __t); break; \ + case 4: __get_user_asm_word(__gu_val, __gu_addr, err, __t); break; \ default: (__gu_val) = __get_user_bad(); \ } \ uaccess_restore(__ua_flags); \ (x) = (__typeof__(*(ptr)))__gu_val; \ } while (0) +#endif #define __get_user_asm(x, addr, err, instr) \ __asm__ __volatile__( \ - "1: " TUSER(instr) " %1, [%2], #0\n" \ + "1: " instr " %1, [%2], #0\n" \ "2:\n" \ " .pushsection .text.fixup,\"ax\"\n" \ " .align 2\n" \ @@ -348,40 +349,38 @@ do { \ : "r" (addr), "i" (-EFAULT) \ : "cc") -#define __get_user_asm_byte(x, addr, err) \ - __get_user_asm(x, addr, err, ldrb) +#define __get_user_asm_byte(x, addr, err, __t) \ + __get_user_asm(x, addr, err, "ldrb" __t) #if __LINUX_ARM_ARCH__ >= 6 -#define __get_user_asm_half(x, addr, err) \ - __get_user_asm(x, addr, err, ldrh) +#define __get_user_asm_half(x, addr, err, __t) \ + __get_user_asm(x, addr, err, "ldrh" __t) #else #ifndef __ARMEB__ -#define __get_user_asm_half(x, __gu_addr, err) \ +#define __get_user_asm_half(x, __gu_addr, err, __t) \ ({ \ unsigned long __b1, __b2; \ - __get_user_asm_byte(__b1, __gu_addr, err); \ - __get_user_asm_byte(__b2, __gu_addr + 1, err); \ + __get_user_asm_byte(__b1, __gu_addr, err, __t); \ + __get_user_asm_byte(__b2, __gu_addr + 1, err, __t); \ (x) = __b1 | (__b2 << 8); \ }) #else -#define __get_user_asm_half(x, __gu_addr, err) \ +#define __get_user_asm_half(x, __gu_addr, err, __t) \ ({ \ unsigned long __b1, __b2; \ - __get_user_asm_byte(__b1, __gu_addr, err); \ - __get_user_asm_byte(__b2, __gu_addr + 1, err); \ + __get_user_asm_byte(__b1, __gu_addr, err, __t); \ + __get_user_asm_byte(__b2, __gu_addr + 1, err, __t); \ (x) = (__b1 << 8) | __b2; \ }) #endif #endif /* __LINUX_ARM_ARCH__ >= 6 */ -#define __get_user_asm_word(x, addr, err) \ - __get_user_asm(x, addr, err, ldr) -#endif - +#define __get_user_asm_word(x, addr, err, __t) \ + __get_user_asm(x, addr, err, "ldr" __t) #define __put_user_switch(x, ptr, __err, __fn) \ do { \ @@ -425,7 +424,7 @@ do { \ #define __put_user_nocheck(x, __pu_ptr, __err, __size) \ do { \ unsigned long __pu_addr = (unsigned long)__pu_ptr; \ - __put_user_nocheck_##__size(x, __pu_addr, __err); \ + __put_user_nocheck_##__size(x, __pu_addr, __err, TUSER());\ } while (0) #define __put_user_nocheck_1 __put_user_asm_byte @@ -433,9 +432,11 @@ do { \ #define __put_user_nocheck_4 __put_user_asm_word #define __put_user_nocheck_8 __put_user_asm_dword +#endif /* !CONFIG_CPU_SPECTRE */ + #define __put_user_asm(x, __pu_addr, err, instr) \ __asm__ __volatile__( \ - "1: " TUSER(instr) " %1, [%2], #0\n" \ + "1: " instr " %1, [%2], #0\n" \ "2:\n" \ " .pushsection .text.fixup,\"ax\"\n" \ " .align 2\n" \ @@ -450,36 +451,36 @@ do { \ : "r" (x), "r" (__pu_addr), "i" (-EFAULT) \ : "cc") -#define __put_user_asm_byte(x, __pu_addr, err) \ - __put_user_asm(x, __pu_addr, err, strb) +#define __put_user_asm_byte(x, __pu_addr, err, __t) \ + __put_user_asm(x, __pu_addr, err, "strb" __t) #if __LINUX_ARM_ARCH__ >= 6 -#define __put_user_asm_half(x, __pu_addr, err) \ - __put_user_asm(x, __pu_addr, err, strh) +#define __put_user_asm_half(x, __pu_addr, err, __t) \ + __put_user_asm(x, __pu_addr, err, "strh" __t) #else #ifndef __ARMEB__ -#define __put_user_asm_half(x, __pu_addr, err) \ +#define __put_user_asm_half(x, __pu_addr, err, __t) \ ({ \ unsigned long __temp = (__force unsigned long)(x); \ - __put_user_asm_byte(__temp, __pu_addr, err); \ - __put_user_asm_byte(__temp >> 8, __pu_addr + 1, err); \ + __put_user_asm_byte(__temp, __pu_addr, err, __t); \ + __put_user_asm_byte(__temp >> 8, __pu_addr + 1, err, __t);\ }) #else -#define __put_user_asm_half(x, __pu_addr, err) \ +#define __put_user_asm_half(x, __pu_addr, err, __t) \ ({ \ unsigned long __temp = (__force unsigned long)(x); \ - __put_user_asm_byte(__temp >> 8, __pu_addr, err); \ - __put_user_asm_byte(__temp, __pu_addr + 1, err); \ + __put_user_asm_byte(__temp >> 8, __pu_addr, err, __t); \ + __put_user_asm_byte(__temp, __pu_addr + 1, err, __t); \ }) #endif #endif /* __LINUX_ARM_ARCH__ >= 6 */ -#define __put_user_asm_word(x, __pu_addr, err) \ - __put_user_asm(x, __pu_addr, err, str) +#define __put_user_asm_word(x, __pu_addr, err, __t) \ + __put_user_asm(x, __pu_addr, err, "str" __t) #ifndef __ARMEB__ #define __reg_oper0 "%R2" @@ -489,12 +490,12 @@ do { \ #define __reg_oper1 "%R2" #endif -#define __put_user_asm_dword(x, __pu_addr, err) \ +#define __put_user_asm_dword(x, __pu_addr, err, __t) \ __asm__ __volatile__( \ - ARM( "1: " TUSER(str) " " __reg_oper1 ", [%1], #4\n" ) \ - ARM( "2: " TUSER(str) " " __reg_oper0 ", [%1]\n" ) \ - THUMB( "1: " TUSER(str) " " __reg_oper1 ", [%1]\n" ) \ - THUMB( "2: " TUSER(str) " " __reg_oper0 ", [%1, #4]\n" ) \ + ARM( "1: str" __t " " __reg_oper1 ", [%1], #4\n" ) \ + ARM( "2: str" __t " " __reg_oper0 ", [%1]\n" ) \ + THUMB( "1: str" __t " " __reg_oper1 ", [%1]\n" ) \ + THUMB( "2: str" __t " " __reg_oper0 ", [%1, #4]\n" ) \ "3:\n" \ " .pushsection .text.fixup,\"ax\"\n" \ " .align 2\n" \ @@ -510,7 +511,49 @@ do { \ : "r" (x), "i" (-EFAULT) \ : "cc") -#endif /* !CONFIG_CPU_SPECTRE */ +#define HAVE_GET_KERNEL_NOFAULT + +#define __get_kernel_nofault(dst, src, type, err_label) \ +do { \ + const type *__pk_ptr = (src); \ + unsigned long __src = (unsigned long)(__pk_ptr); \ + type __val; \ + int __err = 0; \ + switch (sizeof(type)) { \ + case 1: __get_user_asm_byte(__val, __src, __err, ""); break; \ + case 2: __get_user_asm_half(__val, __src, __err, ""); break; \ + case 4: __get_user_asm_word(__val, __src, __err, ""); break; \ + case 8: { \ + u32 *__v32 = (u32*)&__val; \ + __get_user_asm_word(__v32[0], __src, __err, ""); \ + if (__err) \ + break; \ + __get_user_asm_word(__v32[1], __src+4, __err, ""); \ + break; \ + } \ + default: __err = __get_user_bad(); break; \ + } \ + *(type *)(dst) = __val; \ + if (__err) \ + goto err_label; \ +} while (0) + +#define __put_kernel_nofault(dst, src, type, err_label) \ +do { \ + const type *__pk_ptr = (dst); \ + unsigned long __dst = (unsigned long)__pk_ptr; \ + int __err = 0; \ + type __val = *(type *)src; \ + switch (sizeof(type)) { \ + case 1: __put_user_asm_byte(__val, __dst, __err, ""); break; \ + case 2: __put_user_asm_half(__val, __dst, __err, ""); break; \ + case 4: __put_user_asm_word(__val, __dst, __err, ""); break; \ + case 8: __put_user_asm_dword(__val, __dst, __err, ""); break; \ + default: __err = __put_user_bad(); break; \ + } \ + if (__err) \ + goto err_label; \ +} while (0) #ifdef CONFIG_MMU extern unsigned long __must_check From 8ac6f5d7f84bf362e67591708bcb9788cdc42c50 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 11 Aug 2021 08:30:26 +0100 Subject: [PATCH 162/696] ARM: 9113/1: uaccess: remove set_fs() implementation There are no remaining callers of set_fs(), so just remove it along with all associated code that operates on thread_info->addr_limit. There are still further optimizations that can be done: - In get_user(), the address check could be moved entirely into the out of line code, rather than passing a constant as an argument, - I assume the DACR handling can be simplified as we now only change it during user access when CONFIG_CPU_SW_DOMAIN_PAN is set, but not during set_fs(). Acked-by: Christoph Hellwig Signed-off-by: Arnd Bergmann Signed-off-by: Russell King (Oracle) --- arch/arm/Kconfig | 1 - arch/arm/include/asm/ptrace.h | 1 - arch/arm/include/asm/thread_info.h | 4 --- arch/arm/include/asm/uaccess-asm.h | 6 ---- arch/arm/include/asm/uaccess.h | 46 +++--------------------------- arch/arm/kernel/asm-offsets.c | 2 -- arch/arm/kernel/entry-common.S | 12 -------- arch/arm/kernel/process.c | 7 +---- arch/arm/kernel/signal.c | 8 ------ arch/arm/lib/copy_from_user.S | 3 +- arch/arm/lib/copy_to_user.S | 3 +- 11 files changed, 7 insertions(+), 86 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 3ea1c417339f..51897e4cc413 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -126,7 +126,6 @@ config ARM select PCI_SYSCALL if PCI select PERF_USE_VMALLOC select RTC_LIB - select SET_FS select SYS_SUPPORTS_APM_EMULATION # Above selects are sorted alphabetically; please add new ones # according to that. Thanks. diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h index 91d6b7856be4..93051e2f402c 100644 --- a/arch/arm/include/asm/ptrace.h +++ b/arch/arm/include/asm/ptrace.h @@ -19,7 +19,6 @@ struct pt_regs { struct svc_pt_regs { struct pt_regs regs; u32 dacr; - u32 addr_limit; }; #define to_svc_pt_regs(r) container_of(r, struct svc_pt_regs, regs) diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h index 17c56051747b..d89931aed59f 100644 --- a/arch/arm/include/asm/thread_info.h +++ b/arch/arm/include/asm/thread_info.h @@ -31,8 +31,6 @@ struct task_struct; #include -typedef unsigned long mm_segment_t; - struct cpu_context_save { __u32 r4; __u32 r5; @@ -54,7 +52,6 @@ struct cpu_context_save { struct thread_info { unsigned long flags; /* low level flags */ int preempt_count; /* 0 => preemptable, <0 => bug */ - mm_segment_t addr_limit; /* address limit */ struct task_struct *task; /* main task structure */ __u32 cpu; /* cpu */ __u32 cpu_domain; /* cpu domain */ @@ -80,7 +77,6 @@ struct thread_info { .task = &tsk, \ .flags = 0, \ .preempt_count = INIT_PREEMPT_COUNT, \ - .addr_limit = KERNEL_DS, \ } /* diff --git a/arch/arm/include/asm/uaccess-asm.h b/arch/arm/include/asm/uaccess-asm.h index e6eb7a2aaf1e..6451a433912c 100644 --- a/arch/arm/include/asm/uaccess-asm.h +++ b/arch/arm/include/asm/uaccess-asm.h @@ -84,12 +84,8 @@ * if \disable is set. */ .macro uaccess_entry, tsk, tmp0, tmp1, tmp2, disable - ldr \tmp1, [\tsk, #TI_ADDR_LIMIT] - ldr \tmp2, =TASK_SIZE - str \tmp2, [\tsk, #TI_ADDR_LIMIT] DACR( mrc p15, 0, \tmp0, c3, c0, 0) DACR( str \tmp0, [sp, #SVC_DACR]) - str \tmp1, [sp, #SVC_ADDR_LIMIT] .if \disable && IS_ENABLED(CONFIG_CPU_SW_DOMAIN_PAN) /* kernel=client, user=no access */ mov \tmp2, #DACR_UACCESS_DISABLE @@ -106,9 +102,7 @@ /* Restore the user access state previously saved by uaccess_entry */ .macro uaccess_exit, tsk, tmp0, tmp1 - ldr \tmp1, [sp, #SVC_ADDR_LIMIT] DACR( ldr \tmp0, [sp, #SVC_DACR]) - str \tmp1, [\tsk, #TI_ADDR_LIMIT] DACR( mcr p15, 0, \tmp0, c3, c0, 0) .endm diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h index 4f60638755c4..084d1c07c2d0 100644 --- a/arch/arm/include/asm/uaccess.h +++ b/arch/arm/include/asm/uaccess.h @@ -52,32 +52,8 @@ static __always_inline void uaccess_restore(unsigned int flags) extern int __get_user_bad(void); extern int __put_user_bad(void); -/* - * Note that this is actually 0x1,0000,0000 - */ -#define KERNEL_DS 0x00000000 - #ifdef CONFIG_MMU -#define USER_DS TASK_SIZE -#define get_fs() (current_thread_info()->addr_limit) - -static inline void set_fs(mm_segment_t fs) -{ - current_thread_info()->addr_limit = fs; - - /* - * Prevent a mispredicted conditional call to set_fs from forwarding - * the wrong address limit to access_ok under speculation. - */ - dsb(nsh); - isb(); - - modify_domain(DOMAIN_KERNEL, fs ? DOMAIN_CLIENT : DOMAIN_MANAGER); -} - -#define uaccess_kernel() (get_fs() == KERNEL_DS) - /* * We use 33-bit arithmetic here. Success returns zero, failure returns * addr_limit. We take advantage that addr_limit will be zero for KERNEL_DS, @@ -89,7 +65,7 @@ static inline void set_fs(mm_segment_t fs) __asm__(".syntax unified\n" \ "adds %1, %2, %3; sbcscc %1, %1, %0; movcc %0, #0" \ : "=&r" (flag), "=&r" (roksum) \ - : "r" (addr), "Ir" (size), "0" (current_thread_info()->addr_limit) \ + : "r" (addr), "Ir" (size), "0" (TASK_SIZE) \ : "cc"); \ flag; }) @@ -120,7 +96,7 @@ static inline void __user *__uaccess_mask_range_ptr(const void __user *ptr, " subshs %1, %1, %2\n" " movlo %0, #0\n" : "+r" (safe_ptr), "=&r" (tmp) - : "r" (size), "r" (current_thread_info()->addr_limit) + : "r" (size), "r" (TASK_SIZE) : "cc"); csdb(); @@ -194,7 +170,7 @@ extern int __get_user_64t_4(void *); #define __get_user_check(x, p) \ ({ \ - unsigned long __limit = current_thread_info()->addr_limit - 1; \ + unsigned long __limit = TASK_SIZE - 1; \ register typeof(*(p)) __user *__p asm("r0") = (p); \ register __inttype(x) __r2 asm("r2"); \ register unsigned long __l asm("r1") = __limit; \ @@ -245,7 +221,7 @@ extern int __put_user_8(void *, unsigned long long); #define __put_user_check(__pu_val, __ptr, __err, __s) \ ({ \ - unsigned long __limit = current_thread_info()->addr_limit - 1; \ + unsigned long __limit = TASK_SIZE - 1; \ register typeof(__pu_val) __r2 asm("r2") = __pu_val; \ register const void __user *__p asm("r0") = __ptr; \ register unsigned long __l asm("r1") = __limit; \ @@ -262,19 +238,8 @@ extern int __put_user_8(void *, unsigned long long); #else /* CONFIG_MMU */ -/* - * uClinux has only one addr space, so has simplified address limits. - */ -#define USER_DS KERNEL_DS - -#define uaccess_kernel() (true) #define __addr_ok(addr) ((void)(addr), 1) #define __range_ok(addr, size) ((void)(addr), 0) -#define get_fs() (KERNEL_DS) - -static inline void set_fs(mm_segment_t fs) -{ -} #define get_user(x, p) __get_user(x, p) #define __put_user_check __put_user_nocheck @@ -283,9 +248,6 @@ static inline void set_fs(mm_segment_t fs) #define access_ok(addr, size) (__range_ok(addr, size) == 0) -#define user_addr_max() \ - (uaccess_kernel() ? ~0UL : get_fs()) - #ifdef CONFIG_CPU_SPECTRE /* * When mitigating Spectre variant 1, it is not worth fixing the non- diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c index a0945b898ca3..c60fefabc868 100644 --- a/arch/arm/kernel/asm-offsets.c +++ b/arch/arm/kernel/asm-offsets.c @@ -43,7 +43,6 @@ int main(void) BLANK(); DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count)); - DEFINE(TI_ADDR_LIMIT, offsetof(struct thread_info, addr_limit)); DEFINE(TI_TASK, offsetof(struct thread_info, task)); DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); DEFINE(TI_CPU_DOMAIN, offsetof(struct thread_info, cpu_domain)); @@ -92,7 +91,6 @@ int main(void) DEFINE(S_OLD_R0, offsetof(struct pt_regs, ARM_ORIG_r0)); DEFINE(PT_REGS_SIZE, sizeof(struct pt_regs)); DEFINE(SVC_DACR, offsetof(struct svc_pt_regs, dacr)); - DEFINE(SVC_ADDR_LIMIT, offsetof(struct svc_pt_regs, addr_limit)); DEFINE(SVC_REGS_SIZE, sizeof(struct svc_pt_regs)); BLANK(); DEFINE(SIGFRAME_RC3_OFFSET, offsetof(struct sigframe, retcode[3])); diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index e837af90cd44..d9c99db50243 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -49,10 +49,6 @@ __ret_fast_syscall: UNWIND(.fnstart ) UNWIND(.cantunwind ) disable_irq_notrace @ disable interrupts - ldr r2, [tsk, #TI_ADDR_LIMIT] - ldr r1, =TASK_SIZE - cmp r2, r1 - blne addr_limit_check_failed ldr r1, [tsk, #TI_FLAGS] @ re-check for syscall tracing movs r1, r1, lsl #16 bne fast_work_pending @@ -87,10 +83,6 @@ __ret_fast_syscall: bl do_rseq_syscall #endif disable_irq_notrace @ disable interrupts - ldr r2, [tsk, #TI_ADDR_LIMIT] - ldr r1, =TASK_SIZE - cmp r2, r1 - blne addr_limit_check_failed ldr r1, [tsk, #TI_FLAGS] @ re-check for syscall tracing movs r1, r1, lsl #16 beq no_work_pending @@ -129,10 +121,6 @@ ret_slow_syscall: #endif disable_irq_notrace @ disable interrupts ENTRY(ret_to_user_from_irq) - ldr r2, [tsk, #TI_ADDR_LIMIT] - ldr r1, =TASK_SIZE - cmp r2, r1 - blne addr_limit_check_failed ldr r1, [tsk, #TI_FLAGS] movs r1, r1, lsl #16 bne slow_work_pending diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index fc9e8b37eaa8..581542fbf5bf 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -108,7 +108,7 @@ void __show_regs(struct pt_regs *regs) unsigned long flags; char buf[64]; #ifndef CONFIG_CPU_V7M - unsigned int domain, fs; + unsigned int domain; #ifdef CONFIG_CPU_SW_DOMAIN_PAN /* * Get the domain register for the parent context. In user @@ -117,14 +117,11 @@ void __show_regs(struct pt_regs *regs) */ if (user_mode(regs)) { domain = DACR_UACCESS_ENABLE; - fs = get_fs(); } else { domain = to_svc_pt_regs(regs)->dacr; - fs = to_svc_pt_regs(regs)->addr_limit; } #else domain = get_domain(); - fs = get_fs(); #endif #endif @@ -160,8 +157,6 @@ void __show_regs(struct pt_regs *regs) if ((domain & domain_mask(DOMAIN_USER)) == domain_val(DOMAIN_USER, DOMAIN_NOACCESS)) segment = "none"; - else if (fs == KERNEL_DS) - segment = "kernel"; else segment = "user"; diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index a3a38d0a4c85..3e7ddac086c2 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -711,14 +711,6 @@ struct page *get_signal_page(void) return page; } -/* Defer to generic check */ -asmlinkage void addr_limit_check_failed(void) -{ -#ifdef CONFIG_MMU - addr_limit_user_check(); -#endif -} - #ifdef CONFIG_DEBUG_RSEQ asmlinkage void do_rseq_syscall(struct pt_regs *regs) { diff --git a/arch/arm/lib/copy_from_user.S b/arch/arm/lib/copy_from_user.S index f8016e3db65d..480a20766137 100644 --- a/arch/arm/lib/copy_from_user.S +++ b/arch/arm/lib/copy_from_user.S @@ -109,8 +109,7 @@ ENTRY(arm_copy_from_user) #ifdef CONFIG_CPU_SPECTRE - get_thread_info r3 - ldr r3, [r3, #TI_ADDR_LIMIT] + ldr r3, =TASK_SIZE uaccess_mask_range_ptr r1, r2, r3, ip #endif diff --git a/arch/arm/lib/copy_to_user.S b/arch/arm/lib/copy_to_user.S index ebfe4cb3d912..842ea5ede485 100644 --- a/arch/arm/lib/copy_to_user.S +++ b/arch/arm/lib/copy_to_user.S @@ -109,8 +109,7 @@ ENTRY(__copy_to_user_std) WEAK(arm_copy_to_user) #ifdef CONFIG_CPU_SPECTRE - get_thread_info r3 - ldr r3, [r3, #TI_ADDR_LIMIT] + ldr r3, =TASK_SIZE uaccess_mask_range_ptr r0, r2, r3, ip #endif From da0b9ee43c152401f711e522c19b1468c84907bf Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 11 Aug 2021 08:30:27 +0100 Subject: [PATCH 163/696] ARM: 9110/1: oabi-compat: fix oabi epoll sparse warning As my patches change the oabi epoll definition, I received a report from the kernel test robot about a pre-existing issue with a mismatched __poll_t type. The OABI code was correct when it was initially added in linux-2.16, but a later (also correct) change to the generic __poll_t triggered a type mismatch warning from sparse. As __poll_t is always 32-bit bits wide and otherwise compatible, using this instead of __u32 in the oabi_epoll_event definition is a valid workaround. Reported-by: kernel test robot Fixes: 8ced390c2b18 ("define __poll_t, annotate constants") Fixes: ee219b946e4b ("uapi: turn __poll_t sparse checks on by default") Fixes: 687ad0191488 ("[ARM] 3109/1: old ABI compat: syscall wrappers for ABI impedance matching") Acked-by: Christoph Hellwig Signed-off-by: Arnd Bergmann Signed-off-by: Russell King (Oracle) --- arch/arm/kernel/sys_oabi-compat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/kernel/sys_oabi-compat.c b/arch/arm/kernel/sys_oabi-compat.c index 223ee46b6e75..68112c172025 100644 --- a/arch/arm/kernel/sys_oabi-compat.c +++ b/arch/arm/kernel/sys_oabi-compat.c @@ -274,7 +274,7 @@ out: } struct oabi_epoll_event { - __u32 events; + __poll_t events; __u64 data; } __attribute__ ((packed,aligned(4))); From 88210317eec69d8c06cac6d6751528160e153ffd Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 11 Aug 2021 10:27:03 +0100 Subject: [PATCH 164/696] ARM: 9116/1: unified: Remove check for gcc < 4 Since commit cafa0010cd51fb71 ("Raise the minimum required gcc version to 4.6"), the kernel can no longer be compiled using gcc-3. Hence this condition is never true, and the check can thus be removed. Signed-off-by: Geert Uytterhoeven Signed-off-by: Russell King (Oracle) --- arch/arm/include/asm/unified.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/arm/include/asm/unified.h b/arch/arm/include/asm/unified.h index 1e2c3eb04353..ce9689118dbb 100644 --- a/arch/arm/include/asm/unified.h +++ b/arch/arm/include/asm/unified.h @@ -24,10 +24,6 @@ __asm__(".syntax unified"); #ifdef CONFIG_THUMB2_KERNEL -#if __GNUC__ < 4 -#error Thumb-2 kernel requires gcc >= 4 -#endif - /* The CPSR bit describing the instruction set (Thumb) */ #define PSR_ISETSTATE PSR_T_BIT From c747ce4706190ef40634dd1366efc75a42415f05 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 11 Aug 2021 10:27:04 +0100 Subject: [PATCH 165/696] ARM: 9117/1: asm-generic: div64: Remove always-true __div64_const32_is_OK() Since commit cafa0010cd51fb71 ("Raise the minimum required gcc version to 4.6"), the kernel can no longer be compiled using gcc-3. Hence __div64_const32_is_OK() is always true, and the corresponding check can thus be removed. While at it, remove the whitespace error that hurts my eyes, and add the missing curly braces for the final else statement, as per coding style. Signed-off-by: Geert Uytterhoeven Acked-by: Arnd Bergmann Signed-off-by: Russell King (Oracle) --- include/asm-generic/div64.h | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/include/asm-generic/div64.h b/include/asm-generic/div64.h index cd905b44a630..13f5aa68a455 100644 --- a/include/asm-generic/div64.h +++ b/include/asm-generic/div64.h @@ -57,17 +57,11 @@ /* * If the divisor happens to be constant, we determine the appropriate * inverse at compile time to turn the division into a few inline - * multiplications which ought to be much faster. And yet only if compiling - * with a sufficiently recent gcc version to perform proper 64-bit constant - * propagation. + * multiplications which ought to be much faster. * * (It is unfortunate that gcc doesn't perform all this internally.) */ -#ifndef __div64_const32_is_OK -#define __div64_const32_is_OK (__GNUC__ >= 4) -#endif - #define __div64_const32(n, ___b) \ ({ \ /* \ @@ -230,8 +224,7 @@ extern uint32_t __div64_32(uint64_t *dividend, uint32_t divisor); is_power_of_2(__base)) { \ __rem = (n) & (__base - 1); \ (n) >>= ilog2(__base); \ - } else if (__div64_const32_is_OK && \ - __builtin_constant_p(__base) && \ + } else if (__builtin_constant_p(__base) && \ __base != 0) { \ uint32_t __res_lo, __n_lo = (n); \ (n) = __div64_const32(n, __base); \ @@ -241,8 +234,9 @@ extern uint32_t __div64_32(uint64_t *dividend, uint32_t divisor); } else if (likely(((n) >> 32) == 0)) { \ __rem = (uint32_t)(n) % __base; \ (n) = (uint32_t)(n) / __base; \ - } else \ + } else { \ __rem = __div64_32(&(n), __base); \ + } \ __rem; \ }) From 6c974e79d37608bc8fd5cf6b61b4233b82b60428 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 11 Aug 2021 10:27:02 +0100 Subject: [PATCH 166/696] ARM: 9118/1: div64: Remove always-true __div64_const32_is_OK() duplicate Since commit cafa0010cd51fb71 ("Raise the minimum required gcc version to 4.6"), the kernel can no longer be compiled using gcc-3. Hence __div64_const32_is_OK() is always true. Moreover, __div64_const32_is_OK() is defined in the same way in include/asm-generic/div64.h, so the ARM-specific definition can be removed regardless. Signed-off-by: Geert Uytterhoeven Signed-off-by: Russell King (Oracle) --- arch/arm/include/asm/div64.h | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/arch/arm/include/asm/div64.h b/arch/arm/include/asm/div64.h index 595e538f5bfb..4b69cf850451 100644 --- a/arch/arm/include/asm/div64.h +++ b/arch/arm/include/asm/div64.h @@ -52,17 +52,6 @@ static inline uint32_t __div64_32(uint64_t *n, uint32_t base) #else -/* - * gcc versions earlier than 4.0 are simply too problematic for the - * __div64_const32() code in asm-generic/div64.h. First there is - * gcc PR 15089 that tend to trig on more complex constructs, spurious - * .global __udivsi3 are inserted even if none of those symbols are - * referenced in the generated code, and those gcc versions are not able - * to do constant propagation on long long values anyway. - */ - -#define __div64_const32_is_OK (__GNUC__ >= 4) - static inline uint64_t __arch_xprod_64(uint64_t m, uint64_t n, bool bias) { unsigned long long res; From d44f571ff5ce51298df520cc46c3a9f5b983fc0a Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Thu, 12 Aug 2021 09:50:29 +0000 Subject: [PATCH 167/696] Documentation/process/applying-patches: Activate linux-next man hyperlink There is a url for linux-next in the 'applying-patches.rst', but it's surrounded by backquotes. So the url doesn't have a hyperlink in the built document. To let readers easily move to the page, this commit puts the url outside of the backquotes so that a hyperlink to the url can be automatically made. Signed-off-by: SeongJae Park Link: https://lore.kernel.org/r/20210812095030.4704-1-sj38.park@gmail.com Signed-off-by: Jonathan Corbet --- Documentation/process/applying-patches.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/process/applying-patches.rst b/Documentation/process/applying-patches.rst index 2e7017bef4b8..c2121c1e55d7 100644 --- a/Documentation/process/applying-patches.rst +++ b/Documentation/process/applying-patches.rst @@ -389,7 +389,7 @@ The -mm patches are experimental patches released by Andrew Morton. In the past, -mm tree were used to also test subsystem patches, but this function is now done via the -`linux-next ` +`linux-next` (https://www.kernel.org/doc/man-pages/linux-next.html) tree. The Subsystem maintainers push their patches first to linux-next, and, during the merge window, sends them directly to Linus. From 251a7b3edc197a3947b8cb56fffe61d811aba0a5 Mon Sep 17 00:00:00 2001 From: Peilin Ye Date: Wed, 18 Aug 2021 15:01:23 -0700 Subject: [PATCH 168/696] docs: x86: Remove obsolete information about x86_64 vmalloc() faulting x86_64 vmalloc() mappings are no longer "synchronized" among page tables via faulting since commit 6eb82f994026 ("x86/mm: Pre-allocate P4D/PUD pages for vmalloc area"), since the corresponding P4D or PUD pages are now preallocated at boot, by preallocate_vmalloc_pages(). Drop the "lazily synchronized" description for less confusion. While this file is x86_64-specific, it is worth noting that things are different for x86_32, where vmalloc()-related changes to `init_mm.pgd` are synchronized to all page tables in the system during runtime, via arch_sync_kernel_mappings(). Unfortunately, this synchronization is subject to race condition, which is further handled via faulting, see vmalloc_fault(). See commit 4819e15f740e ("x86/mm/32: Bring back vmalloc faulting on x86_32") for more details. Reviewed-by: Muchun Song Signed-off-by: Peilin Ye Reviewed-by: Joerg Roedel Link: https://lore.kernel.org/r/20210818220123.2623-1-yepeilin.cs@gmail.com Signed-off-by: Jonathan Corbet --- Documentation/x86/x86_64/mm.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Documentation/x86/x86_64/mm.rst b/Documentation/x86/x86_64/mm.rst index ede1875719fb..9798676bb0bf 100644 --- a/Documentation/x86/x86_64/mm.rst +++ b/Documentation/x86/x86_64/mm.rst @@ -140,10 +140,6 @@ The direct mapping covers all memory in the system up to the highest memory address (this means in some cases it can also include PCI memory holes). -vmalloc space is lazily synchronized into the different PML4/PML5 pages of -the processes using the page fault handler, with init_top_pgt as -reference. - We map EFI runtime services in the 'efi_pgd' PGD in a 64Gb large virtual memory window (this size is arbitrary, it can be raised later if needed). The mappings are not part of any other kernel PGD and are only available From 630c8fa02f9adf83614871c16c651f049b92f6a7 Mon Sep 17 00:00:00 2001 From: Chun-Hung Tseng Date: Fri, 20 Aug 2021 22:21:52 +0000 Subject: [PATCH 169/696] Documentation: Update details of The Linux Kernel Module Programming Guide Recently, the content and examples of the book "The Linux Kernel Module Programming Guide" are being actively maintained and added on Github[1]. Currently, the book is being regularly built into webpage and pdf file using Github static page[2]. [1]: https://github.com/sysprog21/lkmpg [2]: https://sysprog21.github.io/lkmpg/ Signed-off-by: Chun-Hung Tseng Link: https://lore.kernel.org/r/20210820222152.971174-1-henrybear327@gmail.com [jc: fixed docs-build warnings] Signed-off-by: Jonathan Corbet --- Documentation/process/kernel-docs.rst | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Documentation/process/kernel-docs.rst b/Documentation/process/kernel-docs.rst index 22d9ace5df2a..da9527502ef0 100644 --- a/Documentation/process/kernel-docs.rst +++ b/Documentation/process/kernel-docs.rst @@ -126,15 +126,17 @@ On-line docs describes how to write user-mode utilities for communicating with Card Services. - * Title: **Linux Kernel Module Programming Guide** + * Title: **The Linux Kernel Module Programming Guide** - :Author: Ori Pomerantz. - :URL: https://tldp.org/LDP/lkmpg/2.6/html/index.html - :Date: 2001 + :Author: Peter Jay Salzman, Michael Burian, Ori Pomerantz, Bob Mottram, + Jim Huang. + :URL: https://sysprog21.github.io/lkmpg/ + :Date: 2021 :Keywords: modules, GPL book, /proc, ioctls, system calls, interrupt handlers . - :Description: Very nice 92 pages GPL book on the topic of modules - programming. Lots of examples. + :Description: A very nice GPL book on the topic of modules + programming. Lots of examples. Currently the new version is being + actively maintained at https://github.com/sysprog21/lkmpg. * Title: **Global spinlock list and usage** From e24d12b7442afa9d41331a951fca467449ff1488 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 14 Jul 2021 16:23:19 -0400 Subject: [PATCH 170/696] init: split get_fs_names Split get_fs_names into one function that splits up the command line argument, and one that gets the list of all registered file systems. Signed-off-by: Christoph Hellwig Signed-off-by: Al Viro --- init/do_mounts.c | 50 ++++++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/init/do_mounts.c b/init/do_mounts.c index 74aede860de7..ec32de3ad52b 100644 --- a/init/do_mounts.c +++ b/init/do_mounts.c @@ -338,30 +338,31 @@ __setup("rootflags=", root_data_setup); __setup("rootfstype=", fs_names_setup); __setup("rootdelay=", root_delay_setup); -static void __init get_fs_names(char *page) +static void __init split_fs_names(char *page, char *names) { - char *s = page; - - if (root_fs_names) { - strcpy(page, root_fs_names); - while (*s++) { - if (s[-1] == ',') - s[-1] = '\0'; - } - } else { - int len = get_filesystem_list(page); - char *p, *next; - - page[len] = '\0'; - for (p = page-1; p; p = next) { - next = strchr(++p, '\n'); - if (*p++ != '\t') - continue; - while ((*s++ = *p++) != '\n') - ; - s[-1] = '\0'; - } + strcpy(page, root_fs_names); + while (*page++) { + if (page[-1] == ',') + page[-1] = '\0'; } + *page = '\0'; +} + +static void __init get_all_fs_names(char *page) +{ + int len = get_filesystem_list(page); + char *s = page, *p, *next; + + page[len] = '\0'; + for (p = page - 1; p; p = next) { + next = strchr(++p, '\n'); + if (*p++ != '\t') + continue; + while ((*s++ = *p++) != '\n') + ; + s[-1] = '\0'; + } + *s = '\0'; } @@ -411,7 +412,10 @@ void __init mount_block_root(char *name, int flags) scnprintf(b, BDEVNAME_SIZE, "unknown-block(%u,%u)", MAJOR(ROOT_DEV), MINOR(ROOT_DEV)); - get_fs_names(fs_names); + if (root_fs_names) + split_fs_names(fs_names, root_fs_names); + else + get_all_fs_names(fs_names); retry: for (p = fs_names; *p; p += strlen(p)+1) { int err = do_mount_root(name, p, flags, root_mount_data); From f9259be6a9e7c22d92e5a5000913147ae17e8321 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 14 Jul 2021 16:23:20 -0400 Subject: [PATCH 171/696] init: allow mounting arbitrary non-blockdevice filesystems as root Currently the only non-blockdevice filesystems that can be used as the initial root filesystem are NFS and CIFS, which use the magic "root=/dev/nfs" and "root=/dev/cifs" syntax that requires the root device file system details to come from filesystem specific kernel command line options. Add a little bit of new code that allows to just pass arbitrary string mount options to any non-blockdevice filesystems so that it can be mounted as the root file system. For example a virtiofs root file system can be mounted using the following syntax: "root=myfs rootfstype=virtiofs rw" Based on an earlier patch from Vivek Goyal . Signed-off-by: Christoph Hellwig Signed-off-by: Al Viro --- init/do_mounts.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/init/do_mounts.c b/init/do_mounts.c index ec32de3ad52b..bdeb90b8d669 100644 --- a/init/do_mounts.c +++ b/init/do_mounts.c @@ -534,6 +534,45 @@ static int __init mount_cifs_root(void) } #endif +static bool __init fs_is_nodev(char *fstype) +{ + struct file_system_type *fs = get_fs_type(fstype); + bool ret = false; + + if (fs) { + ret = !(fs->fs_flags & FS_REQUIRES_DEV); + put_filesystem(fs); + } + + return ret; +} + +static int __init mount_nodev_root(void) +{ + char *fs_names, *fstype; + int err = -EINVAL; + + fs_names = (void *)__get_free_page(GFP_KERNEL); + if (!fs_names) + return -EINVAL; + split_fs_names(fs_names, root_fs_names); + + for (fstype = fs_names; *fstype; fstype += strlen(fstype) + 1) { + if (!fs_is_nodev(fstype)) + continue; + err = do_mount_root(root_device_name, fstype, root_mountflags, + root_mount_data); + if (!err) + break; + if (err != -EACCES && err != -EINVAL) + panic("VFS: Unable to mount root \"%s\" (%s), err=%d\n", + root_device_name, fstype, err); + } + + free_page((unsigned long)fs_names); + return err; +} + void __init mount_root(void) { #ifdef CONFIG_ROOT_NFS @@ -550,6 +589,10 @@ void __init mount_root(void) return; } #endif + if (ROOT_DEV == 0 && root_device_name && root_fs_names) { + if (mount_nodev_root() == 0) + return; + } #ifdef CONFIG_BLOCK { int err = create_dev("/dev/root", ROOT_DEV); From 6e7c1770a212239e88ec01ddc7a741505bfd10e5 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 14 Jul 2021 16:23:21 -0400 Subject: [PATCH 172/696] fs: simplify get_filesystem_list / get_all_fs_names Just output the '\0' separate list of supported file systems for block devices directly rather than going through a pointless round of string manipulation. Based on an earlier patch from Al Viro . Vivek: Modified list_bdev_fs_names() and split_fs_names() to return number of null terminted strings to caller. Callers now use that information to loop through all the strings instead of relying on one extra null char being present at the end. Signed-off-by: Christoph Hellwig Signed-off-by: Vivek Goyal Signed-off-by: Al Viro --- fs/filesystems.c | 27 +++++++++++++++---------- include/linux/fs.h | 2 +- init/do_mounts.c | 49 ++++++++++++++++++++-------------------------- 3 files changed, 39 insertions(+), 39 deletions(-) diff --git a/fs/filesystems.c b/fs/filesystems.c index 90b8d879fbaf..58b9067b2391 100644 --- a/fs/filesystems.c +++ b/fs/filesystems.c @@ -209,21 +209,28 @@ SYSCALL_DEFINE3(sysfs, int, option, unsigned long, arg1, unsigned long, arg2) } #endif -int __init get_filesystem_list(char *buf) +int __init list_bdev_fs_names(char *buf, size_t size) { - int len = 0; - struct file_system_type * tmp; + struct file_system_type *p; + size_t len; + int count = 0; read_lock(&file_systems_lock); - tmp = file_systems; - while (tmp && len < PAGE_SIZE - 80) { - len += sprintf(buf+len, "%s\t%s\n", - (tmp->fs_flags & FS_REQUIRES_DEV) ? "" : "nodev", - tmp->name); - tmp = tmp->next; + for (p = file_systems; p; p = p->next) { + if (!(p->fs_flags & FS_REQUIRES_DEV)) + continue; + len = strlen(p->name) + 1; + if (len > size) { + pr_warn("%s: truncating file system list\n", __func__); + break; + } + memcpy(buf, p->name, len); + buf += len; + size -= len; + count++; } read_unlock(&file_systems_lock); - return len; + return count; } #ifdef CONFIG_PROC_FS diff --git a/include/linux/fs.h b/include/linux/fs.h index 640574294216..c76dfc01cf9d 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -3622,7 +3622,7 @@ int proc_nr_dentry(struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos); int proc_nr_inodes(struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos); -int __init get_filesystem_list(char *buf); +int __init list_bdev_fs_names(char *buf, size_t size); #define __FMODE_EXEC ((__force int) FMODE_EXEC) #define __FMODE_NONOTIFY ((__force int) FMODE_NONOTIFY) diff --git a/init/do_mounts.c b/init/do_mounts.c index bdeb90b8d669..9b4a1f877e47 100644 --- a/init/do_mounts.c +++ b/init/do_mounts.c @@ -338,32 +338,22 @@ __setup("rootflags=", root_data_setup); __setup("rootfstype=", fs_names_setup); __setup("rootdelay=", root_delay_setup); -static void __init split_fs_names(char *page, char *names) +static int __init split_fs_names(char *page, char *names) { - strcpy(page, root_fs_names); - while (*page++) { - if (page[-1] == ',') - page[-1] = '\0'; + int count = 0; + char *p = page; + + strcpy(p, root_fs_names); + while (*p++) { + if (p[-1] == ',') + p[-1] = '\0'; } - *page = '\0'; -} + *p = '\0'; -static void __init get_all_fs_names(char *page) -{ - int len = get_filesystem_list(page); - char *s = page, *p, *next; + for (p = page; *p; p += strlen(p)+1) + count++; - page[len] = '\0'; - for (p = page - 1; p; p = next) { - next = strchr(++p, '\n'); - if (*p++ != '\t') - continue; - while ((*s++ = *p++) != '\n') - ; - s[-1] = '\0'; - } - - *s = '\0'; + return count; } static int __init do_mount_root(const char *name, const char *fs, @@ -409,15 +399,16 @@ void __init mount_block_root(char *name, int flags) char *fs_names = page_address(page); char *p; char b[BDEVNAME_SIZE]; + int num_fs, i; scnprintf(b, BDEVNAME_SIZE, "unknown-block(%u,%u)", MAJOR(ROOT_DEV), MINOR(ROOT_DEV)); if (root_fs_names) - split_fs_names(fs_names, root_fs_names); + num_fs = split_fs_names(fs_names, root_fs_names); else - get_all_fs_names(fs_names); + num_fs = list_bdev_fs_names(fs_names, PAGE_SIZE); retry: - for (p = fs_names; *p; p += strlen(p)+1) { + for (i = 0, p = fs_names; i < num_fs; i++, p += strlen(p)+1) { int err = do_mount_root(name, p, flags, root_mount_data); switch (err) { case 0: @@ -450,7 +441,7 @@ retry: printk("List of all partitions:\n"); printk_all_partitions(); printk("No filesystem could mount root, tried: "); - for (p = fs_names; *p; p += strlen(p)+1) + for (i = 0, p = fs_names; i < num_fs; i++, p += strlen(p)+1) printk(" %s", p); printk("\n"); panic("VFS: Unable to mount root fs on %s", b); @@ -551,13 +542,15 @@ static int __init mount_nodev_root(void) { char *fs_names, *fstype; int err = -EINVAL; + int num_fs, i; fs_names = (void *)__get_free_page(GFP_KERNEL); if (!fs_names) return -EINVAL; - split_fs_names(fs_names, root_fs_names); + num_fs = split_fs_names(fs_names, root_fs_names); - for (fstype = fs_names; *fstype; fstype += strlen(fstype) + 1) { + for (i = 0, fstype = fs_names; i < num_fs; + i++, fstype += strlen(fstype) + 1) { if (!fs_is_nodev(fstype)) continue; err = do_mount_root(root_device_name, fstype, root_mountflags, From d00aa8061e04da5c570a54283462e47fab01bd3c Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 20 Jul 2021 08:41:19 -0600 Subject: [PATCH 173/696] ARM: dts: omap: Drop references to opp.txt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit opp.txt is getting removed with the OPP binding converted to DT schema. As it is unusual to reference a binding doc from a dts file, let's just remove the reference. Cc: "Benoît Cousson" Cc: Tony Lindgren Signed-off-by: Rob Herring Signed-off-by: Viresh Kumar --- arch/arm/boot/dts/omap34xx.dtsi | 1 - arch/arm/boot/dts/omap36xx.dtsi | 1 - 2 files changed, 2 deletions(-) diff --git a/arch/arm/boot/dts/omap34xx.dtsi b/arch/arm/boot/dts/omap34xx.dtsi index feaa43b78535..8b8451399784 100644 --- a/arch/arm/boot/dts/omap34xx.dtsi +++ b/arch/arm/boot/dts/omap34xx.dtsi @@ -24,7 +24,6 @@ }; }; - /* see Documentation/devicetree/bindings/opp/opp.txt */ cpu0_opp_table: opp-table { compatible = "operating-points-v2-ti-cpu"; syscon = <&scm_conf>; diff --git a/arch/arm/boot/dts/omap36xx.dtsi b/arch/arm/boot/dts/omap36xx.dtsi index 20844dbc002e..22b33098b1a2 100644 --- a/arch/arm/boot/dts/omap36xx.dtsi +++ b/arch/arm/boot/dts/omap36xx.dtsi @@ -29,7 +29,6 @@ }; }; - /* see Documentation/devicetree/bindings/opp/opp.txt */ cpu0_opp_table: opp-table { compatible = "operating-points-v2-ti-cpu"; syscon = <&scm_conf>; From 29fc76957a9754768cfa3884b413ffc10f82d3b4 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 20 Jul 2021 08:41:20 -0600 Subject: [PATCH 174/696] dt-bindings: Clean-up OPP binding node names in examples In preparation to convert OPP bindings to DT schema, clean-up a few OPP binding node names in the binding examples. Cc: Georgi Djakov Cc: Shawn Guo Cc: Sascha Hauer Cc: Leonard Crestez Acked-by: Viresh Kumar Signed-off-by: Rob Herring Acked-by: Georgi Djakov Signed-off-by: Viresh Kumar --- Documentation/devicetree/bindings/gpu/arm,mali-bifrost.yaml | 2 +- Documentation/devicetree/bindings/gpu/arm,mali-midgard.yaml | 2 +- .../devicetree/bindings/interconnect/fsl,imx8m-noc.yaml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/gpu/arm,mali-bifrost.yaml b/Documentation/devicetree/bindings/gpu/arm,mali-bifrost.yaml index 0f73f436bea7..4bea51d1e7ea 100644 --- a/Documentation/devicetree/bindings/gpu/arm,mali-bifrost.yaml +++ b/Documentation/devicetree/bindings/gpu/arm,mali-bifrost.yaml @@ -136,7 +136,7 @@ examples: resets = <&reset 0>, <&reset 1>; }; - gpu_opp_table: opp_table0 { + gpu_opp_table: opp-table { compatible = "operating-points-v2"; opp-533000000 { diff --git a/Documentation/devicetree/bindings/gpu/arm,mali-midgard.yaml b/Documentation/devicetree/bindings/gpu/arm,mali-midgard.yaml index 696c17aedbbe..d209f272625d 100644 --- a/Documentation/devicetree/bindings/gpu/arm,mali-midgard.yaml +++ b/Documentation/devicetree/bindings/gpu/arm,mali-midgard.yaml @@ -160,7 +160,7 @@ examples: #cooling-cells = <2>; }; - gpu_opp_table: opp_table0 { + gpu_opp_table: opp-table { compatible = "operating-points-v2"; opp-533000000 { diff --git a/Documentation/devicetree/bindings/interconnect/fsl,imx8m-noc.yaml b/Documentation/devicetree/bindings/interconnect/fsl,imx8m-noc.yaml index a8873739d61a..b8204ed22dd5 100644 --- a/Documentation/devicetree/bindings/interconnect/fsl,imx8m-noc.yaml +++ b/Documentation/devicetree/bindings/interconnect/fsl,imx8m-noc.yaml @@ -81,10 +81,10 @@ examples: noc_opp_table: opp-table { compatible = "operating-points-v2"; - opp-133M { + opp-133333333 { opp-hz = /bits/ 64 <133333333>; }; - opp-800M { + opp-800000000 { opp-hz = /bits/ 64 <800000000>; }; }; From 94274f20f6bf5eb0099bbf7e133aac1f5cd087e8 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 20 Jul 2021 08:41:21 -0600 Subject: [PATCH 175/696] dt-bindings: opp: Convert to DT schema Convert the OPP v1 and v2 bindings to DT schema format. As the OPPv2 binding can be extended by vendors, we need to split the common part out from the "operating-points-v2" conforming compatible. Cc: Yangtao Li Cc: Nishanth Menon Cc: Stephen Boyd Cc: Maxime Ripard Cc: Chen-Yu Tsai Acked-by: Viresh Kumar Signed-off-by: Rob Herring Acked-by: Maxime Ripard Signed-off-by: Viresh Kumar --- .../bindings/cpufreq/cpufreq-dt.txt | 2 +- .../bindings/cpufreq/cpufreq-mediatek.txt | 2 +- .../bindings/cpufreq/cpufreq-st.txt | 6 +- .../cpufreq/nvidia,tegra20-cpufreq.txt | 2 +- .../bindings/devfreq/rk3399_dmc.txt | 2 +- .../allwinner,sun50i-h6-operating-points.yaml | 4 + .../devicetree/bindings/opp/opp-v1.yaml | 51 ++ .../devicetree/bindings/opp/opp-v2-base.yaml | 214 ++++++ .../devicetree/bindings/opp/opp-v2.yaml | 475 +++++++++++++ Documentation/devicetree/bindings/opp/opp.txt | 622 ------------------ .../devicetree/bindings/opp/qcom-opp.txt | 2 +- .../bindings/opp/ti-omap5-opp-supply.txt | 2 +- .../bindings/power/power-domain.yaml | 2 +- 13 files changed, 753 insertions(+), 633 deletions(-) create mode 100644 Documentation/devicetree/bindings/opp/opp-v1.yaml create mode 100644 Documentation/devicetree/bindings/opp/opp-v2-base.yaml create mode 100644 Documentation/devicetree/bindings/opp/opp-v2.yaml delete mode 100644 Documentation/devicetree/bindings/opp/opp.txt diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-dt.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-dt.txt index 56f442374383..1d7e49167666 100644 --- a/Documentation/devicetree/bindings/cpufreq/cpufreq-dt.txt +++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-dt.txt @@ -11,7 +11,7 @@ Required properties: - None Optional properties: -- operating-points: Refer to Documentation/devicetree/bindings/opp/opp.txt for +- operating-points: Refer to Documentation/devicetree/bindings/opp/opp-v1.yaml for details. OPPs *must* be supplied either via DT, i.e. this property, or populated at runtime. - clock-latency: Specify the possible maximum transition latency for clock, diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-mediatek.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-mediatek.txt index ef68711716fb..b8233ec91d3d 100644 --- a/Documentation/devicetree/bindings/cpufreq/cpufreq-mediatek.txt +++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-mediatek.txt @@ -10,7 +10,7 @@ Required properties: transition and not stable yet. Please refer to Documentation/devicetree/bindings/clock/clock-bindings.txt for generic clock consumer properties. -- operating-points-v2: Please refer to Documentation/devicetree/bindings/opp/opp.txt +- operating-points-v2: Please refer to Documentation/devicetree/bindings/opp/opp-v2.yaml for detail. - proc-supply: Regulator for Vproc of CPU cluster. diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-st.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-st.txt index d91a02a3b6b0..6b0b452acef0 100644 --- a/Documentation/devicetree/bindings/cpufreq/cpufreq-st.txt +++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-st.txt @@ -6,8 +6,6 @@ from the SoC, then supplies the OPP framework with 'prop' and 'supported hardware' information respectively. The framework is then able to read the DT and operate in the usual way. -For more information about the expected DT format [See: ../opp/opp.txt]. - Frequency Scaling only ---------------------- @@ -15,7 +13,7 @@ No vendor specific driver required for this. Located in CPU's node: -- operating-points : [See: ../power/opp.txt] +- operating-points : [See: ../power/opp-v1.yaml] Example [safe] -------------- @@ -37,7 +35,7 @@ This requires the ST CPUFreq driver to supply 'process' and 'version' info. Located in CPU's node: -- operating-points-v2 : [See ../power/opp.txt] +- operating-points-v2 : [See ../power/opp-v2.yaml] Example [unsafe] ---------------- diff --git a/Documentation/devicetree/bindings/cpufreq/nvidia,tegra20-cpufreq.txt b/Documentation/devicetree/bindings/cpufreq/nvidia,tegra20-cpufreq.txt index 52a24b82fd86..bdbfd7c36101 100644 --- a/Documentation/devicetree/bindings/cpufreq/nvidia,tegra20-cpufreq.txt +++ b/Documentation/devicetree/bindings/cpufreq/nvidia,tegra20-cpufreq.txt @@ -4,7 +4,7 @@ Binding for NVIDIA Tegra20 CPUFreq Required properties: - clocks: Must contain an entry for the CPU clock. See ../clocks/clock-bindings.txt for details. -- operating-points-v2: See ../bindings/opp/opp.txt for details. +- operating-points-v2: See ../bindings/opp/opp-v2.yaml for details. - #cooling-cells: Should be 2. See ../thermal/thermal-cooling-devices.yaml for details. For each opp entry in 'operating-points-v2' table: diff --git a/Documentation/devicetree/bindings/devfreq/rk3399_dmc.txt b/Documentation/devicetree/bindings/devfreq/rk3399_dmc.txt index ac189dd82b08..3fbeb3733c48 100644 --- a/Documentation/devicetree/bindings/devfreq/rk3399_dmc.txt +++ b/Documentation/devicetree/bindings/devfreq/rk3399_dmc.txt @@ -8,7 +8,7 @@ Required properties: - clocks: Phandles for clock specified in "clock-names" property - clock-names : The name of clock used by the DFI, must be "pclk_ddr_mon"; -- operating-points-v2: Refer to Documentation/devicetree/bindings/opp/opp.txt +- operating-points-v2: Refer to Documentation/devicetree/bindings/opp/opp-v2.yaml for details. - center-supply: DMC supply node. - status: Marks the node enabled/disabled. diff --git a/Documentation/devicetree/bindings/opp/allwinner,sun50i-h6-operating-points.yaml b/Documentation/devicetree/bindings/opp/allwinner,sun50i-h6-operating-points.yaml index aeff2bd774dd..729ae97b63d9 100644 --- a/Documentation/devicetree/bindings/opp/allwinner,sun50i-h6-operating-points.yaml +++ b/Documentation/devicetree/bindings/opp/allwinner,sun50i-h6-operating-points.yaml @@ -18,6 +18,9 @@ description: | sun50i-cpufreq-nvmem driver reads the efuse value from the SoC to provide the OPP framework with required information. +allOf: + - $ref: opp-v2-base.yaml# + properties: compatible: const: allwinner,sun50i-h6-operating-points @@ -43,6 +46,7 @@ patternProperties: properties: opp-hz: true + clock-latency-ns: true patternProperties: "opp-microvolt-.*": true diff --git a/Documentation/devicetree/bindings/opp/opp-v1.yaml b/Documentation/devicetree/bindings/opp/opp-v1.yaml new file mode 100644 index 000000000000..d585d536a3fb --- /dev/null +++ b/Documentation/devicetree/bindings/opp/opp-v1.yaml @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/opp/opp-v1.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Generic OPP (Operating Performance Points) v1 Bindings + +maintainers: + - Viresh Kumar + +description: |+ + Devices work at voltage-current-frequency combinations and some implementations + have the liberty of choosing these. These combinations are called Operating + Performance Points aka OPPs. This document defines bindings for these OPPs + applicable across wide range of devices. For illustration purpose, this document + uses CPU as a device. + + This binding only supports voltage-frequency pairs. + +select: true + +properties: + operating-points: + $ref: /schemas/types.yaml#/definitions/uint32-matrix + items: + items: + - description: Frequency in kHz + - description: Voltage for OPP in uV + + +additionalProperties: true +examples: + - | + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "arm,cortex-a9"; + device_type = "cpu"; + reg = <0>; + next-level-cache = <&L2>; + operating-points = + /* kHz uV */ + <792000 1100000>, + <396000 950000>, + <198000 850000>; + }; + }; +... diff --git a/Documentation/devicetree/bindings/opp/opp-v2-base.yaml b/Documentation/devicetree/bindings/opp/opp-v2-base.yaml new file mode 100644 index 000000000000..ae3ae4d39843 --- /dev/null +++ b/Documentation/devicetree/bindings/opp/opp-v2-base.yaml @@ -0,0 +1,214 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/opp/opp-v2-base.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Generic OPP (Operating Performance Points) Common Binding + +maintainers: + - Viresh Kumar + +description: | + Devices work at voltage-current-frequency combinations and some implementations + have the liberty of choosing these. These combinations are called Operating + Performance Points aka OPPs. This document defines bindings for these OPPs + applicable across wide range of devices. For illustration purpose, this document + uses CPU as a device. + + This describes the OPPs belonging to a device. + +select: false + +properties: + $nodename: + pattern: '^opp-table(-[a-z0-9]+)?$' + + opp-shared: + description: + Indicates that device nodes using this OPP Table Node's phandle switch + their DVFS state together, i.e. they share clock/voltage/current lines. + Missing property means devices have independent clock/voltage/current + lines, but they share OPP tables. + type: boolean + +patternProperties: + '^opp-?[0-9]+$': + type: object + description: + One or more OPP nodes describing voltage-current-frequency combinations. + Their name isn't significant but their phandle can be used to reference an + OPP. These are mandatory except for the case where the OPP table is + present only to indicate dependency between devices using the opp-shared + property. + + properties: + opp-hz: + description: + Frequency in Hz, expressed as a 64-bit big-endian integer. This is a + required property for all device nodes, unless another "required" + property to uniquely identify the OPP nodes exists. Devices like power + domains must have another (implementation dependent) property. + + opp-microvolt: + description: | + Voltage for the OPP + + A single regulator's voltage is specified with an array of size one or three. + Single entry is for target voltage and three entries are for + voltages. + + Entries for multiple regulators shall be provided in the same field separated + by angular brackets <>. The OPP binding doesn't provide any provisions to + relate the values to their power supplies or the order in which the supplies + need to be configured and that is left for the implementation specific + binding. + + Entries for all regulators shall be of the same size, i.e. either all use a + single value or triplets. + minItems: 1 + maxItems: 8 # Should be enough regulators + items: + minItems: 1 + maxItems: 3 + + opp-microamp: + description: | + The maximum current drawn by the device in microamperes considering + system specific parameters (such as transients, process, aging, + maximum operating temperature range etc.) as necessary. This may be + used to set the most efficient regulator operating mode. + + Should only be set if opp-microvolt or opp-microvolt- is set for + the OPP. + + Entries for multiple regulators shall be provided in the same field + separated by angular brackets <>. If current values aren't required + for a regulator, then it shall be filled with 0. If current values + aren't required for any of the regulators, then this field is not + required. The OPP binding doesn't provide any provisions to relate the + values to their power supplies or the order in which the supplies need + to be configured and that is left for the implementation specific + binding. + minItems: 1 + maxItems: 8 # Should be enough regulators + + opp-level: + description: + A value representing the performance level of the device. + $ref: /schemas/types.yaml#/definitions/uint32 + + opp-peak-kBps: + description: + Peak bandwidth in kilobytes per second, expressed as an array of + 32-bit big-endian integers. Each element of the array represents the + peak bandwidth value of each interconnect path. The number of elements + should match the number of interconnect paths. + minItems: 1 + maxItems: 32 # Should be enough + + opp-avg-kBps: + description: + Average bandwidth in kilobytes per second, expressed as an array + of 32-bit big-endian integers. Each element of the array represents the + average bandwidth value of each interconnect path. The number of elements + should match the number of interconnect paths. This property is only + meaningful in OPP tables where opp-peak-kBps is present. + minItems: 1 + maxItems: 32 # Should be enough + + clock-latency-ns: + description: + Specifies the maximum possible transition latency (in nanoseconds) for + switching to this OPP from any other OPP. + + turbo-mode: + description: + Marks the OPP to be used only for turbo modes. Turbo mode is available + on some platforms, where the device can run over its operating + frequency for a short duration of time limited by the device's power, + current and thermal limits. + type: boolean + + opp-suspend: + description: + Marks the OPP to be used during device suspend. If multiple OPPs in + the table have this, the OPP with highest opp-hz will be used. + type: boolean + + opp-supported-hw: + description: | + This property allows a platform to enable only a subset of the OPPs + from the larger set present in the OPP table, based on the current + version of the hardware (already known to the operating system). + + Each block present in the array of blocks in this property, represents + a sub-group of hardware versions supported by the OPP. i.e. , , etc. The OPP will be enabled if _any_ of these + sub-groups match the hardware's version. + + Each sub-group is a platform defined array representing the hierarchy + of hardware versions supported by the platform. For a platform with + three hierarchical levels of version (X.Y.Z), this field shall look + like + + opp-supported-hw = , , . + + Each level (eg. X1) in version hierarchy is represented by a 32 bit + value, one bit per version and so there can be maximum 32 versions per + level. Logical AND (&) operation is performed for each level with the + hardware's level version and a non-zero output for _all_ the levels in + a sub-group means the OPP is supported by hardware. A value of + 0xFFFFFFFF for each level in the sub-group will enable the OPP for all + versions for the hardware. + $ref: /schemas/types.yaml#/definitions/uint32-matrix + maxItems: 32 + items: + minItems: 1 + maxItems: 4 + + required-opps: + description: + This contains phandle to an OPP node in another device's OPP table. It + may contain an array of phandles, where each phandle points to an OPP + of a different device. It should not contain multiple phandles to the + OPP nodes in the same OPP table. This specifies the minimum required + OPP of the device(s), whose OPP's phandle is present in this property, + for the functioning of the current device at the current OPP (where + this property is present). + $ref: /schemas/types.yaml#/definitions/phandle-array + + patternProperties: + '^opp-microvolt-': + description: + Named opp-microvolt property. This is exactly similar to the above + opp-microvolt property, but allows multiple voltage ranges to be + provided for the same OPP. At runtime, the platform can pick a + and matching opp-microvolt- property will be enabled for all + OPPs. If the platform doesn't pick a specific or the + doesn't match with any opp-microvolt- properties, then + opp-microvolt property shall be used, if present. + $ref: /schemas/types.yaml#/definitions/uint32-matrix + minItems: 1 + maxItems: 8 # Should be enough regulators + items: + minItems: 1 + maxItems: 3 + + '^opp-microamp-': + description: + Named opp-microamp property. Similar to opp-microvolt- property, + but for microamp instead. + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 1 + maxItems: 8 # Should be enough regulators + + dependencies: + opp-avg-kBps: [ opp-peak-kBps ] + +required: + - compatible + +additionalProperties: true + +... diff --git a/Documentation/devicetree/bindings/opp/opp-v2.yaml b/Documentation/devicetree/bindings/opp/opp-v2.yaml new file mode 100644 index 000000000000..eaf8fba2c691 --- /dev/null +++ b/Documentation/devicetree/bindings/opp/opp-v2.yaml @@ -0,0 +1,475 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/opp/opp-v2.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Generic OPP (Operating Performance Points) Bindings + +maintainers: + - Viresh Kumar + +allOf: + - $ref: opp-v2-base.yaml# + +properties: + compatible: + const: operating-points-v2 + +unevaluatedProperties: false + +examples: + - | + /* + * Example 1: Single cluster Dual-core ARM cortex A9, switch DVFS states + * together. + */ + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "arm,cortex-a9"; + device_type = "cpu"; + reg = <0>; + next-level-cache = <&L2>; + clocks = <&clk_controller 0>; + clock-names = "cpu"; + cpu-supply = <&cpu_supply0>; + operating-points-v2 = <&cpu0_opp_table0>; + }; + + cpu@1 { + compatible = "arm,cortex-a9"; + device_type = "cpu"; + reg = <1>; + next-level-cache = <&L2>; + clocks = <&clk_controller 0>; + clock-names = "cpu"; + cpu-supply = <&cpu_supply0>; + operating-points-v2 = <&cpu0_opp_table0>; + }; + }; + + cpu0_opp_table0: opp-table { + compatible = "operating-points-v2"; + opp-shared; + + opp-1000000000 { + opp-hz = /bits/ 64 <1000000000>; + opp-microvolt = <975000 970000 985000>; + opp-microamp = <70000>; + clock-latency-ns = <300000>; + opp-suspend; + }; + opp-1100000000 { + opp-hz = /bits/ 64 <1100000000>; + opp-microvolt = <1000000 980000 1010000>; + opp-microamp = <80000>; + clock-latency-ns = <310000>; + }; + opp-1200000000 { + opp-hz = /bits/ 64 <1200000000>; + opp-microvolt = <1025000>; + clock-latency-ns = <290000>; + turbo-mode; + }; + }; + + - | + /* + * Example 2: Single cluster, Quad-core Qualcom-krait, switches DVFS states + * independently. + */ + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "qcom,krait"; + device_type = "cpu"; + reg = <0>; + next-level-cache = <&L2>; + clocks = <&clk_controller 0>; + clock-names = "cpu"; + cpu-supply = <&cpu_supply0>; + operating-points-v2 = <&cpu_opp_table>; + }; + + cpu@1 { + compatible = "qcom,krait"; + device_type = "cpu"; + reg = <1>; + next-level-cache = <&L2>; + clocks = <&clk_controller 1>; + clock-names = "cpu"; + cpu-supply = <&cpu_supply1>; + operating-points-v2 = <&cpu_opp_table>; + }; + + cpu@2 { + compatible = "qcom,krait"; + device_type = "cpu"; + reg = <2>; + next-level-cache = <&L2>; + clocks = <&clk_controller 2>; + clock-names = "cpu"; + cpu-supply = <&cpu_supply2>; + operating-points-v2 = <&cpu_opp_table>; + }; + + cpu@3 { + compatible = "qcom,krait"; + device_type = "cpu"; + reg = <3>; + next-level-cache = <&L2>; + clocks = <&clk_controller 3>; + clock-names = "cpu"; + cpu-supply = <&cpu_supply3>; + operating-points-v2 = <&cpu_opp_table>; + }; + }; + + cpu_opp_table: opp-table { + compatible = "operating-points-v2"; + + /* + * Missing opp-shared property means CPUs switch DVFS states + * independently. + */ + + opp-1000000000 { + opp-hz = /bits/ 64 <1000000000>; + opp-microvolt = <975000 970000 985000>; + opp-microamp = <70000>; + clock-latency-ns = <300000>; + opp-suspend; + }; + opp-1100000000 { + opp-hz = /bits/ 64 <1100000000>; + opp-microvolt = <1000000 980000 1010000>; + opp-microamp = <80000>; + clock-latency-ns = <310000>; + }; + opp-1200000000 { + opp-hz = /bits/ 64 <1200000000>; + opp-microvolt = <1025000>; + opp-microamp = <90000>; + lock-latency-ns = <290000>; + turbo-mode; + }; + }; + + - | + /* + * Example 3: Dual-cluster, Dual-core per cluster. CPUs within a cluster switch + * DVFS state together. + */ + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "arm,cortex-a7"; + device_type = "cpu"; + reg = <0>; + next-level-cache = <&L2>; + clocks = <&clk_controller 0>; + clock-names = "cpu"; + cpu-supply = <&cpu_supply0>; + operating-points-v2 = <&cluster0_opp>; + }; + + cpu@1 { + compatible = "arm,cortex-a7"; + device_type = "cpu"; + reg = <1>; + next-level-cache = <&L2>; + clocks = <&clk_controller 0>; + clock-names = "cpu"; + cpu-supply = <&cpu_supply0>; + operating-points-v2 = <&cluster0_opp>; + }; + + cpu@100 { + compatible = "arm,cortex-a15"; + device_type = "cpu"; + reg = <100>; + next-level-cache = <&L2>; + clocks = <&clk_controller 1>; + clock-names = "cpu"; + cpu-supply = <&cpu_supply1>; + operating-points-v2 = <&cluster1_opp>; + }; + + cpu@101 { + compatible = "arm,cortex-a15"; + device_type = "cpu"; + reg = <101>; + next-level-cache = <&L2>; + clocks = <&clk_controller 1>; + clock-names = "cpu"; + cpu-supply = <&cpu_supply1>; + operating-points-v2 = <&cluster1_opp>; + }; + }; + + cluster0_opp: opp-table-0 { + compatible = "operating-points-v2"; + opp-shared; + + opp-1000000000 { + opp-hz = /bits/ 64 <1000000000>; + opp-microvolt = <975000 970000 985000>; + opp-microamp = <70000>; + clock-latency-ns = <300000>; + opp-suspend; + }; + opp-1100000000 { + opp-hz = /bits/ 64 <1100000000>; + opp-microvolt = <1000000 980000 1010000>; + opp-microamp = <80000>; + clock-latency-ns = <310000>; + }; + opp-1200000000 { + opp-hz = /bits/ 64 <1200000000>; + opp-microvolt = <1025000>; + opp-microamp = <90000>; + clock-latency-ns = <290000>; + turbo-mode; + }; + }; + + cluster1_opp: opp-table-1 { + compatible = "operating-points-v2"; + opp-shared; + + opp-1300000000 { + opp-hz = /bits/ 64 <1300000000>; + opp-microvolt = <1050000 1045000 1055000>; + opp-microamp = <95000>; + clock-latency-ns = <400000>; + opp-suspend; + }; + opp-1400000000 { + opp-hz = /bits/ 64 <1400000000>; + opp-microvolt = <1075000>; + opp-microamp = <100000>; + clock-latency-ns = <400000>; + }; + opp-1500000000 { + opp-hz = /bits/ 64 <1500000000>; + opp-microvolt = <1100000 1010000 1110000>; + opp-microamp = <95000>; + clock-latency-ns = <400000>; + turbo-mode; + }; + }; + + - | + /* Example 4: Handling multiple regulators */ + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "foo,cpu-type"; + device_type = "cpu"; + reg = <0>; + + vcc0-supply = <&cpu_supply0>; + vcc1-supply = <&cpu_supply1>; + vcc2-supply = <&cpu_supply2>; + operating-points-v2 = <&cpu0_opp_table4>; + }; + }; + + cpu0_opp_table4: opp-table-0 { + compatible = "operating-points-v2"; + opp-shared; + + opp-1000000000 { + opp-hz = /bits/ 64 <1000000000>; + opp-microvolt = <970000>, /* Supply 0 */ + <960000>, /* Supply 1 */ + <960000>; /* Supply 2 */ + opp-microamp = <70000>, /* Supply 0 */ + <70000>, /* Supply 1 */ + <70000>; /* Supply 2 */ + clock-latency-ns = <300000>; + }; + + /* OR */ + + opp-1000000001 { + opp-hz = /bits/ 64 <1000000001>; + opp-microvolt = <975000 970000 985000>, /* Supply 0 */ + <965000 960000 975000>, /* Supply 1 */ + <965000 960000 975000>; /* Supply 2 */ + opp-microamp = <70000>, /* Supply 0 */ + <70000>, /* Supply 1 */ + <70000>; /* Supply 2 */ + clock-latency-ns = <300000>; + }; + + /* OR */ + + opp-1000000002 { + opp-hz = /bits/ 64 <1000000002>; + opp-microvolt = <975000 970000 985000>, /* Supply 0 */ + <965000 960000 975000>, /* Supply 1 */ + <965000 960000 975000>; /* Supply 2 */ + opp-microamp = <70000>, /* Supply 0 */ + <0>, /* Supply 1 doesn't need this */ + <70000>; /* Supply 2 */ + clock-latency-ns = <300000>; + }; + }; + + - | + /* + * Example 5: opp-supported-hw + * (example: three level hierarchy of versions: cuts, substrate and process) + */ + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "arm,cortex-a7"; + device_type = "cpu"; + reg = <0>; + cpu-supply = <&cpu_supply>; + operating-points-v2 = <&cpu0_opp_table_slow>; + }; + }; + + cpu0_opp_table_slow: opp-table { + compatible = "operating-points-v2"; + opp-shared; + + opp-600000000 { + /* + * Supports all substrate and process versions for 0xF + * cuts, i.e. only first four cuts. + */ + opp-supported-hw = <0xF 0xFFFFFFFF 0xFFFFFFFF>; + opp-hz = /bits/ 64 <600000000>; + }; + + opp-800000000 { + /* + * Supports: + * - cuts: only one, 6th cut (represented by 6th bit). + * - substrate: supports 16 different substrate versions + * - process: supports 9 different process versions + */ + opp-supported-hw = <0x20 0xff0000ff 0x0000f4f0>; + opp-hz = /bits/ 64 <800000000>; + }; + + opp-900000000 { + /* + * Supports: + * - All cuts and substrate where process version is 0x2. + * - All cuts and process where substrate version is 0x2. + */ + opp-supported-hw = <0xFFFFFFFF 0xFFFFFFFF 0x02>, + <0xFFFFFFFF 0x01 0xFFFFFFFF>; + opp-hz = /bits/ 64 <900000000>; + }; + }; + + - | + /* + * Example 6: opp-microvolt-, opp-microamp-: + * (example: device with two possible microvolt ranges: slow and fast) + */ + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "arm,cortex-a7"; + device_type = "cpu"; + reg = <0>; + operating-points-v2 = <&cpu0_opp_table6>; + }; + }; + + cpu0_opp_table6: opp-table-0 { + compatible = "operating-points-v2"; + opp-shared; + + opp-1000000000 { + opp-hz = /bits/ 64 <1000000000>; + opp-microvolt-slow = <915000 900000 925000>; + opp-microvolt-fast = <975000 970000 985000>; + opp-microamp-slow = <70000>; + opp-microamp-fast = <71000>; + }; + + opp-1200000000 { + opp-hz = /bits/ 64 <1200000000>; + opp-microvolt-slow = <915000 900000 925000>, /* Supply vcc0 */ + <925000 910000 935000>; /* Supply vcc1 */ + opp-microvolt-fast = <975000 970000 985000>, /* Supply vcc0 */ + <965000 960000 975000>; /* Supply vcc1 */ + opp-microamp = <70000>; /* Will be used for both slow/fast */ + }; + }; + + - | + /* + * Example 7: Single cluster Quad-core ARM cortex A53, OPP points from firmware, + * distinct clock controls but two sets of clock/voltage/current lines. + */ + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu@0 { + compatible = "arm,cortex-a53"; + device_type = "cpu"; + reg = <0x0 0x100>; + next-level-cache = <&A53_L2>; + clocks = <&dvfs_controller 0>; + operating-points-v2 = <&cpu_opp0_table>; + }; + cpu@1 { + compatible = "arm,cortex-a53"; + device_type = "cpu"; + reg = <0x0 0x101>; + next-level-cache = <&A53_L2>; + clocks = <&dvfs_controller 1>; + operating-points-v2 = <&cpu_opp0_table>; + }; + cpu@2 { + compatible = "arm,cortex-a53"; + device_type = "cpu"; + reg = <0x0 0x102>; + next-level-cache = <&A53_L2>; + clocks = <&dvfs_controller 2>; + operating-points-v2 = <&cpu_opp1_table>; + }; + cpu@3 { + compatible = "arm,cortex-a53"; + device_type = "cpu"; + reg = <0x0 0x103>; + next-level-cache = <&A53_L2>; + clocks = <&dvfs_controller 3>; + operating-points-v2 = <&cpu_opp1_table>; + }; + + }; + + cpu_opp0_table: opp-table-0 { + compatible = "operating-points-v2"; + opp-shared; + }; + + cpu_opp1_table: opp-table-1 { + compatible = "operating-points-v2"; + opp-shared; + }; +... diff --git a/Documentation/devicetree/bindings/opp/opp.txt b/Documentation/devicetree/bindings/opp/opp.txt deleted file mode 100644 index 08b3da4736cf..000000000000 --- a/Documentation/devicetree/bindings/opp/opp.txt +++ /dev/null @@ -1,622 +0,0 @@ -Generic OPP (Operating Performance Points) Bindings ----------------------------------------------------- - -Devices work at voltage-current-frequency combinations and some implementations -have the liberty of choosing these. These combinations are called Operating -Performance Points aka OPPs. This document defines bindings for these OPPs -applicable across wide range of devices. For illustration purpose, this document -uses CPU as a device. - -This document contain multiple versions of OPP binding and only one of them -should be used per device. - -Binding 1: operating-points -============================ - -This binding only supports voltage-frequency pairs. - -Properties: -- operating-points: An array of 2-tuples items, and each item consists - of frequency and voltage like . - freq: clock frequency in kHz - vol: voltage in microvolt - -Examples: - -cpu@0 { - compatible = "arm,cortex-a9"; - reg = <0>; - next-level-cache = <&L2>; - operating-points = < - /* kHz uV */ - 792000 1100000 - 396000 950000 - 198000 850000 - >; -}; - - -Binding 2: operating-points-v2 -============================ - -* Property: operating-points-v2 - -Devices supporting OPPs must set their "operating-points-v2" property with -phandle to a OPP table in their DT node. The OPP core will use this phandle to -find the operating points for the device. - -This can contain more than one phandle for power domain providers that provide -multiple power domains. That is, one phandle for each power domain. If only one -phandle is available, then the same OPP table will be used for all power domains -provided by the power domain provider. - -If required, this can be extended for SoC vendor specific bindings. Such bindings -should be documented as Documentation/devicetree/bindings/power/-opp.txt -and should have a compatible description like: "operating-points-v2-". - -* OPP Table Node - -This describes the OPPs belonging to a device. This node can have following -properties: - -Required properties: -- compatible: Allow OPPs to express their compatibility. It should be: - "operating-points-v2". - -- OPP nodes: One or more OPP nodes describing voltage-current-frequency - combinations. Their name isn't significant but their phandle can be used to - reference an OPP. These are mandatory except for the case where the OPP table - is present only to indicate dependency between devices using the opp-shared - property. - -Optional properties: -- opp-shared: Indicates that device nodes using this OPP Table Node's phandle - switch their DVFS state together, i.e. they share clock/voltage/current lines. - Missing property means devices have independent clock/voltage/current lines, - but they share OPP tables. - -- status: Marks the OPP table enabled/disabled. - - -* OPP Node - -This defines voltage-current-frequency combinations along with other related -properties. - -Required properties: -- opp-hz: Frequency in Hz, expressed as a 64-bit big-endian integer. This is a - required property for all device nodes, unless another "required" property to - uniquely identify the OPP nodes exists. Devices like power domains must have - another (implementation dependent) property. - -- opp-peak-kBps: Peak bandwidth in kilobytes per second, expressed as an array - of 32-bit big-endian integers. Each element of the array represents the - peak bandwidth value of each interconnect path. The number of elements should - match the number of interconnect paths. - -Optional properties: -- opp-microvolt: voltage in micro Volts. - - A single regulator's voltage is specified with an array of size one or three. - Single entry is for target voltage and three entries are for - voltages. - - Entries for multiple regulators shall be provided in the same field separated - by angular brackets <>. The OPP binding doesn't provide any provisions to - relate the values to their power supplies or the order in which the supplies - need to be configured and that is left for the implementation specific - binding. - - Entries for all regulators shall be of the same size, i.e. either all use a - single value or triplets. - -- opp-microvolt-: Named opp-microvolt property. This is exactly similar to - the above opp-microvolt property, but allows multiple voltage ranges to be - provided for the same OPP. At runtime, the platform can pick a and - matching opp-microvolt- property will be enabled for all OPPs. If the - platform doesn't pick a specific or the doesn't match with any - opp-microvolt- properties, then opp-microvolt property shall be used, if - present. - -- opp-microamp: The maximum current drawn by the device in microamperes - considering system specific parameters (such as transients, process, aging, - maximum operating temperature range etc.) as necessary. This may be used to - set the most efficient regulator operating mode. - - Should only be set if opp-microvolt is set for the OPP. - - Entries for multiple regulators shall be provided in the same field separated - by angular brackets <>. If current values aren't required for a regulator, - then it shall be filled with 0. If current values aren't required for any of - the regulators, then this field is not required. The OPP binding doesn't - provide any provisions to relate the values to their power supplies or the - order in which the supplies need to be configured and that is left for the - implementation specific binding. - -- opp-microamp-: Named opp-microamp property. Similar to - opp-microvolt- property, but for microamp instead. - -- opp-level: A value representing the performance level of the device, - expressed as a 32-bit integer. - -- opp-avg-kBps: Average bandwidth in kilobytes per second, expressed as an array - of 32-bit big-endian integers. Each element of the array represents the - average bandwidth value of each interconnect path. The number of elements - should match the number of interconnect paths. This property is only - meaningful in OPP tables where opp-peak-kBps is present. - -- clock-latency-ns: Specifies the maximum possible transition latency (in - nanoseconds) for switching to this OPP from any other OPP. - -- turbo-mode: Marks the OPP to be used only for turbo modes. Turbo mode is - available on some platforms, where the device can run over its operating - frequency for a short duration of time limited by the device's power, current - and thermal limits. - -- opp-suspend: Marks the OPP to be used during device suspend. If multiple OPPs - in the table have this, the OPP with highest opp-hz will be used. - -- opp-supported-hw: This property allows a platform to enable only a subset of - the OPPs from the larger set present in the OPP table, based on the current - version of the hardware (already known to the operating system). - - Each block present in the array of blocks in this property, represents a - sub-group of hardware versions supported by the OPP. i.e. , - , etc. The OPP will be enabled if _any_ of these sub-groups match - the hardware's version. - - Each sub-group is a platform defined array representing the hierarchy of - hardware versions supported by the platform. For a platform with three - hierarchical levels of version (X.Y.Z), this field shall look like - - opp-supported-hw = , , . - - Each level (eg. X1) in version hierarchy is represented by a 32 bit value, one - bit per version and so there can be maximum 32 versions per level. Logical AND - (&) operation is performed for each level with the hardware's level version - and a non-zero output for _all_ the levels in a sub-group means the OPP is - supported by hardware. A value of 0xFFFFFFFF for each level in the sub-group - will enable the OPP for all versions for the hardware. - -- status: Marks the node enabled/disabled. - -- required-opps: This contains phandle to an OPP node in another device's OPP - table. It may contain an array of phandles, where each phandle points to an - OPP of a different device. It should not contain multiple phandles to the OPP - nodes in the same OPP table. This specifies the minimum required OPP of the - device(s), whose OPP's phandle is present in this property, for the - functioning of the current device at the current OPP (where this property is - present). - -Example 1: Single cluster Dual-core ARM cortex A9, switch DVFS states together. - -/ { - cpus { - #address-cells = <1>; - #size-cells = <0>; - - cpu@0 { - compatible = "arm,cortex-a9"; - reg = <0>; - next-level-cache = <&L2>; - clocks = <&clk_controller 0>; - clock-names = "cpu"; - cpu-supply = <&cpu_supply0>; - operating-points-v2 = <&cpu0_opp_table>; - }; - - cpu@1 { - compatible = "arm,cortex-a9"; - reg = <1>; - next-level-cache = <&L2>; - clocks = <&clk_controller 0>; - clock-names = "cpu"; - cpu-supply = <&cpu_supply0>; - operating-points-v2 = <&cpu0_opp_table>; - }; - }; - - cpu0_opp_table: opp_table0 { - compatible = "operating-points-v2"; - opp-shared; - - opp-1000000000 { - opp-hz = /bits/ 64 <1000000000>; - opp-microvolt = <975000 970000 985000>; - opp-microamp = <70000>; - clock-latency-ns = <300000>; - opp-suspend; - }; - opp-1100000000 { - opp-hz = /bits/ 64 <1100000000>; - opp-microvolt = <1000000 980000 1010000>; - opp-microamp = <80000>; - clock-latency-ns = <310000>; - }; - opp-1200000000 { - opp-hz = /bits/ 64 <1200000000>; - opp-microvolt = <1025000>; - clock-latency-ns = <290000>; - turbo-mode; - }; - }; -}; - -Example 2: Single cluster, Quad-core Qualcom-krait, switches DVFS states -independently. - -/ { - cpus { - #address-cells = <1>; - #size-cells = <0>; - - cpu@0 { - compatible = "qcom,krait"; - reg = <0>; - next-level-cache = <&L2>; - clocks = <&clk_controller 0>; - clock-names = "cpu"; - cpu-supply = <&cpu_supply0>; - operating-points-v2 = <&cpu_opp_table>; - }; - - cpu@1 { - compatible = "qcom,krait"; - reg = <1>; - next-level-cache = <&L2>; - clocks = <&clk_controller 1>; - clock-names = "cpu"; - cpu-supply = <&cpu_supply1>; - operating-points-v2 = <&cpu_opp_table>; - }; - - cpu@2 { - compatible = "qcom,krait"; - reg = <2>; - next-level-cache = <&L2>; - clocks = <&clk_controller 2>; - clock-names = "cpu"; - cpu-supply = <&cpu_supply2>; - operating-points-v2 = <&cpu_opp_table>; - }; - - cpu@3 { - compatible = "qcom,krait"; - reg = <3>; - next-level-cache = <&L2>; - clocks = <&clk_controller 3>; - clock-names = "cpu"; - cpu-supply = <&cpu_supply3>; - operating-points-v2 = <&cpu_opp_table>; - }; - }; - - cpu_opp_table: opp_table { - compatible = "operating-points-v2"; - - /* - * Missing opp-shared property means CPUs switch DVFS states - * independently. - */ - - opp-1000000000 { - opp-hz = /bits/ 64 <1000000000>; - opp-microvolt = <975000 970000 985000>; - opp-microamp = <70000>; - clock-latency-ns = <300000>; - opp-suspend; - }; - opp-1100000000 { - opp-hz = /bits/ 64 <1100000000>; - opp-microvolt = <1000000 980000 1010000>; - opp-microamp = <80000>; - clock-latency-ns = <310000>; - }; - opp-1200000000 { - opp-hz = /bits/ 64 <1200000000>; - opp-microvolt = <1025000>; - opp-microamp = <90000; - lock-latency-ns = <290000>; - turbo-mode; - }; - }; -}; - -Example 3: Dual-cluster, Dual-core per cluster. CPUs within a cluster switch -DVFS state together. - -/ { - cpus { - #address-cells = <1>; - #size-cells = <0>; - - cpu@0 { - compatible = "arm,cortex-a7"; - reg = <0>; - next-level-cache = <&L2>; - clocks = <&clk_controller 0>; - clock-names = "cpu"; - cpu-supply = <&cpu_supply0>; - operating-points-v2 = <&cluster0_opp>; - }; - - cpu@1 { - compatible = "arm,cortex-a7"; - reg = <1>; - next-level-cache = <&L2>; - clocks = <&clk_controller 0>; - clock-names = "cpu"; - cpu-supply = <&cpu_supply0>; - operating-points-v2 = <&cluster0_opp>; - }; - - cpu@100 { - compatible = "arm,cortex-a15"; - reg = <100>; - next-level-cache = <&L2>; - clocks = <&clk_controller 1>; - clock-names = "cpu"; - cpu-supply = <&cpu_supply1>; - operating-points-v2 = <&cluster1_opp>; - }; - - cpu@101 { - compatible = "arm,cortex-a15"; - reg = <101>; - next-level-cache = <&L2>; - clocks = <&clk_controller 1>; - clock-names = "cpu"; - cpu-supply = <&cpu_supply1>; - operating-points-v2 = <&cluster1_opp>; - }; - }; - - cluster0_opp: opp_table0 { - compatible = "operating-points-v2"; - opp-shared; - - opp-1000000000 { - opp-hz = /bits/ 64 <1000000000>; - opp-microvolt = <975000 970000 985000>; - opp-microamp = <70000>; - clock-latency-ns = <300000>; - opp-suspend; - }; - opp-1100000000 { - opp-hz = /bits/ 64 <1100000000>; - opp-microvolt = <1000000 980000 1010000>; - opp-microamp = <80000>; - clock-latency-ns = <310000>; - }; - opp-1200000000 { - opp-hz = /bits/ 64 <1200000000>; - opp-microvolt = <1025000>; - opp-microamp = <90000>; - clock-latency-ns = <290000>; - turbo-mode; - }; - }; - - cluster1_opp: opp_table1 { - compatible = "operating-points-v2"; - opp-shared; - - opp-1300000000 { - opp-hz = /bits/ 64 <1300000000>; - opp-microvolt = <1050000 1045000 1055000>; - opp-microamp = <95000>; - clock-latency-ns = <400000>; - opp-suspend; - }; - opp-1400000000 { - opp-hz = /bits/ 64 <1400000000>; - opp-microvolt = <1075000>; - opp-microamp = <100000>; - clock-latency-ns = <400000>; - }; - opp-1500000000 { - opp-hz = /bits/ 64 <1500000000>; - opp-microvolt = <1100000 1010000 1110000>; - opp-microamp = <95000>; - clock-latency-ns = <400000>; - turbo-mode; - }; - }; -}; - -Example 4: Handling multiple regulators - -/ { - cpus { - cpu@0 { - compatible = "vendor,cpu-type"; - ... - - vcc0-supply = <&cpu_supply0>; - vcc1-supply = <&cpu_supply1>; - vcc2-supply = <&cpu_supply2>; - operating-points-v2 = <&cpu0_opp_table>; - }; - }; - - cpu0_opp_table: opp_table0 { - compatible = "operating-points-v2"; - opp-shared; - - opp-1000000000 { - opp-hz = /bits/ 64 <1000000000>; - opp-microvolt = <970000>, /* Supply 0 */ - <960000>, /* Supply 1 */ - <960000>; /* Supply 2 */ - opp-microamp = <70000>, /* Supply 0 */ - <70000>, /* Supply 1 */ - <70000>; /* Supply 2 */ - clock-latency-ns = <300000>; - }; - - /* OR */ - - opp-1000000000 { - opp-hz = /bits/ 64 <1000000000>; - opp-microvolt = <975000 970000 985000>, /* Supply 0 */ - <965000 960000 975000>, /* Supply 1 */ - <965000 960000 975000>; /* Supply 2 */ - opp-microamp = <70000>, /* Supply 0 */ - <70000>, /* Supply 1 */ - <70000>; /* Supply 2 */ - clock-latency-ns = <300000>; - }; - - /* OR */ - - opp-1000000000 { - opp-hz = /bits/ 64 <1000000000>; - opp-microvolt = <975000 970000 985000>, /* Supply 0 */ - <965000 960000 975000>, /* Supply 1 */ - <965000 960000 975000>; /* Supply 2 */ - opp-microamp = <70000>, /* Supply 0 */ - <0>, /* Supply 1 doesn't need this */ - <70000>; /* Supply 2 */ - clock-latency-ns = <300000>; - }; - }; -}; - -Example 5: opp-supported-hw -(example: three level hierarchy of versions: cuts, substrate and process) - -/ { - cpus { - cpu@0 { - compatible = "arm,cortex-a7"; - ... - - cpu-supply = <&cpu_supply> - operating-points-v2 = <&cpu0_opp_table_slow>; - }; - }; - - opp_table { - compatible = "operating-points-v2"; - opp-shared; - - opp-600000000 { - /* - * Supports all substrate and process versions for 0xF - * cuts, i.e. only first four cuts. - */ - opp-supported-hw = <0xF 0xFFFFFFFF 0xFFFFFFFF> - opp-hz = /bits/ 64 <600000000>; - ... - }; - - opp-800000000 { - /* - * Supports: - * - cuts: only one, 6th cut (represented by 6th bit). - * - substrate: supports 16 different substrate versions - * - process: supports 9 different process versions - */ - opp-supported-hw = <0x20 0xff0000ff 0x0000f4f0> - opp-hz = /bits/ 64 <800000000>; - ... - }; - - opp-900000000 { - /* - * Supports: - * - All cuts and substrate where process version is 0x2. - * - All cuts and process where substrate version is 0x2. - */ - opp-supported-hw = <0xFFFFFFFF 0xFFFFFFFF 0x02>, <0xFFFFFFFF 0x01 0xFFFFFFFF> - opp-hz = /bits/ 64 <900000000>; - ... - }; - }; -}; - -Example 6: opp-microvolt-, opp-microamp-: -(example: device with two possible microvolt ranges: slow and fast) - -/ { - cpus { - cpu@0 { - compatible = "arm,cortex-a7"; - ... - - operating-points-v2 = <&cpu0_opp_table>; - }; - }; - - cpu0_opp_table: opp_table0 { - compatible = "operating-points-v2"; - opp-shared; - - opp-1000000000 { - opp-hz = /bits/ 64 <1000000000>; - opp-microvolt-slow = <915000 900000 925000>; - opp-microvolt-fast = <975000 970000 985000>; - opp-microamp-slow = <70000>; - opp-microamp-fast = <71000>; - }; - - opp-1200000000 { - opp-hz = /bits/ 64 <1200000000>; - opp-microvolt-slow = <915000 900000 925000>, /* Supply vcc0 */ - <925000 910000 935000>; /* Supply vcc1 */ - opp-microvolt-fast = <975000 970000 985000>, /* Supply vcc0 */ - <965000 960000 975000>; /* Supply vcc1 */ - opp-microamp = <70000>; /* Will be used for both slow/fast */ - }; - }; -}; - -Example 7: Single cluster Quad-core ARM cortex A53, OPP points from firmware, -distinct clock controls but two sets of clock/voltage/current lines. - -/ { - cpus { - #address-cells = <2>; - #size-cells = <0>; - - cpu@0 { - compatible = "arm,cortex-a53"; - reg = <0x0 0x100>; - next-level-cache = <&A53_L2>; - clocks = <&dvfs_controller 0>; - operating-points-v2 = <&cpu_opp0_table>; - }; - cpu@1 { - compatible = "arm,cortex-a53"; - reg = <0x0 0x101>; - next-level-cache = <&A53_L2>; - clocks = <&dvfs_controller 1>; - operating-points-v2 = <&cpu_opp0_table>; - }; - cpu@2 { - compatible = "arm,cortex-a53"; - reg = <0x0 0x102>; - next-level-cache = <&A53_L2>; - clocks = <&dvfs_controller 2>; - operating-points-v2 = <&cpu_opp1_table>; - }; - cpu@3 { - compatible = "arm,cortex-a53"; - reg = <0x0 0x103>; - next-level-cache = <&A53_L2>; - clocks = <&dvfs_controller 3>; - operating-points-v2 = <&cpu_opp1_table>; - }; - - }; - - cpu_opp0_table: opp0_table { - compatible = "operating-points-v2"; - opp-shared; - }; - - cpu_opp1_table: opp1_table { - compatible = "operating-points-v2"; - opp-shared; - }; -}; diff --git a/Documentation/devicetree/bindings/opp/qcom-opp.txt b/Documentation/devicetree/bindings/opp/qcom-opp.txt index 32eb0793c7e6..41d3e4ff2dc3 100644 --- a/Documentation/devicetree/bindings/opp/qcom-opp.txt +++ b/Documentation/devicetree/bindings/opp/qcom-opp.txt @@ -1,7 +1,7 @@ Qualcomm OPP bindings to describe OPP nodes The bindings are based on top of the operating-points-v2 bindings -described in Documentation/devicetree/bindings/opp/opp.txt +described in Documentation/devicetree/bindings/opp/opp-v2-base.yaml Additional properties are described below. * OPP Table Node diff --git a/Documentation/devicetree/bindings/opp/ti-omap5-opp-supply.txt b/Documentation/devicetree/bindings/opp/ti-omap5-opp-supply.txt index 832346e489a3..b70d326117cd 100644 --- a/Documentation/devicetree/bindings/opp/ti-omap5-opp-supply.txt +++ b/Documentation/devicetree/bindings/opp/ti-omap5-opp-supply.txt @@ -13,7 +13,7 @@ regulators to the device that will undergo OPP transitions we can make use of the multi regulator binding that is part of the OPP core described here [1] to describe both regulators needed by the platform. -[1] Documentation/devicetree/bindings/opp/opp.txt +[1] Documentation/devicetree/bindings/opp/opp-v2.yaml Required Properties for Device Node: - vdd-supply: phandle to regulator controlling VDD supply diff --git a/Documentation/devicetree/bindings/power/power-domain.yaml b/Documentation/devicetree/bindings/power/power-domain.yaml index aed51e9dcb11..3143ed9a3313 100644 --- a/Documentation/devicetree/bindings/power/power-domain.yaml +++ b/Documentation/devicetree/bindings/power/power-domain.yaml @@ -46,7 +46,7 @@ properties: Phandles to the OPP tables of power domains provided by a power domain provider. If the provider provides a single power domain only or all the power domains provided by the provider have identical OPP tables, - then this shall contain a single phandle. Refer to ../opp/opp.txt + then this shall contain a single phandle. Refer to ../opp/opp-v2-base.yaml for more information. "#power-domain-cells": From a8db7a3f8ac69e558c7bfbd04802201c39a104ad Mon Sep 17 00:00:00 2001 From: Prashant Malani Date: Tue, 3 Aug 2021 10:36:21 -0700 Subject: [PATCH 176/696] platform/chrome: cros_ec_typec: Use existing feature check Replace the cros_typec_feature_supported() function with the pre-existing cros_ec_check_features() function which does the same thing. Signed-off-by: Prashant Malani Link: https://lore.kernel.org/r/20210803173619.91539-2-pmalani@chromium.org Signed-off-by: Benson Leung --- drivers/platform/chrome/cros_ec_typec.c | 27 +++++-------------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_typec.c b/drivers/platform/chrome/cros_ec_typec.c index 27c068c4c38d..262a891eded3 100644 --- a/drivers/platform/chrome/cros_ec_typec.c +++ b/drivers/platform/chrome/cros_ec_typec.c @@ -1054,24 +1054,6 @@ static int cros_typec_get_cmd_version(struct cros_typec_data *typec) return 0; } -/* Check the EC feature flags to see if TYPEC_* features are supported. */ -static int cros_typec_feature_supported(struct cros_typec_data *typec, enum ec_feature_code feature) -{ - struct ec_response_get_features resp = {}; - int ret; - - ret = cros_typec_ec_command(typec, 0, EC_CMD_GET_FEATURES, NULL, 0, - &resp, sizeof(resp)); - if (ret < 0) { - dev_warn(typec->dev, - "Failed to get features, assuming typec feature=%d unsupported.\n", - feature); - return 0; - } - - return resp.flags[feature / 32] & EC_FEATURE_MASK_1(feature); -} - static void cros_typec_port_work(struct work_struct *work) { struct cros_typec_data *typec = container_of(work, struct cros_typec_data, port_work); @@ -1113,6 +1095,7 @@ MODULE_DEVICE_TABLE(of, cros_typec_of_match); static int cros_typec_probe(struct platform_device *pdev) { + struct cros_ec_dev *ec_dev = NULL; struct device *dev = &pdev->dev; struct cros_typec_data *typec; struct ec_response_usb_pd_ports resp; @@ -1132,10 +1115,10 @@ static int cros_typec_probe(struct platform_device *pdev) return ret; } - typec->typec_cmd_supported = !!cros_typec_feature_supported(typec, - EC_FEATURE_TYPEC_CMD); - typec->needs_mux_ack = !!cros_typec_feature_supported(typec, - EC_FEATURE_TYPEC_MUX_REQUIRE_AP_ACK); + ec_dev = dev_get_drvdata(&typec->ec->ec->dev); + typec->typec_cmd_supported = !!cros_ec_check_features(ec_dev, EC_FEATURE_TYPEC_CMD); + typec->needs_mux_ack = !!cros_ec_check_features(ec_dev, + EC_FEATURE_TYPEC_MUX_REQUIRE_AP_ACK); ret = cros_typec_ec_command(typec, 0, EC_CMD_USB_PD_PORTS, NULL, 0, &resp, sizeof(resp)); From b4366a827f6cf6e58c93e076e335d9ee9ee0480f Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 24 Aug 2021 09:05:30 -0700 Subject: [PATCH 177/696] libnvdimm/labels: Introduce getters for namespace label fields In preparation for LIBNVDIMM to manage labels on CXL devices deploy helpers that abstract the label type from the implementation. The CXL label format is mostly similar to the EFI label format with concepts / fields added, like dynamic region creation and label type guids, and other concepts removed like BLK-mode and interleave-set-cookie ids. In addition to nsl_get_* helpers there is the nsl_ref_name() helper that returns a pointer to a label field rather than copying the data. Where changes touch the old whitespace style, update to clang-format expectations. Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/162982113002.1124374.15922077050771304490.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams --- drivers/nvdimm/label.c | 20 +++++----- drivers/nvdimm/namespace_devs.c | 70 ++++++++++++++++----------------- drivers/nvdimm/nd.h | 66 +++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+), 46 deletions(-) diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c index 9251441fd8a3..b6d845cfb70e 100644 --- a/drivers/nvdimm/label.c +++ b/drivers/nvdimm/label.c @@ -350,14 +350,14 @@ static bool slot_valid(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label, u32 slot) { /* check that we are written where we expect to be written */ - if (slot != __le32_to_cpu(nd_label->slot)) + if (slot != nsl_get_slot(ndd, nd_label)) return false; /* check checksum */ if (namespace_label_has(ndd, checksum)) { u64 sum, sum_save; - sum_save = __le64_to_cpu(nd_label->checksum); + sum_save = nsl_get_checksum(ndd, nd_label); nd_label->checksum = __cpu_to_le64(0); sum = nd_fletcher64(nd_label, sizeof_namespace_label(ndd), 1); nd_label->checksum = __cpu_to_le64(sum_save); @@ -395,13 +395,13 @@ int nd_label_reserve_dpa(struct nvdimm_drvdata *ndd) continue; memcpy(label_uuid, nd_label->uuid, NSLABEL_UUID_LEN); - flags = __le32_to_cpu(nd_label->flags); + flags = nsl_get_flags(ndd, nd_label); if (test_bit(NDD_NOBLK, &nvdimm->flags)) flags &= ~NSLABEL_FLAG_LOCAL; nd_label_gen_id(&label_id, label_uuid, flags); res = nvdimm_allocate_dpa(ndd, &label_id, - __le64_to_cpu(nd_label->dpa), - __le64_to_cpu(nd_label->rawsize)); + nsl_get_dpa(ndd, nd_label), + nsl_get_rawsize(ndd, nd_label)); nd_dbg_dpa(nd_region, ndd, res, "reserve\n"); if (!res) return -EBUSY; @@ -548,9 +548,9 @@ int nd_label_active_count(struct nvdimm_drvdata *ndd) nd_label = to_label(ndd, slot); if (!slot_valid(ndd, nd_label, slot)) { - u32 label_slot = __le32_to_cpu(nd_label->slot); - u64 size = __le64_to_cpu(nd_label->rawsize); - u64 dpa = __le64_to_cpu(nd_label->dpa); + u32 label_slot = nsl_get_slot(ndd, nd_label); + u64 size = nsl_get_rawsize(ndd, nd_label); + u64 dpa = nsl_get_dpa(ndd, nd_label); dev_dbg(ndd->dev, "slot%d invalid slot: %d dpa: %llx size: %llx\n", @@ -879,9 +879,9 @@ static struct resource *to_resource(struct nvdimm_drvdata *ndd, struct resource *res; for_each_dpa_resource(ndd, res) { - if (res->start != __le64_to_cpu(nd_label->dpa)) + if (res->start != nsl_get_dpa(ndd, nd_label)) continue; - if (resource_size(res) != __le64_to_cpu(nd_label->rawsize)) + if (resource_size(res) != nsl_get_rawsize(ndd, nd_label)) continue; return res; } diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c index 2403b71b601e..94da804372bf 100644 --- a/drivers/nvdimm/namespace_devs.c +++ b/drivers/nvdimm/namespace_devs.c @@ -1235,7 +1235,7 @@ static int namespace_update_uuid(struct nd_region *nd_region, if (!nd_label) continue; nd_label_gen_id(&label_id, nd_label->uuid, - __le32_to_cpu(nd_label->flags)); + nsl_get_flags(ndd, nd_label)); if (strcmp(old_label_id.id, label_id.id) == 0) set_bit(ND_LABEL_REAP, &label_ent->flags); } @@ -1851,9 +1851,9 @@ static bool has_uuid_at_pos(struct nd_region *nd_region, u8 *uuid, if (!nd_label) continue; - isetcookie = __le64_to_cpu(nd_label->isetcookie); - position = __le16_to_cpu(nd_label->position); - nlabel = __le16_to_cpu(nd_label->nlabel); + isetcookie = nsl_get_isetcookie(ndd, nd_label); + position = nsl_get_position(ndd, nd_label); + nlabel = nsl_get_nlabel(ndd, nd_label); if (isetcookie != cookie) continue; @@ -1923,8 +1923,8 @@ static int select_pmem_id(struct nd_region *nd_region, u8 *pmem_id) */ hw_start = nd_mapping->start; hw_end = hw_start + nd_mapping->size; - pmem_start = __le64_to_cpu(nd_label->dpa); - pmem_end = pmem_start + __le64_to_cpu(nd_label->rawsize); + pmem_start = nsl_get_dpa(ndd, nd_label); + pmem_end = pmem_start + nsl_get_rawsize(ndd, nd_label); if (pmem_start >= hw_start && pmem_start < hw_end && pmem_end <= hw_end && pmem_end > hw_start) /* pass */; @@ -1947,14 +1947,16 @@ static int select_pmem_id(struct nd_region *nd_region, u8 *pmem_id) * @nd_label: target pmem namespace label to evaluate */ static struct device *create_namespace_pmem(struct nd_region *nd_region, - struct nd_namespace_index *nsindex, - struct nd_namespace_label *nd_label) + struct nd_mapping *nd_mapping, + struct nd_namespace_label *nd_label) { + struct nvdimm_drvdata *ndd = to_ndd(nd_mapping); + struct nd_namespace_index *nsindex = + to_namespace_index(ndd, ndd->ns_current); u64 cookie = nd_region_interleave_set_cookie(nd_region, nsindex); u64 altcookie = nd_region_interleave_set_altcookie(nd_region); struct nd_label_ent *label_ent; struct nd_namespace_pmem *nspm; - struct nd_mapping *nd_mapping; resource_size_t size = 0; struct resource *res; struct device *dev; @@ -1966,10 +1968,10 @@ static struct device *create_namespace_pmem(struct nd_region *nd_region, return ERR_PTR(-ENXIO); } - if (__le64_to_cpu(nd_label->isetcookie) != cookie) { + if (nsl_get_isetcookie(ndd, nd_label) != cookie) { dev_dbg(&nd_region->dev, "invalid cookie in label: %pUb\n", nd_label->uuid); - if (__le64_to_cpu(nd_label->isetcookie) != altcookie) + if (nsl_get_isetcookie(ndd, nd_label) != altcookie) return ERR_PTR(-EAGAIN); dev_dbg(&nd_region->dev, "valid altcookie in label: %pUb\n", @@ -2037,16 +2039,16 @@ static struct device *create_namespace_pmem(struct nd_region *nd_region, continue; } - size += __le64_to_cpu(label0->rawsize); - if (__le16_to_cpu(label0->position) != 0) + ndd = to_ndd(nd_mapping); + size += nsl_get_rawsize(ndd, label0); + if (nsl_get_position(ndd, label0) != 0) continue; WARN_ON(nspm->alt_name || nspm->uuid); - nspm->alt_name = kmemdup((void __force *) label0->name, - NSLABEL_NAME_LEN, GFP_KERNEL); + nspm->alt_name = kmemdup(nsl_ref_name(ndd, label0), + NSLABEL_NAME_LEN, GFP_KERNEL); nspm->uuid = kmemdup((void __force *) label0->uuid, NSLABEL_UUID_LEN, GFP_KERNEL); - nspm->lbasize = __le64_to_cpu(label0->lbasize); - ndd = to_ndd(nd_mapping); + nspm->lbasize = nsl_get_lbasize(ndd, label0); if (namespace_label_has(ndd, abstraction_guid)) nspm->nsio.common.claim_class = to_nvdimm_cclass(&label0->abstraction_guid); @@ -2237,7 +2239,7 @@ static int add_namespace_resource(struct nd_region *nd_region, if (is_namespace_blk(devs[i])) { res = nsblk_add_resource(nd_region, ndd, to_nd_namespace_blk(devs[i]), - __le64_to_cpu(nd_label->dpa)); + nsl_get_dpa(ndd, nd_label)); if (!res) return -ENXIO; nd_dbg_dpa(nd_region, ndd, res, "%d assign\n", count); @@ -2276,7 +2278,7 @@ static struct device *create_namespace_blk(struct nd_region *nd_region, if (nd_label->isetcookie != __cpu_to_le64(nd_set->cookie2)) { dev_dbg(ndd->dev, "expect cookie %#llx got %#llx\n", nd_set->cookie2, - __le64_to_cpu(nd_label->isetcookie)); + nsl_get_isetcookie(ndd, nd_label)); return ERR_PTR(-EAGAIN); } } @@ -2288,7 +2290,7 @@ static struct device *create_namespace_blk(struct nd_region *nd_region, dev->type = &namespace_blk_device_type; dev->parent = &nd_region->dev; nsblk->id = -1; - nsblk->lbasize = __le64_to_cpu(nd_label->lbasize); + nsblk->lbasize = nsl_get_lbasize(ndd, nd_label); nsblk->uuid = kmemdup(nd_label->uuid, NSLABEL_UUID_LEN, GFP_KERNEL); if (namespace_label_has(ndd, abstraction_guid)) @@ -2296,15 +2298,14 @@ static struct device *create_namespace_blk(struct nd_region *nd_region, = to_nvdimm_cclass(&nd_label->abstraction_guid); if (!nsblk->uuid) goto blk_err; - memcpy(name, nd_label->name, NSLABEL_NAME_LEN); + nsl_get_name(ndd, nd_label, name); if (name[0]) { - nsblk->alt_name = kmemdup(name, NSLABEL_NAME_LEN, - GFP_KERNEL); + nsblk->alt_name = kmemdup(name, NSLABEL_NAME_LEN, GFP_KERNEL); if (!nsblk->alt_name) goto blk_err; } res = nsblk_add_resource(nd_region, ndd, nsblk, - __le64_to_cpu(nd_label->dpa)); + nsl_get_dpa(ndd, nd_label)); if (!res) goto blk_err; nd_dbg_dpa(nd_region, ndd, res, "%d: assign\n", count); @@ -2345,6 +2346,7 @@ static struct device **scan_labels(struct nd_region *nd_region) struct device *dev, **devs = NULL; struct nd_label_ent *label_ent, *e; struct nd_mapping *nd_mapping = &nd_region->mapping[0]; + struct nvdimm_drvdata *ndd = to_ndd(nd_mapping); resource_size_t map_end = nd_mapping->start + nd_mapping->size - 1; /* "safe" because create_namespace_pmem() might list_move() label_ent */ @@ -2355,7 +2357,7 @@ static struct device **scan_labels(struct nd_region *nd_region) if (!nd_label) continue; - flags = __le32_to_cpu(nd_label->flags); + flags = nsl_get_flags(ndd, nd_label); if (is_nd_blk(&nd_region->dev) == !!(flags & NSLABEL_FLAG_LOCAL)) /* pass, region matches label type */; @@ -2363,9 +2365,9 @@ static struct device **scan_labels(struct nd_region *nd_region) continue; /* skip labels that describe extents outside of the region */ - if (__le64_to_cpu(nd_label->dpa) < nd_mapping->start || - __le64_to_cpu(nd_label->dpa) > map_end) - continue; + if (nsl_get_dpa(ndd, nd_label) < nd_mapping->start || + nsl_get_dpa(ndd, nd_label) > map_end) + continue; i = add_namespace_resource(nd_region, nd_label, devs, count); if (i < 0) @@ -2381,13 +2383,9 @@ static struct device **scan_labels(struct nd_region *nd_region) if (is_nd_blk(&nd_region->dev)) dev = create_namespace_blk(nd_region, nd_label, count); - else { - struct nvdimm_drvdata *ndd = to_ndd(nd_mapping); - struct nd_namespace_index *nsindex; - - nsindex = to_namespace_index(ndd, ndd->ns_current); - dev = create_namespace_pmem(nd_region, nsindex, nd_label); - } + else + dev = create_namespace_pmem(nd_region, nd_mapping, + nd_label); if (IS_ERR(dev)) { switch (PTR_ERR(dev)) { @@ -2570,7 +2568,7 @@ static int init_active_labels(struct nd_region *nd_region) break; label = nd_label_active(ndd, j); if (test_bit(NDD_NOBLK, &nvdimm->flags)) { - u32 flags = __le32_to_cpu(label->flags); + u32 flags = nsl_get_flags(ndd, label); flags &= ~NSLABEL_FLAG_LOCAL; label->flags = __cpu_to_le32(flags); diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h index 696b55556d4d..61f43f0edabf 100644 --- a/drivers/nvdimm/nd.h +++ b/drivers/nvdimm/nd.h @@ -35,6 +35,72 @@ struct nvdimm_drvdata { struct kref kref; }; +static inline const u8 *nsl_ref_name(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label) +{ + return nd_label->name; +} + +static inline u8 *nsl_get_name(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label, u8 *name) +{ + return memcpy(name, nd_label->name, NSLABEL_NAME_LEN); +} + +static inline u32 nsl_get_slot(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label) +{ + return __le32_to_cpu(nd_label->slot); +} + +static inline u64 nsl_get_checksum(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label) +{ + return __le64_to_cpu(nd_label->checksum); +} + +static inline u32 nsl_get_flags(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label) +{ + return __le32_to_cpu(nd_label->flags); +} + +static inline u64 nsl_get_dpa(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label) +{ + return __le64_to_cpu(nd_label->dpa); +} + +static inline u64 nsl_get_rawsize(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label) +{ + return __le64_to_cpu(nd_label->rawsize); +} + +static inline u64 nsl_get_isetcookie(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label) +{ + return __le64_to_cpu(nd_label->isetcookie); +} + +static inline u16 nsl_get_position(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label) +{ + return __le16_to_cpu(nd_label->position); +} + +static inline u16 nsl_get_nlabel(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label) +{ + return __le16_to_cpu(nd_label->nlabel); +} + +static inline u64 nsl_get_lbasize(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label) +{ + return __le64_to_cpu(nd_label->lbasize); +} + struct nd_region_data { int ns_count; int ns_active; From 9761b02d40de4b7f9f4947f801b69993817883ee Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 24 Aug 2021 09:05:35 -0700 Subject: [PATCH 178/696] libnvdimm/labels: Add isetcookie validation helper In preparation to handle CXL labels with the same code that handles EFI labels, add a specific interleave-set-cookie validation helper rather than a getter since the CXL label type does not support this concept. The answer for CXL labels will always be true. Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/162982113550.1124374.206762177785773038.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams --- drivers/nvdimm/namespace_devs.c | 8 +++----- drivers/nvdimm/nd.h | 7 +++++++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c index 94da804372bf..f33245c27cc4 100644 --- a/drivers/nvdimm/namespace_devs.c +++ b/drivers/nvdimm/namespace_devs.c @@ -1847,15 +1847,13 @@ static bool has_uuid_at_pos(struct nd_region *nd_region, u8 *uuid, list_for_each_entry(label_ent, &nd_mapping->labels, list) { struct nd_namespace_label *nd_label = label_ent->label; u16 position, nlabel; - u64 isetcookie; if (!nd_label) continue; - isetcookie = nsl_get_isetcookie(ndd, nd_label); position = nsl_get_position(ndd, nd_label); nlabel = nsl_get_nlabel(ndd, nd_label); - if (isetcookie != cookie) + if (!nsl_validate_isetcookie(ndd, nd_label, cookie)) continue; if (memcmp(nd_label->uuid, uuid, NSLABEL_UUID_LEN) != 0) @@ -1968,10 +1966,10 @@ static struct device *create_namespace_pmem(struct nd_region *nd_region, return ERR_PTR(-ENXIO); } - if (nsl_get_isetcookie(ndd, nd_label) != cookie) { + if (!nsl_validate_isetcookie(ndd, nd_label, cookie)) { dev_dbg(&nd_region->dev, "invalid cookie in label: %pUb\n", nd_label->uuid); - if (nsl_get_isetcookie(ndd, nd_label) != altcookie) + if (!nsl_validate_isetcookie(ndd, nd_label, altcookie)) return ERR_PTR(-EAGAIN); dev_dbg(&nd_region->dev, "valid altcookie in label: %pUb\n", diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h index 61f43f0edabf..b3feaf3699f7 100644 --- a/drivers/nvdimm/nd.h +++ b/drivers/nvdimm/nd.h @@ -83,6 +83,13 @@ static inline u64 nsl_get_isetcookie(struct nvdimm_drvdata *ndd, return __le64_to_cpu(nd_label->isetcookie); } +static inline bool nsl_validate_isetcookie(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label, + u64 cookie) +{ + return cookie == __le64_to_cpu(nd_label->isetcookie); +} + static inline u16 nsl_get_position(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label) { From 8176f147891258a8eb42bf5579fa344fef34e5bc Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 24 Aug 2021 09:05:41 -0700 Subject: [PATCH 179/696] libnvdimm/labels: Introduce label setter helpers In preparation for LIBNVDIMM to manage labels on CXL devices deploy helpers that abstract the label type from the implementation. The CXL label format is mostly similar to the EFI label format with concepts / fields added, like dynamic region creation and label type guids, and other concepts removed like BLK-mode and interleave-set-cookie ids. Reported-by: kernel test robot Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/162982114123.1124374.17153270107594686116.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams --- drivers/nvdimm/label.c | 61 ++++++++++++++--------------- drivers/nvdimm/namespace_devs.c | 2 +- drivers/nvdimm/nd.h | 69 +++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+), 33 deletions(-) diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c index b6d845cfb70e..b40a4eda1d89 100644 --- a/drivers/nvdimm/label.c +++ b/drivers/nvdimm/label.c @@ -358,9 +358,9 @@ static bool slot_valid(struct nvdimm_drvdata *ndd, u64 sum, sum_save; sum_save = nsl_get_checksum(ndd, nd_label); - nd_label->checksum = __cpu_to_le64(0); + nsl_set_checksum(ndd, nd_label, 0); sum = nd_fletcher64(nd_label, sizeof_namespace_label(ndd), 1); - nd_label->checksum = __cpu_to_le64(sum_save); + nsl_set_checksum(ndd, nd_label, sum_save); if (sum != sum_save) { dev_dbg(ndd->dev, "fail checksum. slot: %d expect: %#llx\n", slot, sum); @@ -797,16 +797,15 @@ static int __pmem_label_update(struct nd_region *nd_region, nd_label = to_label(ndd, slot); memset(nd_label, 0, sizeof_namespace_label(ndd)); memcpy(nd_label->uuid, nspm->uuid, NSLABEL_UUID_LEN); - if (nspm->alt_name) - memcpy(nd_label->name, nspm->alt_name, NSLABEL_NAME_LEN); - nd_label->flags = __cpu_to_le32(flags); - nd_label->nlabel = __cpu_to_le16(nd_region->ndr_mappings); - nd_label->position = __cpu_to_le16(pos); - nd_label->isetcookie = __cpu_to_le64(cookie); - nd_label->rawsize = __cpu_to_le64(resource_size(res)); - nd_label->lbasize = __cpu_to_le64(nspm->lbasize); - nd_label->dpa = __cpu_to_le64(res->start); - nd_label->slot = __cpu_to_le32(slot); + nsl_set_name(ndd, nd_label, nspm->alt_name); + nsl_set_flags(ndd, nd_label, flags); + nsl_set_nlabel(ndd, nd_label, nd_region->ndr_mappings); + nsl_set_position(ndd, nd_label, pos); + nsl_set_isetcookie(ndd, nd_label, cookie); + nsl_set_rawsize(ndd, nd_label, resource_size(res)); + nsl_set_lbasize(ndd, nd_label, nspm->lbasize); + nsl_set_dpa(ndd, nd_label, res->start); + nsl_set_slot(ndd, nd_label, slot); if (namespace_label_has(ndd, type_guid)) guid_copy(&nd_label->type_guid, &nd_set->type_guid); if (namespace_label_has(ndd, abstraction_guid)) @@ -816,9 +815,9 @@ static int __pmem_label_update(struct nd_region *nd_region, if (namespace_label_has(ndd, checksum)) { u64 sum; - nd_label->checksum = __cpu_to_le64(0); + nsl_set_checksum(ndd, nd_label, 0); sum = nd_fletcher64(nd_label, sizeof_namespace_label(ndd), 1); - nd_label->checksum = __cpu_to_le64(sum); + nsl_set_checksum(ndd, nd_label, sum); } nd_dbg_dpa(nd_region, ndd, res, "\n"); @@ -1017,10 +1016,8 @@ static int __blk_label_update(struct nd_region *nd_region, nd_label = to_label(ndd, slot); memset(nd_label, 0, sizeof_namespace_label(ndd)); memcpy(nd_label->uuid, nsblk->uuid, NSLABEL_UUID_LEN); - if (nsblk->alt_name) - memcpy(nd_label->name, nsblk->alt_name, - NSLABEL_NAME_LEN); - nd_label->flags = __cpu_to_le32(NSLABEL_FLAG_LOCAL); + nsl_set_name(ndd, nd_label, nsblk->alt_name); + nsl_set_flags(ndd, nd_label, NSLABEL_FLAG_LOCAL); /* * Use the presence of the type_guid as a flag to @@ -1029,23 +1026,23 @@ static int __blk_label_update(struct nd_region *nd_region, */ if (namespace_label_has(ndd, type_guid)) { if (i == min_dpa_idx) { - nd_label->nlabel = __cpu_to_le16(nsblk->num_resources); - nd_label->position = __cpu_to_le16(0); + nsl_set_nlabel(ndd, nd_label, nsblk->num_resources); + nsl_set_position(ndd, nd_label, 0); } else { - nd_label->nlabel = __cpu_to_le16(0xffff); - nd_label->position = __cpu_to_le16(0xffff); + nsl_set_nlabel(ndd, nd_label, 0xffff); + nsl_set_position(ndd, nd_label, 0xffff); } - nd_label->isetcookie = __cpu_to_le64(nd_set->cookie2); + nsl_set_isetcookie(ndd, nd_label, nd_set->cookie2); } else { - nd_label->nlabel = __cpu_to_le16(0); /* N/A */ - nd_label->position = __cpu_to_le16(0); /* N/A */ - nd_label->isetcookie = __cpu_to_le64(0); /* N/A */ + nsl_set_nlabel(ndd, nd_label, 0); /* N/A */ + nsl_set_position(ndd, nd_label, 0); /* N/A */ + nsl_set_isetcookie(ndd, nd_label, 0); /* N/A */ } - nd_label->dpa = __cpu_to_le64(res->start); - nd_label->rawsize = __cpu_to_le64(resource_size(res)); - nd_label->lbasize = __cpu_to_le64(nsblk->lbasize); - nd_label->slot = __cpu_to_le32(slot); + nsl_set_dpa(ndd, nd_label, res->start); + nsl_set_rawsize(ndd, nd_label, resource_size(res)); + nsl_set_lbasize(ndd, nd_label, nsblk->lbasize); + nsl_set_slot(ndd, nd_label, slot); if (namespace_label_has(ndd, type_guid)) guid_copy(&nd_label->type_guid, &nd_set->type_guid); if (namespace_label_has(ndd, abstraction_guid)) @@ -1056,10 +1053,10 @@ static int __blk_label_update(struct nd_region *nd_region, if (namespace_label_has(ndd, checksum)) { u64 sum; - nd_label->checksum = __cpu_to_le64(0); + nsl_set_checksum(ndd, nd_label, 0); sum = nd_fletcher64(nd_label, sizeof_namespace_label(ndd), 1); - nd_label->checksum = __cpu_to_le64(sum); + nsl_set_checksum(ndd, nd_label, sum); } /* update label */ diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c index f33245c27cc4..fb9e080ce654 100644 --- a/drivers/nvdimm/namespace_devs.c +++ b/drivers/nvdimm/namespace_devs.c @@ -2569,7 +2569,7 @@ static int init_active_labels(struct nd_region *nd_region) u32 flags = nsl_get_flags(ndd, label); flags &= ~NSLABEL_FLAG_LOCAL; - label->flags = __cpu_to_le32(flags); + nsl_set_flags(ndd, label, flags); } label_ent->label = label; diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h index b3feaf3699f7..9bf9cd4a9a2d 100644 --- a/drivers/nvdimm/nd.h +++ b/drivers/nvdimm/nd.h @@ -47,42 +47,89 @@ static inline u8 *nsl_get_name(struct nvdimm_drvdata *ndd, return memcpy(name, nd_label->name, NSLABEL_NAME_LEN); } +static inline u8 *nsl_set_name(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label, u8 *name) +{ + if (!name) + return NULL; + return memcpy(nd_label->name, name, NSLABEL_NAME_LEN); +} + static inline u32 nsl_get_slot(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label) { return __le32_to_cpu(nd_label->slot); } +static inline void nsl_set_slot(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label, u32 slot) +{ + nd_label->slot = __cpu_to_le32(slot); +} + static inline u64 nsl_get_checksum(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label) { return __le64_to_cpu(nd_label->checksum); } +static inline void nsl_set_checksum(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label, + u64 checksum) +{ + nd_label->checksum = __cpu_to_le64(checksum); +} + static inline u32 nsl_get_flags(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label) { return __le32_to_cpu(nd_label->flags); } +static inline void nsl_set_flags(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label, u32 flags) +{ + nd_label->flags = __cpu_to_le32(flags); +} + static inline u64 nsl_get_dpa(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label) { return __le64_to_cpu(nd_label->dpa); } +static inline void nsl_set_dpa(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label, u64 dpa) +{ + nd_label->dpa = __cpu_to_le64(dpa); +} + static inline u64 nsl_get_rawsize(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label) { return __le64_to_cpu(nd_label->rawsize); } +static inline void nsl_set_rawsize(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label, + u64 rawsize) +{ + nd_label->rawsize = __cpu_to_le64(rawsize); +} + static inline u64 nsl_get_isetcookie(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label) { return __le64_to_cpu(nd_label->isetcookie); } +static inline void nsl_set_isetcookie(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label, + u64 isetcookie) +{ + nd_label->isetcookie = __cpu_to_le64(isetcookie); +} + static inline bool nsl_validate_isetcookie(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label, u64 cookie) @@ -96,18 +143,40 @@ static inline u16 nsl_get_position(struct nvdimm_drvdata *ndd, return __le16_to_cpu(nd_label->position); } +static inline void nsl_set_position(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label, + u16 position) +{ + nd_label->position = __cpu_to_le16(position); +} + + static inline u16 nsl_get_nlabel(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label) { return __le16_to_cpu(nd_label->nlabel); } +static inline void nsl_set_nlabel(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label, + u16 nlabel) +{ + nd_label->nlabel = __cpu_to_le16(nlabel); +} + static inline u64 nsl_get_lbasize(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label) { return __le64_to_cpu(nd_label->lbasize); } +static inline void nsl_set_lbasize(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label, + u64 lbasize) +{ + nd_label->lbasize = __cpu_to_le64(lbasize); +} + struct nd_region_data { int ns_count; int ns_active; From 7cd35b2920500908eb3d9d00939f2aea3e8f8361 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 24 Aug 2021 09:05:46 -0700 Subject: [PATCH 180/696] libnvdimm/labels: Add a checksum calculation helper In preparation for LIBNVDIMM to manage labels on CXL devices deploy helpers that abstract the label type from the implementation. The CXL label format is mostly similar to the EFI label format with concepts / fields added, like dynamic region creation and label type guids, and other concepts removed like BLK-mode and interleave-set-cookie ids. CXL labels support checksums by default, but early versions of the EFI labels did not. Add a validate function that can return true in the case the label format does not implement a checksum. Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/162982114637.1124374.6966639787307077105.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams --- drivers/nvdimm/label.c | 68 ++++++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c index b40a4eda1d89..3f73412dd438 100644 --- a/drivers/nvdimm/label.c +++ b/drivers/nvdimm/label.c @@ -346,29 +346,45 @@ static bool preamble_next(struct nvdimm_drvdata *ndd, free, nslot); } +static bool nsl_validate_checksum(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label) +{ + u64 sum, sum_save; + + if (!namespace_label_has(ndd, checksum)) + return true; + + sum_save = nsl_get_checksum(ndd, nd_label); + nsl_set_checksum(ndd, nd_label, 0); + sum = nd_fletcher64(nd_label, sizeof_namespace_label(ndd), 1); + nsl_set_checksum(ndd, nd_label, sum_save); + return sum == sum_save; +} + +static void nsl_calculate_checksum(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label) +{ + u64 sum; + + if (!namespace_label_has(ndd, checksum)) + return; + nsl_set_checksum(ndd, nd_label, 0); + sum = nd_fletcher64(nd_label, sizeof_namespace_label(ndd), 1); + nsl_set_checksum(ndd, nd_label, sum); +} + static bool slot_valid(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label, u32 slot) { + bool valid; + /* check that we are written where we expect to be written */ if (slot != nsl_get_slot(ndd, nd_label)) return false; - - /* check checksum */ - if (namespace_label_has(ndd, checksum)) { - u64 sum, sum_save; - - sum_save = nsl_get_checksum(ndd, nd_label); - nsl_set_checksum(ndd, nd_label, 0); - sum = nd_fletcher64(nd_label, sizeof_namespace_label(ndd), 1); - nsl_set_checksum(ndd, nd_label, sum_save); - if (sum != sum_save) { - dev_dbg(ndd->dev, "fail checksum. slot: %d expect: %#llx\n", - slot, sum); - return false; - } - } - - return true; + valid = nsl_validate_checksum(ndd, nd_label); + if (!valid) + dev_dbg(ndd->dev, "fail checksum. slot: %d\n", slot); + return valid; } int nd_label_reserve_dpa(struct nvdimm_drvdata *ndd) @@ -812,13 +828,7 @@ static int __pmem_label_update(struct nd_region *nd_region, guid_copy(&nd_label->abstraction_guid, to_abstraction_guid(ndns->claim_class, &nd_label->abstraction_guid)); - if (namespace_label_has(ndd, checksum)) { - u64 sum; - - nsl_set_checksum(ndd, nd_label, 0); - sum = nd_fletcher64(nd_label, sizeof_namespace_label(ndd), 1); - nsl_set_checksum(ndd, nd_label, sum); - } + nsl_calculate_checksum(ndd, nd_label); nd_dbg_dpa(nd_region, ndd, res, "\n"); /* update label */ @@ -1049,15 +1059,7 @@ static int __blk_label_update(struct nd_region *nd_region, guid_copy(&nd_label->abstraction_guid, to_abstraction_guid(ndns->claim_class, &nd_label->abstraction_guid)); - - if (namespace_label_has(ndd, checksum)) { - u64 sum; - - nsl_set_checksum(ndd, nd_label, 0); - sum = nd_fletcher64(nd_label, - sizeof_namespace_label(ndd), 1); - nsl_set_checksum(ndd, nd_label, sum); - } + nsl_calculate_checksum(ndd, nd_label); /* update label */ offset = nd_label_offset(ndd, nd_label); From f56541a7122c68ef3074e41c2cb14182eb11d3a5 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 24 Aug 2021 09:05:51 -0700 Subject: [PATCH 181/696] libnvdimm/labels: Add blk isetcookie set / validation helpers In preparation for LIBNVDIMM to manage labels on CXL devices deploy helpers that abstract the label type from the implementation. The CXL label format is mostly similar to the EFI label format with concepts / fields added, like dynamic region creation and label type guids, and other concepts removed like BLK-mode and interleave-set-cookie ids. Given BLK-mode is not even supported on CXL push hide the BLK-mode specific details inside the helpers. Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/162982115185.1124374.13459190993792729776.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams --- drivers/nvdimm/label.c | 30 ++++++++++++++++++++++++++++-- drivers/nvdimm/namespace_devs.c | 9 ++------- drivers/nvdimm/nd.h | 4 ++++ 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c index 3f73412dd438..d1a7f399cfe4 100644 --- a/drivers/nvdimm/label.c +++ b/drivers/nvdimm/label.c @@ -898,6 +898,33 @@ static struct resource *to_resource(struct nvdimm_drvdata *ndd, return NULL; } +static void nsl_set_blk_isetcookie(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label, + u64 isetcookie) +{ + if (namespace_label_has(ndd, type_guid)) { + nsl_set_isetcookie(ndd, nd_label, isetcookie); + return; + } + nsl_set_isetcookie(ndd, nd_label, 0); /* N/A */ +} + +bool nsl_validate_blk_isetcookie(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label, + u64 isetcookie) +{ + if (!namespace_label_has(ndd, type_guid)) + return true; + + if (nsl_get_isetcookie(ndd, nd_label) != isetcookie) { + dev_dbg(ndd->dev, "expect cookie %#llx got %#llx\n", isetcookie, + nsl_get_isetcookie(ndd, nd_label)); + return false; + } + + return true; +} + /* * 1/ Account all the labels that can be freed after this update * 2/ Allocate and write the label to the staging (next) index @@ -1042,12 +1069,11 @@ static int __blk_label_update(struct nd_region *nd_region, nsl_set_nlabel(ndd, nd_label, 0xffff); nsl_set_position(ndd, nd_label, 0xffff); } - nsl_set_isetcookie(ndd, nd_label, nd_set->cookie2); } else { nsl_set_nlabel(ndd, nd_label, 0); /* N/A */ nsl_set_position(ndd, nd_label, 0); /* N/A */ - nsl_set_isetcookie(ndd, nd_label, 0); /* N/A */ } + nsl_set_blk_isetcookie(ndd, nd_label, nd_set->cookie2); nsl_set_dpa(ndd, nd_label, res->start); nsl_set_rawsize(ndd, nd_label, resource_size(res)); diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c index fb9e080ce654..fbd0c2fcea4a 100644 --- a/drivers/nvdimm/namespace_devs.c +++ b/drivers/nvdimm/namespace_devs.c @@ -2272,14 +2272,9 @@ static struct device *create_namespace_blk(struct nd_region *nd_region, &nd_label->type_guid); return ERR_PTR(-EAGAIN); } - - if (nd_label->isetcookie != __cpu_to_le64(nd_set->cookie2)) { - dev_dbg(ndd->dev, "expect cookie %#llx got %#llx\n", - nd_set->cookie2, - nsl_get_isetcookie(ndd, nd_label)); - return ERR_PTR(-EAGAIN); - } } + if (!nsl_validate_blk_isetcookie(ndd, nd_label, nd_set->cookie2)) + return ERR_PTR(-EAGAIN); nsblk = kzalloc(sizeof(*nsblk), GFP_KERNEL); if (!nsblk) diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h index 9bf9cd4a9a2d..955c4395a8e3 100644 --- a/drivers/nvdimm/nd.h +++ b/drivers/nvdimm/nd.h @@ -177,6 +177,10 @@ static inline void nsl_set_lbasize(struct nvdimm_drvdata *ndd, nd_label->lbasize = __cpu_to_le64(lbasize); } +bool nsl_validate_blk_isetcookie(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label, + u64 isetcookie); + struct nd_region_data { int ns_count; int ns_active; From de8fa48b9a281e69f944c58ae2adbd8a277787a6 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 24 Aug 2021 09:05:57 -0700 Subject: [PATCH 182/696] libnvdimm/labels: Add blk special cases for nlabel and position helpers In preparation for LIBNVDIMM to manage labels on CXL devices deploy helpers that abstract the label type from the implementation. The CXL label format is mostly similar to the EFI label format with concepts / fields added, like dynamic region creation and label type guids, and other concepts removed like BLK-mode and interleave-set-cookie ids. Finish off the BLK-mode specific helper conversion with the nlabel and position behaviour that is specific to EFI v1.2 labels and not the original v1.1 definition. Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/162982115698.1124374.10182273478536799613.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams --- drivers/nvdimm/label.c | 46 ++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c index d1a7f399cfe4..7188675c0955 100644 --- a/drivers/nvdimm/label.c +++ b/drivers/nvdimm/label.c @@ -898,6 +898,10 @@ static struct resource *to_resource(struct nvdimm_drvdata *ndd, return NULL; } +/* + * Use the presence of the type_guid as a flag to determine isetcookie + * usage and nlabel + position policy for blk-aperture namespaces. + */ static void nsl_set_blk_isetcookie(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label, u64 isetcookie) @@ -925,6 +929,28 @@ bool nsl_validate_blk_isetcookie(struct nvdimm_drvdata *ndd, return true; } +static void nsl_set_blk_nlabel(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label, int nlabel, + bool first) +{ + if (!namespace_label_has(ndd, type_guid)) { + nsl_set_nlabel(ndd, nd_label, 0); /* N/A */ + return; + } + nsl_set_nlabel(ndd, nd_label, first ? nlabel : 0xffff); +} + +static void nsl_set_blk_position(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label, + bool first) +{ + if (!namespace_label_has(ndd, type_guid)) { + nsl_set_position(ndd, nd_label, 0); + return; + } + nsl_set_position(ndd, nd_label, first ? 0 : 0xffff); +} + /* * 1/ Account all the labels that can be freed after this update * 2/ Allocate and write the label to the staging (next) index @@ -1056,23 +1082,9 @@ static int __blk_label_update(struct nd_region *nd_region, nsl_set_name(ndd, nd_label, nsblk->alt_name); nsl_set_flags(ndd, nd_label, NSLABEL_FLAG_LOCAL); - /* - * Use the presence of the type_guid as a flag to - * determine isetcookie usage and nlabel + position - * policy for blk-aperture namespaces. - */ - if (namespace_label_has(ndd, type_guid)) { - if (i == min_dpa_idx) { - nsl_set_nlabel(ndd, nd_label, nsblk->num_resources); - nsl_set_position(ndd, nd_label, 0); - } else { - nsl_set_nlabel(ndd, nd_label, 0xffff); - nsl_set_position(ndd, nd_label, 0xffff); - } - } else { - nsl_set_nlabel(ndd, nd_label, 0); /* N/A */ - nsl_set_position(ndd, nd_label, 0); /* N/A */ - } + nsl_set_blk_nlabel(ndd, nd_label, nsblk->num_resources, + i == min_dpa_idx); + nsl_set_blk_position(ndd, nd_label, i == min_dpa_idx); nsl_set_blk_isetcookie(ndd, nd_label, nd_set->cookie2); nsl_set_dpa(ndd, nd_label, res->start); From 8b03aa0e0e5aea61d5a7fc6434faba2a05a6095b Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 24 Aug 2021 09:06:02 -0700 Subject: [PATCH 183/696] libnvdimm/labels: Add type-guid helpers In preparation for CXL label support, which does not have the type-guid concept, wrap the existing users with nsl_set_type_guid, and nsl_validate_type_guid. Recall that the type-guid is a value in the ACPI NFIT table to indicate how the memory range is used / should be presented to upper layers. Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/162982116208.1124374.13938280892226800953.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams --- drivers/nvdimm/label.c | 26 ++++++++++++++++++++++---- drivers/nvdimm/namespace_devs.c | 19 ++++--------------- drivers/nvdimm/nd.h | 2 ++ 3 files changed, 28 insertions(+), 19 deletions(-) diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c index 7188675c0955..294ffc3cb582 100644 --- a/drivers/nvdimm/label.c +++ b/drivers/nvdimm/label.c @@ -772,6 +772,26 @@ static void reap_victim(struct nd_mapping *nd_mapping, victim->label = NULL; } +static void nsl_set_type_guid(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label, guid_t *guid) +{ + if (namespace_label_has(ndd, type_guid)) + guid_copy(&nd_label->type_guid, guid); +} + +bool nsl_validate_type_guid(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label, guid_t *guid) +{ + if (!namespace_label_has(ndd, type_guid)) + return true; + if (!guid_equal(&nd_label->type_guid, guid)) { + dev_dbg(ndd->dev, "expect type_guid %pUb got %pUb\n", guid, + &nd_label->type_guid); + return false; + } + return true; +} + static int __pmem_label_update(struct nd_region *nd_region, struct nd_mapping *nd_mapping, struct nd_namespace_pmem *nspm, int pos, unsigned long flags) @@ -822,8 +842,7 @@ static int __pmem_label_update(struct nd_region *nd_region, nsl_set_lbasize(ndd, nd_label, nspm->lbasize); nsl_set_dpa(ndd, nd_label, res->start); nsl_set_slot(ndd, nd_label, slot); - if (namespace_label_has(ndd, type_guid)) - guid_copy(&nd_label->type_guid, &nd_set->type_guid); + nsl_set_type_guid(ndd, nd_label, &nd_set->type_guid); if (namespace_label_has(ndd, abstraction_guid)) guid_copy(&nd_label->abstraction_guid, to_abstraction_guid(ndns->claim_class, @@ -1091,8 +1110,7 @@ static int __blk_label_update(struct nd_region *nd_region, nsl_set_rawsize(ndd, nd_label, resource_size(res)); nsl_set_lbasize(ndd, nd_label, nsblk->lbasize); nsl_set_slot(ndd, nd_label, slot); - if (namespace_label_has(ndd, type_guid)) - guid_copy(&nd_label->type_guid, &nd_set->type_guid); + nsl_set_type_guid(ndd, nd_label, &nd_set->type_guid); if (namespace_label_has(ndd, abstraction_guid)) guid_copy(&nd_label->abstraction_guid, to_abstraction_guid(ndns->claim_class, diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c index fbd0c2fcea4a..af5a31dd3147 100644 --- a/drivers/nvdimm/namespace_devs.c +++ b/drivers/nvdimm/namespace_devs.c @@ -1859,14 +1859,9 @@ static bool has_uuid_at_pos(struct nd_region *nd_region, u8 *uuid, if (memcmp(nd_label->uuid, uuid, NSLABEL_UUID_LEN) != 0) continue; - if (namespace_label_has(ndd, type_guid) - && !guid_equal(&nd_set->type_guid, - &nd_label->type_guid)) { - dev_dbg(ndd->dev, "expect type_guid %pUb got %pUb\n", - &nd_set->type_guid, - &nd_label->type_guid); + if (!nsl_validate_type_guid(ndd, nd_label, + &nd_set->type_guid)) continue; - } if (found_uuid) { dev_dbg(ndd->dev, "duplicate entry for uuid\n"); @@ -2265,14 +2260,8 @@ static struct device *create_namespace_blk(struct nd_region *nd_region, struct device *dev = NULL; struct resource *res; - if (namespace_label_has(ndd, type_guid)) { - if (!guid_equal(&nd_set->type_guid, &nd_label->type_guid)) { - dev_dbg(ndd->dev, "expect type_guid %pUb got %pUb\n", - &nd_set->type_guid, - &nd_label->type_guid); - return ERR_PTR(-EAGAIN); - } - } + if (!nsl_validate_type_guid(ndd, nd_label, &nd_set->type_guid)) + return ERR_PTR(-EAGAIN); if (!nsl_validate_blk_isetcookie(ndd, nd_label, nd_set->cookie2)) return ERR_PTR(-EAGAIN); diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h index 955c4395a8e3..a3e215f2d837 100644 --- a/drivers/nvdimm/nd.h +++ b/drivers/nvdimm/nd.h @@ -180,6 +180,8 @@ static inline void nsl_set_lbasize(struct nvdimm_drvdata *ndd, bool nsl_validate_blk_isetcookie(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label, u64 isetcookie); +bool nsl_validate_type_guid(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label, guid_t *guid); struct nd_region_data { int ns_count; From a6e6d722957273afebf26b9a36b90acfc27dca8a Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 24 Aug 2021 09:06:07 -0700 Subject: [PATCH 184/696] libnvdimm/labels: Add claim class helpers In preparation for LIBNVDIMM to manage labels on CXL devices deploy helpers that abstract the label type from the implementation. The CXL label format is mostly similar to the EFI label format with concepts / fields added, like dynamic region creation and label type guids, and other concepts removed like BLK-mode and interleave-set-cookie ids. CXL labels do have the concept of a claim class represented by an "abstraction" identifier. It turns out both label implementations use the same ids, but EFI encodes them as GUIDs and CXL labels encode them as UUIDs. For now abstract out the claim class such that the UUID vs GUID distinction can later be hidden in the helper. Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/162982116719.1124374.9917866609080940364.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams --- drivers/nvdimm/label.c | 31 ++++++++++++++++++++++--------- drivers/nvdimm/label.h | 1 - drivers/nvdimm/namespace_devs.c | 13 ++++--------- drivers/nvdimm/nd.h | 2 ++ 4 files changed, 28 insertions(+), 19 deletions(-) diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c index 294ffc3cb582..7f473f9db300 100644 --- a/drivers/nvdimm/label.c +++ b/drivers/nvdimm/label.c @@ -724,7 +724,7 @@ static unsigned long nd_label_offset(struct nvdimm_drvdata *ndd, - (unsigned long) to_namespace_index(ndd, 0); } -enum nvdimm_claim_class to_nvdimm_cclass(guid_t *guid) +static enum nvdimm_claim_class to_nvdimm_cclass(guid_t *guid) { if (guid_equal(guid, &nvdimm_btt_guid)) return NVDIMM_CCLASS_BTT; @@ -792,6 +792,25 @@ bool nsl_validate_type_guid(struct nvdimm_drvdata *ndd, return true; } +static void nsl_set_claim_class(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label, + enum nvdimm_claim_class claim_class) +{ + if (!namespace_label_has(ndd, abstraction_guid)) + return; + guid_copy(&nd_label->abstraction_guid, + to_abstraction_guid(claim_class, + &nd_label->abstraction_guid)); +} + +enum nvdimm_claim_class nsl_get_claim_class(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label) +{ + if (!namespace_label_has(ndd, abstraction_guid)) + return NVDIMM_CCLASS_NONE; + return to_nvdimm_cclass(&nd_label->abstraction_guid); +} + static int __pmem_label_update(struct nd_region *nd_region, struct nd_mapping *nd_mapping, struct nd_namespace_pmem *nspm, int pos, unsigned long flags) @@ -843,10 +862,7 @@ static int __pmem_label_update(struct nd_region *nd_region, nsl_set_dpa(ndd, nd_label, res->start); nsl_set_slot(ndd, nd_label, slot); nsl_set_type_guid(ndd, nd_label, &nd_set->type_guid); - if (namespace_label_has(ndd, abstraction_guid)) - guid_copy(&nd_label->abstraction_guid, - to_abstraction_guid(ndns->claim_class, - &nd_label->abstraction_guid)); + nsl_set_claim_class(ndd, nd_label, ndns->claim_class); nsl_calculate_checksum(ndd, nd_label); nd_dbg_dpa(nd_region, ndd, res, "\n"); @@ -1111,10 +1127,7 @@ static int __blk_label_update(struct nd_region *nd_region, nsl_set_lbasize(ndd, nd_label, nsblk->lbasize); nsl_set_slot(ndd, nd_label, slot); nsl_set_type_guid(ndd, nd_label, &nd_set->type_guid); - if (namespace_label_has(ndd, abstraction_guid)) - guid_copy(&nd_label->abstraction_guid, - to_abstraction_guid(ndns->claim_class, - &nd_label->abstraction_guid)); + nsl_set_claim_class(ndd, nd_label, ndns->claim_class); nsl_calculate_checksum(ndd, nd_label); /* update label */ diff --git a/drivers/nvdimm/label.h b/drivers/nvdimm/label.h index 956b6d1bd8cc..31f94fad7b92 100644 --- a/drivers/nvdimm/label.h +++ b/drivers/nvdimm/label.h @@ -135,7 +135,6 @@ struct nd_namespace_label *nd_label_active(struct nvdimm_drvdata *ndd, int n); u32 nd_label_alloc_slot(struct nvdimm_drvdata *ndd); bool nd_label_free_slot(struct nvdimm_drvdata *ndd, u32 slot); u32 nd_label_nfree(struct nvdimm_drvdata *ndd); -enum nvdimm_claim_class to_nvdimm_cclass(guid_t *guid); struct nd_region; struct nd_namespace_pmem; struct nd_namespace_blk; diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c index af5a31dd3147..58c76d74127a 100644 --- a/drivers/nvdimm/namespace_devs.c +++ b/drivers/nvdimm/namespace_devs.c @@ -2042,10 +2042,8 @@ static struct device *create_namespace_pmem(struct nd_region *nd_region, nspm->uuid = kmemdup((void __force *) label0->uuid, NSLABEL_UUID_LEN, GFP_KERNEL); nspm->lbasize = nsl_get_lbasize(ndd, label0); - if (namespace_label_has(ndd, abstraction_guid)) - nspm->nsio.common.claim_class - = to_nvdimm_cclass(&label0->abstraction_guid); - + nspm->nsio.common.claim_class = + nsl_get_claim_class(ndd, label0); } if (!nspm->alt_name || !nspm->uuid) { @@ -2273,11 +2271,8 @@ static struct device *create_namespace_blk(struct nd_region *nd_region, dev->parent = &nd_region->dev; nsblk->id = -1; nsblk->lbasize = nsl_get_lbasize(ndd, nd_label); - nsblk->uuid = kmemdup(nd_label->uuid, NSLABEL_UUID_LEN, - GFP_KERNEL); - if (namespace_label_has(ndd, abstraction_guid)) - nsblk->common.claim_class - = to_nvdimm_cclass(&nd_label->abstraction_guid); + nsblk->uuid = kmemdup(nd_label->uuid, NSLABEL_UUID_LEN, GFP_KERNEL); + nsblk->common.claim_class = nsl_get_claim_class(ndd, nd_label); if (!nsblk->uuid) goto blk_err; nsl_get_name(ndd, nd_label, name); diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h index a3e215f2d837..5467ebbb4a6b 100644 --- a/drivers/nvdimm/nd.h +++ b/drivers/nvdimm/nd.h @@ -182,6 +182,8 @@ bool nsl_validate_blk_isetcookie(struct nvdimm_drvdata *ndd, u64 isetcookie); bool nsl_validate_type_guid(struct nvdimm_drvdata *ndd, struct nd_namespace_label *nd_label, guid_t *guid); +enum nvdimm_claim_class nsl_get_claim_class(struct nvdimm_drvdata *ndd, + struct nd_namespace_label *nd_label); struct nd_region_data { int ns_count; From 8c7a729d09644dafbb90207c35cab495d3a33175 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Mon, 23 Aug 2021 14:31:43 -0400 Subject: [PATCH 185/696] Documentation: locking: fix references This patch fixes file references from txt to rst file ending in ww-mutex-design.rst and futex-requeue-pi.rst. While on it fix a spelling issue "desgin" to "design" reported by Matthew Wilcox. Signed-off-by: Alexander Aring Link: https://lore.kernel.org/r/20210823183143.1691344-1-aahringo@redhat.com Signed-off-by: Jonathan Corbet --- Documentation/locking/futex-requeue-pi.rst | 2 +- Documentation/locking/ww-mutex-design.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/locking/futex-requeue-pi.rst b/Documentation/locking/futex-requeue-pi.rst index 14ab5787b9a7..dd4ecf4528a4 100644 --- a/Documentation/locking/futex-requeue-pi.rst +++ b/Documentation/locking/futex-requeue-pi.rst @@ -5,7 +5,7 @@ Futex Requeue PI Requeueing of tasks from a non-PI futex to a PI futex requires special handling in order to ensure the underlying rt_mutex is never left without an owner if it has waiters; doing so would break the PI -boosting logic [see rt-mutex-desgin.txt] For the purposes of +boosting logic [see rt-mutex-design.rst] For the purposes of brevity, this action will be referred to as "requeue_pi" throughout this document. Priority inheritance is abbreviated throughout as "PI". diff --git a/Documentation/locking/ww-mutex-design.rst b/Documentation/locking/ww-mutex-design.rst index 54d9c17bb66b..6a4d7319f8f0 100644 --- a/Documentation/locking/ww-mutex-design.rst +++ b/Documentation/locking/ww-mutex-design.rst @@ -2,7 +2,7 @@ Wound/Wait Deadlock-Proof Mutex Design ====================================== -Please read mutex-design.txt first, as it applies to wait/wound mutexes too. +Please read mutex-design.rst first, as it applies to wait/wound mutexes too. Motivation for WW-Mutexes ------------------------- From 59c6a716b14ba3092ea685b6274d5233c18cc194 Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Thu, 12 Aug 2021 09:50:30 +0000 Subject: [PATCH 186/696] Documentation/process/maintainer-pgp-guide: Replace broken link to PGP path finder PGP pathfinder[1], which is suggested for finding a trust path to unknown PGP keys by 'maintainer-pgp-guide.rst', is not working now. This commit replaces it with other available tools. [1] https://pgp.cs.uu.nl/ Signed-off-by: SeongJae Park Reviewed-by: Konstantin Ryabitsev Link: https://lore.kernel.org/r/20210812095030.4704-2-sj38.park@gmail.com Signed-off-by: Jonathan Corbet --- Documentation/process/maintainer-pgp-guide.rst | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/Documentation/process/maintainer-pgp-guide.rst b/Documentation/process/maintainer-pgp-guide.rst index 8f8f1fee92b8..29e7d7b1cd44 100644 --- a/Documentation/process/maintainer-pgp-guide.rst +++ b/Documentation/process/maintainer-pgp-guide.rst @@ -944,12 +944,11 @@ have on your keyring:: uid [ unknown] Linus Torvalds sub rsa2048 2011-09-20 [E] -Next, open the `PGP pathfinder`_. In the "From" field, paste the key -fingerprint of Linus Torvalds from the output above. In the "To" field, -paste the key-id you found via ``gpg --search`` of the unknown key, and -check the results: - -- `Finding paths to Linus`_ +Next, find a trust path from Linus Torvalds to the key-id you found via ``gpg +--search`` of the unknown key. For this, you can use several tools including +https://github.com/mricon/wotmate, +https://git.kernel.org/pub/scm/docs/kernel/pgpkeys.git/tree/graphs, and +https://the.earth.li/~noodles/pathfind.html. If you get a few decent trust paths, then it's a pretty good indication that it is a valid key. You can add it to your keyring from the @@ -962,6 +961,3 @@ administrators of the PGP Pathfinder service to not be malicious (in fact, this goes against :ref:`devs_not_infra`). However, if you do not carefully maintain your own web of trust, then it is a marked improvement over blindly trusting keyservers. - -.. _`PGP pathfinder`: https://pgp.cs.uu.nl/ -.. _`Finding paths to Linus`: https://pgp.cs.uu.nl/paths/79BE3E4300411886/to/C94035C21B4F2AEB.html From f08fe9d29366c0204c3d571fa0088b1f0efd1a17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Sat, 14 Aug 2021 14:48:05 +0200 Subject: [PATCH 187/696] Documentation: arm: marvell: Add 88F6825 model into list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 88F6825 is just 88F6820 but without encryption acceleration hardware and is used e.g. in DTS file arch/arm/boot/dts/armada-385-clearfog-gtr.dtsi Signed-off-by: Pali Rohár Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/20210814124805.14568-1-pali@kernel.org Signed-off-by: Jonathan Corbet --- Documentation/arm/marvell.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/arm/marvell.rst b/Documentation/arm/marvell.rst index 85169bc3f538..56bb592dbd0c 100644 --- a/Documentation/arm/marvell.rst +++ b/Documentation/arm/marvell.rst @@ -140,6 +140,7 @@ EBU Armada family - 88F6821 Armada 382 - 88F6W21 Armada 383 - 88F6820 Armada 385 + - 88F6825 - 88F6828 Armada 388 - Product infos: https://web.archive.org/web/20181006144616/http://www.marvell.com/embedded-processors/armada-38x/ From fe450eeb4e6f1c19d088c99d2206ecabb8d0892b Mon Sep 17 00:00:00 2001 From: Changbin Du Date: Sat, 14 Aug 2021 09:48:31 +0800 Subject: [PATCH 188/696] Documentation: in_irq() cleanup Replace the obsolete and ambiguos macro in_irq() with new macro in_hardirq(). Signed-off-by: Changbin Du Link: https://lore.kernel.org/r/20210814014831.53083-1-changbin.du@gmail.com Signed-off-by: Jonathan Corbet --- Documentation/kernel-hacking/hacking.rst | 4 ++-- Documentation/kernel-hacking/locking.rst | 4 ++-- Documentation/translations/it_IT/kernel-hacking/hacking.rst | 2 +- Documentation/translations/it_IT/kernel-hacking/locking.rst | 4 ++-- Documentation/translations/zh_CN/kernel-hacking/hacking.rst | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Documentation/kernel-hacking/hacking.rst b/Documentation/kernel-hacking/hacking.rst index df65c19aa7df..55bd37a2efb0 100644 --- a/Documentation/kernel-hacking/hacking.rst +++ b/Documentation/kernel-hacking/hacking.rst @@ -76,8 +76,8 @@ handler is never re-entered: if the same interrupt arrives, it is queued fast: frequently it simply acknowledges the interrupt, marks a 'software interrupt' for execution and exits. -You can tell you are in a hardware interrupt, because -:c:func:`in_irq()` returns true. +You can tell you are in a hardware interrupt, because in_hardirq() returns +true. .. warning:: diff --git a/Documentation/kernel-hacking/locking.rst b/Documentation/kernel-hacking/locking.rst index ed1284c6f078..94232ed1d592 100644 --- a/Documentation/kernel-hacking/locking.rst +++ b/Documentation/kernel-hacking/locking.rst @@ -1406,7 +1406,7 @@ bh half will be running at any time. Hardware Interrupt / Hardware IRQ - Hardware interrupt request. in_irq() returns true in a + Hardware interrupt request. in_hardirq() returns true in a hardware interrupt handler. Interrupt Context @@ -1418,7 +1418,7 @@ SMP (``CONFIG_SMP=y``). Software Interrupt / softirq - Software interrupt handler. in_irq() returns false; + Software interrupt handler. in_hardirq() returns false; in_softirq() returns true. Tasklets and softirqs both fall into the category of 'software interrupts'. diff --git a/Documentation/translations/it_IT/kernel-hacking/hacking.rst b/Documentation/translations/it_IT/kernel-hacking/hacking.rst index b4ea00f1b583..d5c521327f6a 100644 --- a/Documentation/translations/it_IT/kernel-hacking/hacking.rst +++ b/Documentation/translations/it_IT/kernel-hacking/hacking.rst @@ -90,7 +90,7 @@ i gestori d'interruzioni devono essere veloci: spesso si limitano esclusivamente a notificare la presa in carico dell'interruzione, programmare una 'interruzione software' per l'esecuzione e quindi terminare. -Potete dire d'essere in una interruzione hardware perché :c:func:`in_irq()` +Potete dire d'essere in una interruzione hardware perché in_hardirq() ritorna vero. .. warning:: diff --git a/Documentation/translations/it_IT/kernel-hacking/locking.rst b/Documentation/translations/it_IT/kernel-hacking/locking.rst index 1e7c84def369..1efb8293bf1f 100644 --- a/Documentation/translations/it_IT/kernel-hacking/locking.rst +++ b/Documentation/translations/it_IT/kernel-hacking/locking.rst @@ -1459,11 +1459,11 @@ contesto utente che hardware. interruzione hardware - Richiesta di interruzione hardware. in_irq() ritorna vero in un + Richiesta di interruzione hardware. in_hardirq() ritorna vero in un gestore d'interruzioni hardware. interruzione software / softirq - Gestore di interruzioni software: in_irq() ritorna falso; + Gestore di interruzioni software: in_hardirq() ritorna falso; in_softirq() ritorna vero. I tasklet e le softirq sono entrambi considerati 'interruzioni software'. diff --git a/Documentation/translations/zh_CN/kernel-hacking/hacking.rst b/Documentation/translations/zh_CN/kernel-hacking/hacking.rst index ab974faddecf..f2bc154c5bcc 100644 --- a/Documentation/translations/zh_CN/kernel-hacking/hacking.rst +++ b/Documentation/translations/zh_CN/kernel-hacking/hacking.rst @@ -68,7 +68,7 @@ 它将被排队(或丢弃)。因为它会关闭中断,所以处理程序必须很快:通常它只是 确认中断,标记一个“软件中断”以执行并退出。 -您可以通过 :c:func:`in_irq()` 返回真来判断您处于硬件中断状态。 +您可以通过 in_hardirq() 返回真来判断您处于硬件中断状态。 .. warning:: From c19430eec84f7440651266e5f5a811df3d6f46ae Mon Sep 17 00:00:00 2001 From: Jinay Jain Date: Thu, 12 Aug 2021 08:25:28 -0700 Subject: [PATCH 189/696] Documentation: block: blk-mq: Fix small typo in multi-queue docs Fixed a small typo in the documentation for multi-queue block IO. Signed-off-by: Jinay Jain Link: https://lore.kernel.org/r/20210812152528.300668-1-jinaybjain@gmail.com Signed-off-by: Jonathan Corbet --- Documentation/block/blk-mq.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/block/blk-mq.rst b/Documentation/block/blk-mq.rst index d96118c73954..31f52f326971 100644 --- a/Documentation/block/blk-mq.rst +++ b/Documentation/block/blk-mq.rst @@ -54,7 +54,7 @@ layer or if we want to try to merge requests. In both cases, requests will be sent to the software queue. Then, after the requests are processed by software queues, they will be placed -at the hardware queue, a second stage queue were the hardware has direct access +at the hardware queue, a second stage queue where the hardware has direct access to process those requests. However, if the hardware does not have enough resources to accept more requests, blk-mq will places requests on a temporary queue, to be sent in the future, when the hardware is able. From d4477209c8fbc1bb0035ca44426e02238f68c5fd Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Tue, 17 Aug 2021 10:16:21 +0100 Subject: [PATCH 190/696] Documentation/features/vm: correct huge-vmap APIs In commit: bbc180a5adb05ee8 ("mm: HUGE_VMAP arch support cleanup") We replaced: * ioremap_pud_enabled() with arch_vmap_pud_supported() * ioremap_pmd_enabled() with arch_vmap_pmd_supported() Update the documentation accordingly. Signed-off-by: Mark Rutland Cc: Andrew Morton Cc: Ingo Molnar Cc: Jonathan Corbet Cc: Nicholas Piggin Cc: linux-doc@vger.kernel.org Link: https://lore.kernel.org/r/20210817091621.16799-1-mark.rutland@arm.com Signed-off-by: Jonathan Corbet --- Documentation/features/vm/huge-vmap/arch-support.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/features/vm/huge-vmap/arch-support.txt b/Documentation/features/vm/huge-vmap/arch-support.txt index 439fd9069b8b..bc53905a0306 100644 --- a/Documentation/features/vm/huge-vmap/arch-support.txt +++ b/Documentation/features/vm/huge-vmap/arch-support.txt @@ -1,7 +1,7 @@ # # Feature name: huge-vmap # Kconfig: HAVE_ARCH_HUGE_VMAP -# description: arch supports the ioremap_pud_enabled() and ioremap_pmd_enabled() VM APIs +# description: arch supports the arch_vmap_pud_supported() and arch_vmap_pmd_supported() VM APIs # ----------------------- | arch |status| From 8137a49e1567726eb10fcf55ad141ac19804ca6b Mon Sep 17 00:00:00 2001 From: Yanteng Si Date: Sat, 21 Aug 2021 16:18:00 +0800 Subject: [PATCH 191/696] docs/zh_CN: Modify the translator tag and fix the wrong word Fix a wrong word; Fix old Original tag; Remove unnecessary blank lines; Modify the translator tag to be consistent with the current. Signed-off-by: Yanteng Si Reviewed-by: Alex Shi Link: https://lore.kernel.org/r/20210821081800.2205103-1-siyanteng@loongson.cn Signed-off-by: Jonathan Corbet --- Documentation/translations/zh_CN/core-api/cachetlb.rst | 2 +- Documentation/translations/zh_CN/core-api/index.rst | 8 +++++--- .../translations/zh_CN/core-api/irq/concepts.rst | 8 +++++--- Documentation/translations/zh_CN/core-api/irq/index.rst | 7 +++++-- .../translations/zh_CN/core-api/irq/irq-affinity.rst | 8 +++++--- .../translations/zh_CN/core-api/irq/irq-domain.rst | 8 +++++--- .../translations/zh_CN/core-api/irq/irqflags-tracing.rst | 8 +++++--- Documentation/translations/zh_CN/core-api/kernel-api.rst | 6 ++++-- Documentation/translations/zh_CN/core-api/kobject.rst | 5 ++++- Documentation/translations/zh_CN/core-api/local_ops.rst | 6 ++++-- Documentation/translations/zh_CN/core-api/padata.rst | 5 ++++- .../translations/zh_CN/core-api/printk-basics.rst | 6 ++++-- .../translations/zh_CN/core-api/printk-formats.rst | 6 ++++-- .../translations/zh_CN/core-api/refcount-vs-atomic.rst | 6 ++++-- .../translations/zh_CN/core-api/symbol-namespaces.rst | 6 ++++-- Documentation/translations/zh_CN/core-api/workqueue.rst | 6 ++++-- Documentation/translations/zh_CN/cpu-freq/core.rst | 8 +++++--- Documentation/translations/zh_CN/cpu-freq/cpu-drivers.rst | 8 +++++--- .../translations/zh_CN/cpu-freq/cpufreq-stats.rst | 8 +++++--- Documentation/translations/zh_CN/cpu-freq/index.rst | 8 +++++--- Documentation/translations/zh_CN/filesystems/debugfs.rst | 2 +- Documentation/translations/zh_CN/iio/ep93xx_adc.rst | 8 +++++--- Documentation/translations/zh_CN/iio/iio_configfs.rst | 8 +++++--- Documentation/translations/zh_CN/iio/index.rst | 8 +++++--- Documentation/translations/zh_CN/mips/booting.rst | 7 +++++-- Documentation/translations/zh_CN/mips/features.rst | 7 +++++-- Documentation/translations/zh_CN/mips/index.rst | 7 +++++-- Documentation/translations/zh_CN/mips/ingenic-tcu.rst | 7 +++++-- Documentation/translations/zh_CN/openrisc/index.rst | 8 +++++--- .../translations/zh_CN/openrisc/openrisc_port.rst | 7 +++++-- Documentation/translations/zh_CN/openrisc/todo.rst | 7 +++++-- Documentation/translations/zh_CN/parisc/debugging.rst | 5 ++++- Documentation/translations/zh_CN/parisc/index.rst | 5 ++++- Documentation/translations/zh_CN/parisc/registers.rst | 5 ++++- .../translations/zh_CN/riscv/boot-image-header.rst | 8 +++++--- Documentation/translations/zh_CN/riscv/index.rst | 8 +++++--- .../translations/zh_CN/riscv/patch-acceptance.rst | 8 +++++--- Documentation/translations/zh_CN/riscv/pmu.rst | 8 +++++--- 38 files changed, 170 insertions(+), 86 deletions(-) diff --git a/Documentation/translations/zh_CN/core-api/cachetlb.rst b/Documentation/translations/zh_CN/core-api/cachetlb.rst index 8376485a534d..b5bb13a707cd 100644 --- a/Documentation/translations/zh_CN/core-api/cachetlb.rst +++ b/Documentation/translations/zh_CN/core-api/cachetlb.rst @@ -80,7 +80,7 @@ cpu上对这个地址空间进行刷新。 5) ``void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep)`` - 在每个页面故障结束时,这个程序被调用,以告诉体系结构特定的代码,在 + 在每个缺页异常结束时,这个程序被调用,以告诉体系结构特定的代码,在 软件页表中,在地址空间“vma->vm_mm”的虚拟地址“地址”处,现在存在 一个翻译。 diff --git a/Documentation/translations/zh_CN/core-api/index.rst b/Documentation/translations/zh_CN/core-api/index.rst index d5e947d8b6f1..72f0a36daa1c 100644 --- a/Documentation/translations/zh_CN/core-api/index.rst +++ b/Documentation/translations/zh_CN/core-api/index.rst @@ -1,11 +1,13 @@ .. include:: ../disclaimer-zh_CN.rst -:Original: :doc:`../../../core-api/irq/index` -:Translator: Yanteng Si +:Original: Documentation/core-api/index.rst + +:翻译: + + 司延腾 Yanteng Si .. _cn_core-api_index.rst: - =========== 核心API文档 =========== diff --git a/Documentation/translations/zh_CN/core-api/irq/concepts.rst b/Documentation/translations/zh_CN/core-api/irq/concepts.rst index 41455bf0f783..9957f0453353 100644 --- a/Documentation/translations/zh_CN/core-api/irq/concepts.rst +++ b/Documentation/translations/zh_CN/core-api/irq/concepts.rst @@ -1,11 +1,13 @@ .. include:: ../../disclaimer-zh_CN.rst -:Original: :doc:`../../../../core-api/irq/concepts` -:Translator: Yanteng Si +:Original: Documentation/core-api/irq/concepts.rst + +:翻译: + + 司延腾 Yanteng Si .. _cn_concepts.rst: - =========== 什么是IRQ? =========== diff --git a/Documentation/translations/zh_CN/core-api/irq/index.rst b/Documentation/translations/zh_CN/core-api/irq/index.rst index 910ccabf041f..ba6acc4b48e5 100644 --- a/Documentation/translations/zh_CN/core-api/irq/index.rst +++ b/Documentation/translations/zh_CN/core-api/irq/index.rst @@ -1,7 +1,10 @@ .. include:: ../../disclaimer-zh_CN.rst -:Original: :doc:`../../../../core-api/irq/index` -:Translator: Yanteng Si +:Original: Documentation/core-api/irq/index.rst + +:翻译: + + 司延腾 Yanteng Si .. _cn_irq_index.rst: diff --git a/Documentation/translations/zh_CN/core-api/irq/irq-affinity.rst b/Documentation/translations/zh_CN/core-api/irq/irq-affinity.rst index 82a4428f22fd..7addd5f27a88 100644 --- a/Documentation/translations/zh_CN/core-api/irq/irq-affinity.rst +++ b/Documentation/translations/zh_CN/core-api/irq/irq-affinity.rst @@ -1,11 +1,13 @@ .. include:: ../../disclaimer-zh_CN.rst -:Original: :doc:`../../../../core-api/irq/irq-affinity` -:Translator: Yanteng Si +:Original: Documentation/core-api/irq/irq-affinity + +:翻译: + + 司延腾 Yanteng Si .. _cn_irq-affinity.rst: - ============== SMP IRQ 亲和性 ============== diff --git a/Documentation/translations/zh_CN/core-api/irq/irq-domain.rst b/Documentation/translations/zh_CN/core-api/irq/irq-domain.rst index 3c82dd307a46..7d077742f758 100644 --- a/Documentation/translations/zh_CN/core-api/irq/irq-domain.rst +++ b/Documentation/translations/zh_CN/core-api/irq/irq-domain.rst @@ -1,11 +1,13 @@ .. include:: ../../disclaimer-zh_CN.rst -:Original: :doc:`../../../../core-api/irq/irq-domain` -:Translator: Yanteng Si +:Original: Documentation/core-api/irq/irq-domain.rst + +:翻译: + + 司延腾 Yanteng Si .. _cn_irq-domain.rst: - ======================= irq_domain 中断号映射库 ======================= diff --git a/Documentation/translations/zh_CN/core-api/irq/irqflags-tracing.rst b/Documentation/translations/zh_CN/core-api/irq/irqflags-tracing.rst index c889bd0f65d9..9af50b4b8c2d 100644 --- a/Documentation/translations/zh_CN/core-api/irq/irqflags-tracing.rst +++ b/Documentation/translations/zh_CN/core-api/irq/irqflags-tracing.rst @@ -1,11 +1,13 @@ .. include:: ../../disclaimer-zh_CN.rst -:Original: :doc:`../../../../core-api/irq/irqflags-tracing` -:Translator: Yanteng Si +:Original: Documentation/core-api/irq/irqflags-tracing.rst + +:翻译: + + 司延腾 Yanteng Si .. _cn_irqflags-tracing.rst: - ================= IRQ-flags状态追踪 ================= diff --git a/Documentation/translations/zh_CN/core-api/kernel-api.rst b/Documentation/translations/zh_CN/core-api/kernel-api.rst index d6f815ec265b..ab7d81889340 100644 --- a/Documentation/translations/zh_CN/core-api/kernel-api.rst +++ b/Documentation/translations/zh_CN/core-api/kernel-api.rst @@ -1,11 +1,13 @@ .. include:: ../disclaimer-zh_CN.rst :Original: Documentation/core-api/kernel-api.rst -:Translator: Yanteng Si + +:翻译: + + 司延腾 Yanteng Si .. _cn_kernel-api.rst: - ============ Linux内核API ============ diff --git a/Documentation/translations/zh_CN/core-api/kobject.rst b/Documentation/translations/zh_CN/core-api/kobject.rst index f0e6a4aeb372..b7c37794cc7f 100644 --- a/Documentation/translations/zh_CN/core-api/kobject.rst +++ b/Documentation/translations/zh_CN/core-api/kobject.rst @@ -1,7 +1,10 @@ .. include:: ../disclaimer-zh_CN.rst :Original: Documentation/core-api/kobject.rst -:Translator: Yanteng Si + +:翻译: + + 司延腾 Yanteng Si .. _cn_core_api_kobject.rst: diff --git a/Documentation/translations/zh_CN/core-api/local_ops.rst b/Documentation/translations/zh_CN/core-api/local_ops.rst index ee67379b6869..41e4525038e8 100644 --- a/Documentation/translations/zh_CN/core-api/local_ops.rst +++ b/Documentation/translations/zh_CN/core-api/local_ops.rst @@ -1,11 +1,13 @@ .. include:: ../disclaimer-zh_CN.rst :Original: Documentation/core-api/local_ops.rst -:Translator: Yanteng Si + +:翻译: + + 司延腾 Yanteng Si .. _cn_local_ops: - ======================== 本地原子操作的语义和行为 ======================== diff --git a/Documentation/translations/zh_CN/core-api/padata.rst b/Documentation/translations/zh_CN/core-api/padata.rst index c627f8f131f9..781d30675afd 100644 --- a/Documentation/translations/zh_CN/core-api/padata.rst +++ b/Documentation/translations/zh_CN/core-api/padata.rst @@ -3,7 +3,10 @@ .. include:: ../disclaimer-zh_CN.rst :Original: Documentation/core-api/padata.rst -:Translator: Yanteng Si + +:翻译: + + 司延腾 Yanteng Si .. _cn_core_api_padata.rst: diff --git a/Documentation/translations/zh_CN/core-api/printk-basics.rst b/Documentation/translations/zh_CN/core-api/printk-basics.rst index 2b20f6303a82..d574de3167c8 100644 --- a/Documentation/translations/zh_CN/core-api/printk-basics.rst +++ b/Documentation/translations/zh_CN/core-api/printk-basics.rst @@ -2,11 +2,13 @@ .. include:: ../disclaimer-zh_CN.rst :Original: Documentation/core-api/printk-basics.rst -:Translator: Yanteng Si + +:翻译: + + 司延腾 Yanteng Si .. _cn_printk-basics.rst: - ================== 使用printk记录消息 ================== diff --git a/Documentation/translations/zh_CN/core-api/printk-formats.rst b/Documentation/translations/zh_CN/core-api/printk-formats.rst index a680c8f164c3..ce39c788cf5a 100644 --- a/Documentation/translations/zh_CN/core-api/printk-formats.rst +++ b/Documentation/translations/zh_CN/core-api/printk-formats.rst @@ -1,11 +1,13 @@ .. include:: ../disclaimer-zh_CN.rst :Original: Documentation/core-api/printk-formats.rst -:Translator: Yanteng Si + +:翻译: + + 司延腾 Yanteng Si .. _cn_printk-formats.rst: - ============================== 如何获得正确的printk格式占位符 ============================== diff --git a/Documentation/translations/zh_CN/core-api/refcount-vs-atomic.rst b/Documentation/translations/zh_CN/core-api/refcount-vs-atomic.rst index ea834e38d2f6..e2467fd26fc0 100644 --- a/Documentation/translations/zh_CN/core-api/refcount-vs-atomic.rst +++ b/Documentation/translations/zh_CN/core-api/refcount-vs-atomic.rst @@ -1,11 +1,13 @@ .. include:: ../disclaimer-zh_CN.rst :Original: Documentation/core-api/refcount-vs-atomic.rst -:Translator: Yanteng Si + +:翻译: + + 司延腾 Yanteng Si .. _cn_refcount-vs-atomic: - ======================================= 与atomic_t相比,refcount_t的API是这样的 ======================================= diff --git a/Documentation/translations/zh_CN/core-api/symbol-namespaces.rst b/Documentation/translations/zh_CN/core-api/symbol-namespaces.rst index ce05c29c7697..6abf7ed534ca 100644 --- a/Documentation/translations/zh_CN/core-api/symbol-namespaces.rst +++ b/Documentation/translations/zh_CN/core-api/symbol-namespaces.rst @@ -1,11 +1,13 @@ .. include:: ../disclaimer-zh_CN.rst :Original: Documentation/core-api/symbol-namespaces.rst -:Translator: Yanteng Si + +:翻译: + + 司延腾 Yanteng Si .. _cn_symbol-namespaces.rst: - ================================= 符号命名空间(Symbol Namespaces) ================================= diff --git a/Documentation/translations/zh_CN/core-api/workqueue.rst b/Documentation/translations/zh_CN/core-api/workqueue.rst index 0b8f730db6c0..e372fa5cf101 100644 --- a/Documentation/translations/zh_CN/core-api/workqueue.rst +++ b/Documentation/translations/zh_CN/core-api/workqueue.rst @@ -2,11 +2,13 @@ .. include:: ../disclaimer-zh_CN.rst :Original: Documentation/core-api/workqueue.rst -:Translator: Yanteng Si + +:翻译: + + 司延腾 Yanteng Si .. _cn_workqueue.rst: - ========================= 并发管理的工作队列 (cmwq) ========================= diff --git a/Documentation/translations/zh_CN/cpu-freq/core.rst b/Documentation/translations/zh_CN/cpu-freq/core.rst index 19fb9c029cfe..0c6fd447ced6 100644 --- a/Documentation/translations/zh_CN/cpu-freq/core.rst +++ b/Documentation/translations/zh_CN/cpu-freq/core.rst @@ -1,12 +1,14 @@ .. SPDX-License-Identifier: GPL-2.0 .. include:: ../disclaimer-zh_CN.rst -:Original: :doc:`../../../cpu-freq/core` -:Translator: Yanteng Si +:Original: Documentation/cpu-freq/core.rst + +:翻译: + + 司延腾 Yanteng Si .. _cn_core.rst: - ==================================== CPUFreq核心和CPUFreq通知器的通用说明 ==================================== diff --git a/Documentation/translations/zh_CN/cpu-freq/cpu-drivers.rst b/Documentation/translations/zh_CN/cpu-freq/cpu-drivers.rst index 5ae9cfa2ec55..b9846173dd71 100644 --- a/Documentation/translations/zh_CN/cpu-freq/cpu-drivers.rst +++ b/Documentation/translations/zh_CN/cpu-freq/cpu-drivers.rst @@ -2,12 +2,14 @@ .. include:: ../disclaimer-zh_CN.rst -:Original: :doc:`../../../cpu-freq/cpu-drivers` -:Translator: Yanteng Si +:Original: Documentation/cpu-freq/cpu-drivers.rst + +:翻译: + + 司延腾 Yanteng Si .. _cn_cpu-drivers.rst: - ======================================= 如何实现一个新的CPUFreq处理器驱动程序? ======================================= diff --git a/Documentation/translations/zh_CN/cpu-freq/cpufreq-stats.rst b/Documentation/translations/zh_CN/cpu-freq/cpufreq-stats.rst index c90d1d8353ed..f14423099d4b 100644 --- a/Documentation/translations/zh_CN/cpu-freq/cpufreq-stats.rst +++ b/Documentation/translations/zh_CN/cpu-freq/cpufreq-stats.rst @@ -2,12 +2,14 @@ .. include:: ../disclaimer-zh_CN.rst -:Original: :doc:`../../../cpu-freq/cpufreq-stats` -:Translator: Yanteng Si +:Original: Documentation/cpu-freq/cpufreq-stats.rst + +:翻译: + + 司延腾 Yanteng Si .. _cn_cpufreq-stats.rst: - ========================================== sysfs CPUFreq Stats的一般说明 ========================================== diff --git a/Documentation/translations/zh_CN/cpu-freq/index.rst b/Documentation/translations/zh_CN/cpu-freq/index.rst index 65074e211940..c6e50963cd33 100644 --- a/Documentation/translations/zh_CN/cpu-freq/index.rst +++ b/Documentation/translations/zh_CN/cpu-freq/index.rst @@ -2,12 +2,14 @@ .. include:: ../disclaimer-zh_CN.rst -:Original: :doc:`../../../cpu-freq/index` -:Translator: Yanteng Si +:Original: Documentation/cpu-freq/index.rst + +:翻译: + + 司延腾 Yanteng Si .. _cn_index.rst: - ======================================================= Linux CPUFreq - Linux(TM)内核中的CPU频率和电压升降代码 ======================================================= diff --git a/Documentation/translations/zh_CN/filesystems/debugfs.rst b/Documentation/translations/zh_CN/filesystems/debugfs.rst index 822c4d42fdf9..4981a82dd651 100644 --- a/Documentation/translations/zh_CN/filesystems/debugfs.rst +++ b/Documentation/translations/zh_CN/filesystems/debugfs.rst @@ -2,7 +2,7 @@ .. include:: ../disclaimer-zh_CN.rst -:Original: :doc:`../../../filesystems/debugfs` +:Original: Documentation/filesystems/debugfs.rst ======= Debugfs diff --git a/Documentation/translations/zh_CN/iio/ep93xx_adc.rst b/Documentation/translations/zh_CN/iio/ep93xx_adc.rst index 7e91d2197867..64f3f3508353 100644 --- a/Documentation/translations/zh_CN/iio/ep93xx_adc.rst +++ b/Documentation/translations/zh_CN/iio/ep93xx_adc.rst @@ -1,11 +1,13 @@ .. include:: ../disclaimer-zh_CN.rst -:Original: :doc:`../../../iio/ep93xx_adc` -:Translator: Yanteng Si +:Original: Documentation/iio/ep93xx_adc.rst + +:翻译: + + 司延腾 Yanteng Si .. _cn_iio_ep93xx_adc: - ================================== 思睿逻辑 EP93xx 模拟数字转换器驱动 ================================== diff --git a/Documentation/translations/zh_CN/iio/iio_configfs.rst b/Documentation/translations/zh_CN/iio/iio_configfs.rst index 274488e8dce4..d5460e951804 100644 --- a/Documentation/translations/zh_CN/iio/iio_configfs.rst +++ b/Documentation/translations/zh_CN/iio/iio_configfs.rst @@ -1,11 +1,13 @@ .. include:: ../disclaimer-zh_CN.rst -:Original: :doc:`../../../iio/iio_configfs` -:Translator: Yanteng Si +:Original: Documentation/iio/iio_configfs.rst + +:翻译: + + 司延腾 Yanteng Si .. _cn_iio_configfs: - ===================== 工业 IIO configfs支持 ===================== diff --git a/Documentation/translations/zh_CN/iio/index.rst b/Documentation/translations/zh_CN/iio/index.rst index 7087076a10f6..32d69047b16a 100644 --- a/Documentation/translations/zh_CN/iio/index.rst +++ b/Documentation/translations/zh_CN/iio/index.rst @@ -2,12 +2,14 @@ .. include:: ../disclaimer-zh_CN.rst -:Original: :doc:`../../../iio/index` -:Translator: Yanteng Si +:Original: Documentation/iio/index.rst + +:翻译: + + 司延腾 Yanteng Si .. _cn_iio_index: - ======== 工业 I/O ======== diff --git a/Documentation/translations/zh_CN/mips/booting.rst b/Documentation/translations/zh_CN/mips/booting.rst index 96453e1b962e..e0bbd3f20862 100644 --- a/Documentation/translations/zh_CN/mips/booting.rst +++ b/Documentation/translations/zh_CN/mips/booting.rst @@ -2,8 +2,11 @@ .. include:: ../disclaimer-zh_CN.rst -:Original: :doc:`../../../mips/booting` -:Translator: Yanteng Si +:Original: Documentation/mips/booting.rst + +:翻译: + + 司延腾 Yanteng Si .. _cn_booting: diff --git a/Documentation/translations/zh_CN/mips/features.rst b/Documentation/translations/zh_CN/mips/features.rst index 93d93d06b1b3..b61dab06ceaf 100644 --- a/Documentation/translations/zh_CN/mips/features.rst +++ b/Documentation/translations/zh_CN/mips/features.rst @@ -2,8 +2,11 @@ .. include:: ../disclaimer-zh_CN.rst -:Original: :doc:`../../../mips/features` -:Translator: Yanteng Si +:Original: Documentation/mips/features.rst + +:翻译: + + 司延腾 Yanteng Si .. _cn_features: diff --git a/Documentation/translations/zh_CN/mips/index.rst b/Documentation/translations/zh_CN/mips/index.rst index b85033f9d67c..192c6adbb72e 100644 --- a/Documentation/translations/zh_CN/mips/index.rst +++ b/Documentation/translations/zh_CN/mips/index.rst @@ -2,8 +2,11 @@ .. include:: ../disclaimer-zh_CN.rst -:Original: :doc:`../../../mips/index` -:Translator: Yanteng Si +:Original: Documentation/mips/index.rst + +:翻译: + + 司延腾 Yanteng Si =========================== MIPS特性文档 diff --git a/Documentation/translations/zh_CN/mips/ingenic-tcu.rst b/Documentation/translations/zh_CN/mips/ingenic-tcu.rst index f04ba407384a..ddbe149c517b 100644 --- a/Documentation/translations/zh_CN/mips/ingenic-tcu.rst +++ b/Documentation/translations/zh_CN/mips/ingenic-tcu.rst @@ -2,8 +2,11 @@ .. include:: ../disclaimer-zh_CN.rst -:Original: :doc:`../../../mips/ingenic-tcu` -:Translator: Yanteng Si +:Original: Documentation/mips/ingenic-tcu.rst + +:翻译: + + 司延腾 Yanteng Si .. _cn_ingenic-tcu: diff --git a/Documentation/translations/zh_CN/openrisc/index.rst b/Documentation/translations/zh_CN/openrisc/index.rst index d722642796c8..9ad6cc600884 100644 --- a/Documentation/translations/zh_CN/openrisc/index.rst +++ b/Documentation/translations/zh_CN/openrisc/index.rst @@ -2,12 +2,14 @@ .. include:: ../disclaimer-zh_CN.rst -:Original: :doc:`../../../openrisc/index` -:Translator: Yanteng Si +:Original: Documentation/openrisc/index.rst + +:翻译: + + 司延腾 Yanteng Si .. _cn_openrisc_index: - ================= OpenRISC 体系架构 ================= diff --git a/Documentation/translations/zh_CN/openrisc/openrisc_port.rst b/Documentation/translations/zh_CN/openrisc/openrisc_port.rst index e87d0eec281d..b8a67670492d 100644 --- a/Documentation/translations/zh_CN/openrisc/openrisc_port.rst +++ b/Documentation/translations/zh_CN/openrisc/openrisc_port.rst @@ -1,7 +1,10 @@ .. include:: ../disclaimer-zh_CN.rst -:Original: :doc:`../../../openrisc/openrisc_port` -:Translator: Yanteng Si +:Original: Documentation/openrisc/openrisc_port.rst + +:翻译: + + 司延腾 Yanteng Si .. _cn_openrisc_port: diff --git a/Documentation/translations/zh_CN/openrisc/todo.rst b/Documentation/translations/zh_CN/openrisc/todo.rst index 9944ad05473b..63c38717edb1 100644 --- a/Documentation/translations/zh_CN/openrisc/todo.rst +++ b/Documentation/translations/zh_CN/openrisc/todo.rst @@ -1,7 +1,10 @@ .. include:: ../disclaimer-zh_CN.rst -:Original: :doc:`../../../openrisc/todo` -:Translator: Yanteng Si +:Original: Documentation/openrisc/todo.rst + +:翻译: + + 司延腾 Yanteng Si .. _cn_openrisc_todo.rst: diff --git a/Documentation/translations/zh_CN/parisc/debugging.rst b/Documentation/translations/zh_CN/parisc/debugging.rst index c21beb986e15..68b73eb57105 100644 --- a/Documentation/translations/zh_CN/parisc/debugging.rst +++ b/Documentation/translations/zh_CN/parisc/debugging.rst @@ -1,7 +1,10 @@ .. include:: ../disclaimer-zh_CN.rst :Original: Documentation/parisc/debugging.rst -:Translator: Yanteng Si + +:翻译: + + 司延腾 Yanteng Si .. _cn_parisc_debugging: diff --git a/Documentation/translations/zh_CN/parisc/index.rst b/Documentation/translations/zh_CN/parisc/index.rst index a47454ebe32e..0cc553fc8272 100644 --- a/Documentation/translations/zh_CN/parisc/index.rst +++ b/Documentation/translations/zh_CN/parisc/index.rst @@ -2,7 +2,10 @@ .. include:: ../disclaimer-zh_CN.rst :Original: Documentation/parisc/index.rst -:Translator: Yanteng Si + +:翻译: + + 司延腾 Yanteng Si .. _cn_parisc_index: diff --git a/Documentation/translations/zh_CN/parisc/registers.rst b/Documentation/translations/zh_CN/parisc/registers.rst index 71e2404cd103..d2ab1874a602 100644 --- a/Documentation/translations/zh_CN/parisc/registers.rst +++ b/Documentation/translations/zh_CN/parisc/registers.rst @@ -1,7 +1,10 @@ .. include:: ../disclaimer-zh_CN.rst :Original: Documentation/parisc/registers.rst -:Translator: Yanteng Si + +:翻译: + + 司延腾 Yanteng Si .. _cn_parisc_registers: diff --git a/Documentation/translations/zh_CN/riscv/boot-image-header.rst b/Documentation/translations/zh_CN/riscv/boot-image-header.rst index 241bf9c1bcbe..0234c28a7114 100644 --- a/Documentation/translations/zh_CN/riscv/boot-image-header.rst +++ b/Documentation/translations/zh_CN/riscv/boot-image-header.rst @@ -1,11 +1,13 @@ .. include:: ../disclaimer-zh_CN.rst -:Original: :doc:`../../../riscv/boot-image-header` -:Translator: Yanteng Si +:Original: Documentation/riscv/boot-image-header.rst + +:翻译: + + 司延腾 Yanteng Si .. _cn_boot-image-header.rst: - ========================== RISC-V Linux启动镜像文件头 ========================== diff --git a/Documentation/translations/zh_CN/riscv/index.rst b/Documentation/translations/zh_CN/riscv/index.rst index db13b1101490..bbf5d7b3777a 100644 --- a/Documentation/translations/zh_CN/riscv/index.rst +++ b/Documentation/translations/zh_CN/riscv/index.rst @@ -2,12 +2,14 @@ .. include:: ../disclaimer-zh_CN.rst -:Original: :doc:`../../../riscv/index` -:Translator: Yanteng Si +:Original: Documentation/riscv/index.rst + +:翻译: + + 司延腾 Yanteng Si .. _cn_riscv_index: - =============== RISC-V 体系结构 =============== diff --git a/Documentation/translations/zh_CN/riscv/patch-acceptance.rst b/Documentation/translations/zh_CN/riscv/patch-acceptance.rst index 9fd1c8216763..d180d24717bf 100644 --- a/Documentation/translations/zh_CN/riscv/patch-acceptance.rst +++ b/Documentation/translations/zh_CN/riscv/patch-acceptance.rst @@ -2,12 +2,14 @@ .. include:: ../disclaimer-zh_CN.rst -:Original: :doc:`../../../riscv/patch-acceptance` -:Translator: Yanteng Si +:Original: Documentation/riscv/patch-acceptance.rst + +:翻译: + + 司延腾 Yanteng Si .. _cn_riscv_patch-acceptance: - arch/riscv 开发者维护指南 ========================= diff --git a/Documentation/translations/zh_CN/riscv/pmu.rst b/Documentation/translations/zh_CN/riscv/pmu.rst index 22dcf3a9ca6e..7ec801026c4d 100644 --- a/Documentation/translations/zh_CN/riscv/pmu.rst +++ b/Documentation/translations/zh_CN/riscv/pmu.rst @@ -1,11 +1,13 @@ .. include:: ../disclaimer-zh_CN.rst -:Original: :doc:`../../../riscv/pmu` -:Translator: Yanteng Si +:Original: Documentation/riscv/pmu.rst + +:翻译: + + 司延腾 Yanteng Si .. _cn_riscv_pmu: - ======================== RISC-V平台上对PMUs的支持 ======================== From e5cb9494fe799f7358554d5b66568ac16e305499 Mon Sep 17 00:00:00 2001 From: Hu Haowen Date: Sat, 21 Aug 2021 17:40:57 +0800 Subject: [PATCH 192/696] docs/zh_TW: add translations for zh_TW/arm64 Create new translations for zh_TW/arm64 and link them to index. Signed-off-by: Hu Haowen Link: https://lore.kernel.org/r/20210821094059.64300-1-src.res@email.cn Signed-off-by: Jonathan Corbet --- .../translations/zh_TW/arm64/amu.rst | 104 ++++++++ .../translations/zh_TW/arm64/booting.txt | 251 ++++++++++++++++++ .../translations/zh_TW/arm64/elf_hwcaps.rst | 244 +++++++++++++++++ .../translations/zh_TW/arm64/hugetlbpage.rst | 49 ++++ .../translations/zh_TW/arm64/index.rst | 23 ++ .../zh_TW/arm64/legacy_instructions.txt | 77 ++++++ .../translations/zh_TW/arm64/memory.txt | 119 +++++++++ .../translations/zh_TW/arm64/perf.rst | 88 ++++++ .../zh_TW/arm64/silicon-errata.txt | 79 ++++++ .../zh_TW/arm64/tagged-pointers.txt | 57 ++++ Documentation/translations/zh_TW/index.rst | 5 + 11 files changed, 1096 insertions(+) create mode 100644 Documentation/translations/zh_TW/arm64/amu.rst create mode 100644 Documentation/translations/zh_TW/arm64/booting.txt create mode 100644 Documentation/translations/zh_TW/arm64/elf_hwcaps.rst create mode 100644 Documentation/translations/zh_TW/arm64/hugetlbpage.rst create mode 100644 Documentation/translations/zh_TW/arm64/index.rst create mode 100644 Documentation/translations/zh_TW/arm64/legacy_instructions.txt create mode 100644 Documentation/translations/zh_TW/arm64/memory.txt create mode 100644 Documentation/translations/zh_TW/arm64/perf.rst create mode 100644 Documentation/translations/zh_TW/arm64/silicon-errata.txt create mode 100644 Documentation/translations/zh_TW/arm64/tagged-pointers.txt diff --git a/Documentation/translations/zh_TW/arm64/amu.rst b/Documentation/translations/zh_TW/arm64/amu.rst new file mode 100644 index 000000000000..ffdc466e0f62 --- /dev/null +++ b/Documentation/translations/zh_TW/arm64/amu.rst @@ -0,0 +1,104 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: ../disclaimer-zh_TW.rst + +:Original: :ref:`Documentation/arm64/amu.rst ` + +Translator: Bailu Lin + Hu Haowen + +================================== +AArch64 Linux 中擴展的活動監控單元 +================================== + +作者: Ionela Voinescu + +日期: 2019-09-10 + +本文檔簡要描述了 AArch64 Linux 支持的活動監控單元的規範。 + + +架構總述 +-------- + +活動監控是 ARMv8.4 CPU 架構引入的一個可選擴展特性。 + +活動監控單元(在每個 CPU 中實現)爲系統管理提供了性能計數器。既可以通 +過系統寄存器的方式訪問計數器,同時也支持外部內存映射的方式訪問計數器。 + +AMUv1 架構實現了一個由4個固定的64位事件計數器組成的計數器組。 + + - CPU 周期計數器:同 CPU 的頻率增長 + - 常量計數器:同固定的系統時鐘頻率增長 + - 淘汰指令計數器: 同每次架構指令執行增長 + - 內存停頓周期計數器:計算由在時鐘域內的最後一級緩存中未命中而引起 + 的指令調度停頓周期數 + +當處於 WFI 或者 WFE 狀態時,計數器不會增長。 + +AMU 架構提供了一個高達16位的事件計數器空間,未來新的 AMU 版本中可能 +用它來實現新增的事件計數器。 + +另外,AMUv1 實現了一個多達16個64位輔助事件計數器的計數器組。 + +冷復位時所有的計數器會清零。 + + +基本支持 +-------- + +內核可以安全地運行在支持 AMU 和不支持 AMU 的 CPU 組合中。 +因此,當配置 CONFIG_ARM64_AMU_EXTN 後我們無條件使能後續 +(secondary or hotplugged) CPU 檢測和使用這個特性。 + +當在 CPU 上檢測到該特性時,我們會標記爲特性可用但是不能保證計數器的功能, +僅表明有擴展屬性。 + +固件(代碼運行在高異常級別,例如 arm-tf )需支持以下功能: + + - 提供低異常級別(EL2 和 EL1)訪問 AMU 寄存器的能力。 + - 使能計數器。如果未使能,它的值應爲 0。 + - 在從電源關閉狀態啓動 CPU 前或後保存或者恢復計數器。 + +當使用使能了該特性的內核啓動但固件損壞時,訪問計數器寄存器可能會遭遇 +panic 或者死鎖。即使未發現這些症狀,計數器寄存器返回的數據結果並不一 +定能反映真實情況。通常,計數器會返回 0,表明他們未被使能。 + +如果固件沒有提供適當的支持最好關閉 CONFIG_ARM64_AMU_EXTN。 +值得注意的是,出於安全原因,不要繞過 AMUSERRENR_EL0 設置而捕獲從 +EL0(用戶空間) 訪問 EL1(內核空間)。 因此,固件應該確保訪問 AMU寄存器 +不會困在 EL2或EL3。 + +AMUv1 的固定計數器可以通過如下系統寄存器訪問: + + - SYS_AMEVCNTR0_CORE_EL0 + - SYS_AMEVCNTR0_CONST_EL0 + - SYS_AMEVCNTR0_INST_RET_EL0 + - SYS_AMEVCNTR0_MEM_STALL_EL0 + +特定輔助計數器可以通過 SYS_AMEVCNTR1_EL0(n) 訪問,其中n介於0到15。 + +詳細信息定義在目錄:arch/arm64/include/asm/sysreg.h。 + + +用戶空間訪問 +------------ + +由於以下原因,當前禁止從用戶空間訪問 AMU 的寄存器: + + - 安全因數:可能會暴露處於安全模式執行的代碼信息。 + - 意願:AMU 是用於系統管理的。 + +同樣,該功能對用戶空間不可見。 + + +虛擬化 +------ + +由於以下原因,當前禁止從 KVM 客戶端的用戶空間(EL0)和內核空間(EL1) +訪問 AMU 的寄存器: + + - 安全因數:可能會暴露給其他客戶端或主機端執行的代碼信息。 + +任何試圖訪問 AMU 寄存器的行爲都會觸發一個註冊在客戶端的未定義異常。 + diff --git a/Documentation/translations/zh_TW/arm64/booting.txt b/Documentation/translations/zh_TW/arm64/booting.txt new file mode 100644 index 000000000000..b9439dd54012 --- /dev/null +++ b/Documentation/translations/zh_TW/arm64/booting.txt @@ -0,0 +1,251 @@ +SPDX-License-Identifier: GPL-2.0 + +Chinese translated version of Documentation/arm64/booting.rst + +If you have any comment or update to the content, please contact the +original document maintainer directly. However, if you have a problem +communicating in English you can also ask the Chinese maintainer for +help. Contact the Chinese maintainer if this translation is outdated +or if there is a problem with the translation. + +M: Will Deacon +zh_CN: Fu Wei +zh_TW: Hu Haowen +C: 55f058e7574c3615dea4615573a19bdb258696c6 +--------------------------------------------------------------------- +Documentation/arm64/booting.rst 的中文翻譯 + +如果想評論或更新本文的內容,請直接聯繫原文檔的維護者。如果你使用英文 +交流有困難的話,也可以向中文版維護者求助。如果本翻譯更新不及時或者翻 +譯存在問題,請聯繫中文版維護者。 + +英文版維護者: Will Deacon +中文版維護者: 傅煒 Fu Wei +中文版翻譯者: 傅煒 Fu Wei +中文版校譯者: 傅煒 Fu Wei +繁體中文版校譯者: 胡皓文 Hu Haowen +本文翻譯提交時的 Git 檢出點爲: 55f058e7574c3615dea4615573a19bdb258696c6 + +以下爲正文 +--------------------------------------------------------------------- + 啓動 AArch64 Linux + ================== + +作者: Will Deacon +日期: 2012 年 09 月 07 日 + +本文檔基於 Russell King 的 ARM 啓動文檔,且適用於所有公開發布的 +AArch64 Linux 內核代碼。 + +AArch64 異常模型由多個異常級(EL0 - EL3)組成,對於 EL0 和 EL1 異常級 +有對應的安全和非安全模式。EL2 是系統管理級,且僅存在於非安全模式下。 +EL3 是最高特權級,且僅存在於安全模式下。 + +基於本文檔的目的,我們將簡單地使用『引導裝載程序』(『boot loader』) +這個術語來定義在將控制權交給 Linux 內核前 CPU 上執行的所有軟體。 +這可能包含安全監控和系統管理代碼,或者它可能只是一些用於準備最小啓動 +環境的指令。 + +基本上,引導裝載程序(至少)應實現以下操作: + +1、設置和初始化 RAM +2、設置設備樹數據 +3、解壓內核映像 +4、調用內核映像 + + +1、設置和初始化 RAM +----------------- + +必要性: 強制 + +引導裝載程序應該找到並初始化系統中所有內核用於保持系統變量數據的 RAM。 +這個操作的執行方式因設備而異。(它可能使用內部算法來自動定位和計算所有 +RAM,或可能使用對這個設備已知的 RAM 信息,還可能是引導裝載程序設計者 +想到的任何合適的方法。) + + +2、設置設備樹數據 +--------------- + +必要性: 強制 + +設備樹數據塊(dtb)必須 8 字節對齊,且大小不能超過 2MB。由於設備樹 +數據塊將在使能緩存的情況下以 2MB 粒度被映射,故其不能被置於必須以特定 +屬性映射的2M區域內。 + +註: v4.2 之前的版本同時要求設備樹數據塊被置於從內核映像以下 +text_offset 字節處算起第一個 512MB 內。 + +3、解壓內核映像 +------------- + +必要性: 可選 + +AArch64 內核當前沒有提供自解壓代碼,因此如果使用了壓縮內核映像文件 +(比如 Image.gz),則需要通過引導裝載程序(使用 gzip 等)來進行解壓。 +若引導裝載程序沒有實現這個功能,就要使用非壓縮內核映像文件。 + + +4、調用內核映像 +------------- + +必要性: 強制 + +已解壓的內核映像包含一個 64 字節的頭,內容如下: + + u32 code0; /* 可執行代碼 */ + u32 code1; /* 可執行代碼 */ + u64 text_offset; /* 映像裝載偏移,小端模式 */ + u64 image_size; /* 映像實際大小, 小端模式 */ + u64 flags; /* 內核旗標, 小端模式 * + u64 res2 = 0; /* 保留 */ + u64 res3 = 0; /* 保留 */ + u64 res4 = 0; /* 保留 */ + u32 magic = 0x644d5241; /* 魔數, 小端, "ARM\x64" */ + u32 res5; /* 保留 (用於 PE COFF 偏移) */ + + +映像頭注釋: + +- 自 v3.17 起,除非另有說明,所有域都是小端模式。 + +- code0/code1 負責跳轉到 stext. + +- 當通過 EFI 啓動時, 最初 code0/code1 被跳過。 + res5 是到 PE 文件頭的偏移,而 PE 文件頭含有 EFI 的啓動入口點 + (efi_stub_entry)。當 stub 代碼完成了它的使命,它會跳轉到 code0 + 繼續正常的啓動流程。 + +- v3.17 之前,未明確指定 text_offset 的字節序。此時,image_size 爲零, + 且 text_offset 依照內核字節序爲 0x80000。 + 當 image_size 非零,text_offset 爲小端模式且是有效值,應被引導加載 + 程序使用。當 image_size 爲零,text_offset 可假定爲 0x80000。 + +- flags 域 (v3.17 引入) 爲 64 位小端模式,其編碼如下: + 位 0: 內核字節序。 1 表示大端模式,0 表示小端模式。 + 位 1-2: 內核頁大小。 + 0 - 未指定。 + 1 - 4K + 2 - 16K + 3 - 64K + 位 3: 內核物理位置 + 0 - 2MB 對齊基址應儘量靠近內存起始處,因爲 + 其基址以下的內存無法通過線性映射訪問 + 1 - 2MB 對齊基址可以在物理內存的任意位置 + 位 4-63: 保留。 + +- 當 image_size 爲零時,引導裝載程序應試圖在內核映像末尾之後儘可能 + 多地保留空閒內存供內核直接使用。對內存空間的需求量因所選定的內核 + 特性而異, 並無實際限制。 + +內核映像必須被放置在任意一個可用系統內存 2MB 對齊基址的 text_offset +字節處,並從該處被調用。2MB 對齊基址和內核映像起始地址之間的區域對於 +內核來說沒有特殊意義,且可能被用於其他目的。 +從映像起始地址算起,最少必須準備 image_size 字節的空閒內存供內核使用。 +註: v4.6 之前的版本無法使用內核映像物理偏移以下的內存,所以當時建議 +將映像儘量放置在靠近系統內存起始的地方。 + +任何提供給內核的內存(甚至在映像起始地址之前),若未從內核中標記爲保留 +(如在設備樹(dtb)的 memreserve 區域),都將被認爲對內核是可用。 + +在跳轉入內核前,必須符合以下狀態: + +- 停止所有 DMA 設備,這樣內存數據就不會因爲虛假網絡包或磁碟數據而 + 被破壞。這可能可以節省你許多的調試時間。 + +- 主 CPU 通用寄存器設置 + x0 = 系統 RAM 中設備樹數據塊(dtb)的物理地址。 + x1 = 0 (保留,將來可能使用) + x2 = 0 (保留,將來可能使用) + x3 = 0 (保留,將來可能使用) + +- CPU 模式 + 所有形式的中斷必須在 PSTATE.DAIF 中被屏蔽(Debug、SError、IRQ + 和 FIQ)。 + CPU 必須處於 EL2(推薦,可訪問虛擬化擴展)或非安全 EL1 模式下。 + +- 高速緩存、MMU + MMU 必須關閉。 + 指令緩存開啓或關閉皆可。 + 已載入的內核映像的相應內存區必須被清理,以達到緩存一致性點(PoC)。 + 當存在系統緩存或其他使能緩存的一致性主控器時,通常需使用虛擬地址 + 維護其緩存,而非 set/way 操作。 + 遵從通過虛擬地址操作維護構架緩存的系統緩存必須被配置,並可以被使能。 + 而不通過虛擬地址操作維護構架緩存的系統緩存(不推薦),必須被配置且 + 禁用。 + + *譯者註:對於 PoC 以及緩存相關內容,請參考 ARMv8 構架參考手冊 + ARM DDI 0487A + +- 架構計時器 + CNTFRQ 必須設定爲計時器的頻率,且 CNTVOFF 必須設定爲對所有 CPU + 都一致的值。如果在 EL1 模式下進入內核,則 CNTHCTL_EL2 中的 + EL1PCTEN (bit 0) 必須置位。 + +- 一致性 + 通過內核啓動的所有 CPU 在內核入口地址上必須處於相同的一致性域中。 + 這可能要根據具體實現來定義初始化過程,以使能每個CPU上對維護操作的 + 接收。 + +- 系統寄存器 + 在進入內核映像的異常級中,所有構架中可寫的系統寄存器必須通過軟體 + 在一個更高的異常級別下初始化,以防止在 未知 狀態下運行。 + + 對於擁有 GICv3 中斷控制器並以 v3 模式運行的系統: + - 如果 EL3 存在: + ICC_SRE_EL3.Enable (位 3) 必須初始化爲 0b1。 + ICC_SRE_EL3.SRE (位 0) 必須初始化爲 0b1。 + - 若內核運行在 EL1: + ICC_SRE_EL2.Enable (位 3) 必須初始化爲 0b1。 + ICC_SRE_EL2.SRE (位 0) 必須初始化爲 0b1。 + - 設備樹(DT)或 ACPI 表必須描述一個 GICv3 中斷控制器。 + + 對於擁有 GICv3 中斷控制器並以兼容(v2)模式運行的系統: + - 如果 EL3 存在: + ICC_SRE_EL3.SRE (位 0) 必須初始化爲 0b0。 + - 若內核運行在 EL1: + ICC_SRE_EL2.SRE (位 0) 必須初始化爲 0b0。 + - 設備樹(DT)或 ACPI 表必須描述一個 GICv2 中斷控制器。 + +以上對於 CPU 模式、高速緩存、MMU、架構計時器、一致性、系統寄存器的 +必要條件描述適用於所有 CPU。所有 CPU 必須在同一異常級別跳入內核。 + +引導裝載程序必須在每個 CPU 處於以下狀態時跳入內核入口: + +- 主 CPU 必須直接跳入內核映像的第一條指令。通過此 CPU 傳遞的設備樹 + 數據塊必須在每個 CPU 節點中包含一個 『enable-method』 屬性,所 + 支持的 enable-method 請見下文。 + + 引導裝載程序必須生成這些設備樹屬性,並在跳入內核入口之前將其插入 + 數據塊。 + +- enable-method 爲 「spin-table」 的 CPU 必須在它們的 CPU + 節點中包含一個 『cpu-release-addr』 屬性。這個屬性標識了一個 + 64 位自然對齊且初始化爲零的內存位置。 + + 這些 CPU 必須在內存保留區(通過設備樹中的 /memreserve/ 域傳遞 + 給內核)中自旋於內核之外,輪詢它們的 cpu-release-addr 位置(必須 + 包含在保留區中)。可通過插入 wfe 指令來降低忙循環開銷,而主 CPU 將 + 發出 sev 指令。當對 cpu-release-addr 所指位置的讀取操作返回非零值 + 時,CPU 必須跳入此值所指向的地址。此值爲一個單獨的 64 位小端值, + 因此 CPU 須在跳轉前將所讀取的值轉換爲其本身的端模式。 + +- enable-method 爲 「psci」 的 CPU 保持在內核外(比如,在 + memory 節點中描述爲內核空間的內存區外,或在通過設備樹 /memreserve/ + 域中描述爲內核保留區的空間中)。內核將會發起在 ARM 文檔(編號 + ARM DEN 0022A:用於 ARM 上的電源狀態協調接口系統軟體)中描述的 + CPU_ON 調用來將 CPU 帶入內核。 + + *譯者注: ARM DEN 0022A 已更新到 ARM DEN 0022C。 + + 設備樹必須包含一個 『psci』 節點,請參考以下文檔: + Documentation/devicetree/bindings/arm/psci.yaml + + +- 輔助 CPU 通用寄存器設置 + x0 = 0 (保留,將來可能使用) + x1 = 0 (保留,將來可能使用) + x2 = 0 (保留,將來可能使用) + x3 = 0 (保留,將來可能使用) + diff --git a/Documentation/translations/zh_TW/arm64/elf_hwcaps.rst b/Documentation/translations/zh_TW/arm64/elf_hwcaps.rst new file mode 100644 index 000000000000..3eb1c623ce31 --- /dev/null +++ b/Documentation/translations/zh_TW/arm64/elf_hwcaps.rst @@ -0,0 +1,244 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: ../disclaimer-zh_TW.rst + +:Original: :ref:`Documentation/arm64/elf_hwcaps.rst ` + +Translator: Bailu Lin + Hu Haowen + +================ +ARM64 ELF hwcaps +================ + +這篇文檔描述了 arm64 ELF hwcaps 的用法和語義。 + + +1. 簡介 +------- + +有些硬體或軟體功能僅在某些 CPU 實現上和/或在具體某個內核配置上可用,但 +對於處於 EL0 的用戶空間代碼沒有可用的架構發現機制。內核通過在輔助向量表 +公開一組稱爲 hwcaps 的標誌而把這些功能暴露給用戶空間。 + +用戶空間軟體可以通過獲取輔助向量的 AT_HWCAP 或 AT_HWCAP2 條目來測試功能, +並測試是否設置了相關標誌,例如:: + + bool floating_point_is_present(void) + { + unsigned long hwcaps = getauxval(AT_HWCAP); + if (hwcaps & HWCAP_FP) + return true; + + return false; + } + +如果軟體依賴於 hwcap 描述的功能,在嘗試使用該功能前則應檢查相關的 hwcap +標誌以驗證該功能是否存在。 + +不能通過其他方式探查這些功能。當一個功能不可用時,嘗試使用它可能導致不可 +預測的行爲,並且無法保證能確切的知道該功能不可用,例如 SIGILL。 + + +2. Hwcaps 的說明 +---------------- + +大多數 hwcaps 旨在說明通過架構 ID 寄存器(處於 EL0 的用戶空間代碼無法訪問) +描述的功能的存在。這些 hwcap 通過 ID 寄存器欄位定義,並且應根據 ARM 體系 +結構參考手冊(ARM ARM)中定義的欄位來解釋說明。 + +這些 hwcaps 以下面的形式描述:: + + idreg.field == val 表示有某個功能。 + +當 idreg.field 中有 val 時,hwcaps 表示 ARM ARM 定義的功能是有效的,但是 +並不是說要完全和 val 相等,也不是說 idreg.field 描述的其他功能就是缺失的。 + +其他 hwcaps 可能表明無法僅由 ID 寄存器描述的功能的存在。這些 hwcaps 可能 +沒有被 ID 寄存器描述,需要參考其他文檔。 + + +3. AT_HWCAP 中揭示的 hwcaps +--------------------------- + +HWCAP_FP + ID_AA64PFR0_EL1.FP == 0b0000 表示有此功能。 + +HWCAP_ASIMD + ID_AA64PFR0_EL1.AdvSIMD == 0b0000 表示有此功能。 + +HWCAP_EVTSTRM + 通用計時器頻率配置爲大約100KHz以生成事件。 + +HWCAP_AES + ID_AA64ISAR0_EL1.AES == 0b0001 表示有此功能。 + +HWCAP_PMULL + ID_AA64ISAR0_EL1.AES == 0b0010 表示有此功能。 + +HWCAP_SHA1 + ID_AA64ISAR0_EL1.SHA1 == 0b0001 表示有此功能。 + +HWCAP_SHA2 + ID_AA64ISAR0_EL1.SHA2 == 0b0001 表示有此功能。 + +HWCAP_CRC32 + ID_AA64ISAR0_EL1.CRC32 == 0b0001 表示有此功能。 + +HWCAP_ATOMICS + ID_AA64ISAR0_EL1.Atomic == 0b0010 表示有此功能。 + +HWCAP_FPHP + ID_AA64PFR0_EL1.FP == 0b0001 表示有此功能。 + +HWCAP_ASIMDHP + ID_AA64PFR0_EL1.AdvSIMD == 0b0001 表示有此功能。 + +HWCAP_CPUID + 根據 Documentation/arm64/cpu-feature-registers.rst 描述,EL0 可以訪問 + 某些 ID 寄存器。 + + 這些 ID 寄存器可能表示功能的可用性。 + +HWCAP_ASIMDRDM + ID_AA64ISAR0_EL1.RDM == 0b0001 表示有此功能。 + +HWCAP_JSCVT + ID_AA64ISAR1_EL1.JSCVT == 0b0001 表示有此功能。 + +HWCAP_FCMA + ID_AA64ISAR1_EL1.FCMA == 0b0001 表示有此功能。 + +HWCAP_LRCPC + ID_AA64ISAR1_EL1.LRCPC == 0b0001 表示有此功能。 + +HWCAP_DCPOP + ID_AA64ISAR1_EL1.DPB == 0b0001 表示有此功能。 + +HWCAP_SHA3 + ID_AA64ISAR0_EL1.SHA3 == 0b0001 表示有此功能。 + +HWCAP_SM3 + ID_AA64ISAR0_EL1.SM3 == 0b0001 表示有此功能。 + +HWCAP_SM4 + ID_AA64ISAR0_EL1.SM4 == 0b0001 表示有此功能。 + +HWCAP_ASIMDDP + ID_AA64ISAR0_EL1.DP == 0b0001 表示有此功能。 + +HWCAP_SHA512 + ID_AA64ISAR0_EL1.SHA2 == 0b0010 表示有此功能。 + +HWCAP_SVE + ID_AA64PFR0_EL1.SVE == 0b0001 表示有此功能。 + +HWCAP_ASIMDFHM + ID_AA64ISAR0_EL1.FHM == 0b0001 表示有此功能。 + +HWCAP_DIT + ID_AA64PFR0_EL1.DIT == 0b0001 表示有此功能。 + +HWCAP_USCAT + ID_AA64MMFR2_EL1.AT == 0b0001 表示有此功能。 + +HWCAP_ILRCPC + ID_AA64ISAR1_EL1.LRCPC == 0b0010 表示有此功能。 + +HWCAP_FLAGM + ID_AA64ISAR0_EL1.TS == 0b0001 表示有此功能。 + +HWCAP_SSBS + ID_AA64PFR1_EL1.SSBS == 0b0010 表示有此功能。 + +HWCAP_SB + ID_AA64ISAR1_EL1.SB == 0b0001 表示有此功能。 + +HWCAP_PACA + 如 Documentation/arm64/pointer-authentication.rst 所描述, + ID_AA64ISAR1_EL1.APA == 0b0001 或 ID_AA64ISAR1_EL1.API == 0b0001 + 表示有此功能。 + +HWCAP_PACG + 如 Documentation/arm64/pointer-authentication.rst 所描述, + ID_AA64ISAR1_EL1.GPA == 0b0001 或 ID_AA64ISAR1_EL1.GPI == 0b0001 + 表示有此功能。 + +HWCAP2_DCPODP + + ID_AA64ISAR1_EL1.DPB == 0b0010 表示有此功能。 + +HWCAP2_SVE2 + + ID_AA64ZFR0_EL1.SVEVer == 0b0001 表示有此功能。 + +HWCAP2_SVEAES + + ID_AA64ZFR0_EL1.AES == 0b0001 表示有此功能。 + +HWCAP2_SVEPMULL + + ID_AA64ZFR0_EL1.AES == 0b0010 表示有此功能。 + +HWCAP2_SVEBITPERM + + ID_AA64ZFR0_EL1.BitPerm == 0b0001 表示有此功能。 + +HWCAP2_SVESHA3 + + ID_AA64ZFR0_EL1.SHA3 == 0b0001 表示有此功能。 + +HWCAP2_SVESM4 + + ID_AA64ZFR0_EL1.SM4 == 0b0001 表示有此功能。 + +HWCAP2_FLAGM2 + + ID_AA64ISAR0_EL1.TS == 0b0010 表示有此功能。 + +HWCAP2_FRINT + + ID_AA64ISAR1_EL1.FRINTTS == 0b0001 表示有此功能。 + +HWCAP2_SVEI8MM + + ID_AA64ZFR0_EL1.I8MM == 0b0001 表示有此功能。 + +HWCAP2_SVEF32MM + + ID_AA64ZFR0_EL1.F32MM == 0b0001 表示有此功能。 + +HWCAP2_SVEF64MM + + ID_AA64ZFR0_EL1.F64MM == 0b0001 表示有此功能。 + +HWCAP2_SVEBF16 + + ID_AA64ZFR0_EL1.BF16 == 0b0001 表示有此功能。 + +HWCAP2_I8MM + + ID_AA64ISAR1_EL1.I8MM == 0b0001 表示有此功能。 + +HWCAP2_BF16 + + ID_AA64ISAR1_EL1.BF16 == 0b0001 表示有此功能。 + +HWCAP2_DGH + + ID_AA64ISAR1_EL1.DGH == 0b0001 表示有此功能。 + +HWCAP2_RNG + + ID_AA64ISAR0_EL1.RNDR == 0b0001 表示有此功能。 + +HWCAP2_BTI + + ID_AA64PFR0_EL1.BT == 0b0001 表示有此功能。 + + +4. 未使用的 AT_HWCAP 位 +----------------------- + +爲了與用戶空間交互,內核保證 AT_HWCAP 的第62、63位將始終返回0。 + diff --git a/Documentation/translations/zh_TW/arm64/hugetlbpage.rst b/Documentation/translations/zh_TW/arm64/hugetlbpage.rst new file mode 100644 index 000000000000..846b500dae97 --- /dev/null +++ b/Documentation/translations/zh_TW/arm64/hugetlbpage.rst @@ -0,0 +1,49 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: ../disclaimer-zh_TW.rst + +:Original: :ref:`Documentation/arm64/hugetlbpage.rst ` + +Translator: Bailu Lin + Hu Haowen + +===================== +ARM64中的 HugeTLBpage +===================== + +大頁依靠有效利用 TLBs 來提高地址翻譯的性能。這取決於以下 +兩點 - + + - 大頁的大小 + - TLBs 支持的條目大小 + +ARM64 接口支持2種大頁方式。 + +1) pud/pmd 級別的塊映射 +----------------------- + +這是常規大頁,他們的 pmd 或 pud 頁面表條目指向一個內存塊。 +不管 TLB 中支持的條目大小如何,塊映射可以減少翻譯大頁地址 +所需遍歷的頁表深度。 + +2) 使用連續位 +------------- + +架構中轉換頁表條目(D4.5.3, ARM DDI 0487C.a)中提供一個連續 +位告訴 MMU 這個條目是一個連續條目集的一員,它可以被緩存在單 +個 TLB 條目中。 + +在 Linux 中連續位用來增加 pmd 和 pte(最後一級)級別映射的大 +小。受支持的連續頁表條目數量因頁面大小和頁表級別而異。 + + +支持以下大頁尺寸配置 - + + ====== ======== ==== ======== === + - CONT PTE PMD CONT PMD PUD + ====== ======== ==== ======== === + 4K: 64K 2M 32M 1G + 16K: 2M 32M 1G + 64K: 2M 512M 16G + ====== ======== ==== ======== === + diff --git a/Documentation/translations/zh_TW/arm64/index.rst b/Documentation/translations/zh_TW/arm64/index.rst new file mode 100644 index 000000000000..2322783f3881 --- /dev/null +++ b/Documentation/translations/zh_TW/arm64/index.rst @@ -0,0 +1,23 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: ../disclaimer-zh_TW.rst + +:Original: :ref:`Documentation/arm64/index.rst ` +:Translator: Bailu Lin + Hu Haowen + +.. _tw_arm64_index: + + +========== +ARM64 架構 +========== + +.. toctree:: + :maxdepth: 2 + + amu + hugetlbpage + perf + elf_hwcaps + diff --git a/Documentation/translations/zh_TW/arm64/legacy_instructions.txt b/Documentation/translations/zh_TW/arm64/legacy_instructions.txt new file mode 100644 index 000000000000..6d4454f77b9e --- /dev/null +++ b/Documentation/translations/zh_TW/arm64/legacy_instructions.txt @@ -0,0 +1,77 @@ +SPDX-License-Identifier: GPL-2.0 + +Chinese translated version of Documentation/arm64/legacy_instructions.rst + +If you have any comment or update to the content, please contact the +original document maintainer directly. However, if you have a problem +communicating in English you can also ask the Chinese maintainer for +help. Contact the Chinese maintainer if this translation is outdated +or if there is a problem with the translation. + +Maintainer: Punit Agrawal + Suzuki K. Poulose +Chinese maintainer: Fu Wei +Traditional Chinese maintainer: Hu Haowen +--------------------------------------------------------------------- +Documentation/arm64/legacy_instructions.rst 的中文翻譯 + +如果想評論或更新本文的內容,請直接聯繫原文檔的維護者。如果你使用英文 +交流有困難的話,也可以向中文版維護者求助。如果本翻譯更新不及時或者翻 +譯存在問題,請聯繫中文版維護者。 + +本文翻譯提交時的 Git 檢出點爲: bc465aa9d045feb0e13b4a8f32cc33c1943f62d6 + +英文版維護者: Punit Agrawal + Suzuki K. Poulose +中文版維護者: 傅煒 Fu Wei +中文版翻譯者: 傅煒 Fu Wei +中文版校譯者: 傅煒 Fu Wei +繁體中文版校譯者:胡皓文 Hu Haowen + +以下爲正文 +--------------------------------------------------------------------- +Linux 內核在 arm64 上的移植提供了一個基礎框架,以支持構架中正在被淘汰或已廢棄指令的模擬執行。 +這個基礎框架的代碼使用未定義指令鉤子(hooks)來支持模擬。如果指令存在,它也允許在硬體中啓用該指令。 + +模擬模式可通過寫 sysctl 節點(/proc/sys/abi)來控制。 +不同的執行方式及 sysctl 節點的相應值,解釋如下: + +* Undef(未定義) + 值: 0 + 產生未定義指令終止異常。它是那些構架中已廢棄的指令,如 SWP,的默認處理方式。 + +* Emulate(模擬) + 值: 1 + 使用軟體模擬方式。爲解決軟體遷移問題,這種模擬指令模式的使用是被跟蹤的,並會發出速率限制警告。 + 它是那些構架中正在被淘汰的指令,如 CP15 barriers(隔離指令),的默認處理方式。 + +* Hardware Execution(硬體執行) + 值: 2 + 雖然標記爲正在被淘汰,但一些實現可能提供硬體執行這些指令的使能/禁用操作。 + 使用硬體執行一般會有更好的性能,但將無法收集運行時對正被淘汰指令的使用統計數據。 + +默認執行模式依賴於指令在構架中狀態。正在被淘汰的指令應該以模擬(Emulate)作爲默認模式, +而已廢棄的指令必須默認使用未定義(Undef)模式 + +注意:指令模擬可能無法應對所有情況。更多詳情請參考單獨的指令注釋。 + +受支持的遺留指令 +------------- +* SWP{B} +節點: /proc/sys/abi/swp +狀態: 已廢棄 +默認執行方式: Undef (0) + +* CP15 Barriers +節點: /proc/sys/abi/cp15_barrier +狀態: 正被淘汰,不推薦使用 +默認執行方式: Emulate (1) + +* SETEND +節點: /proc/sys/abi/setend +狀態: 正被淘汰,不推薦使用 +默認執行方式: Emulate (1)* +註:爲了使能這個特性,系統中的所有 CPU 必須在 EL0 支持混合字節序。 +如果一個新的 CPU (不支持混合字節序) 在使能這個特性後被熱插入系統, +在應用中可能會出現不可預期的結果。 + diff --git a/Documentation/translations/zh_TW/arm64/memory.txt b/Documentation/translations/zh_TW/arm64/memory.txt new file mode 100644 index 000000000000..99c2b78b5674 --- /dev/null +++ b/Documentation/translations/zh_TW/arm64/memory.txt @@ -0,0 +1,119 @@ +SPDX-License-Identifier: GPL-2.0 + +Chinese translated version of Documentation/arm64/memory.rst + +If you have any comment or update to the content, please contact the +original document maintainer directly. However, if you have a problem +communicating in English you can also ask the Chinese maintainer for +help. Contact the Chinese maintainer if this translation is outdated +or if there is a problem with the translation. + +Maintainer: Catalin Marinas +Chinese maintainer: Fu Wei +Traditional Chinese maintainer: Hu Haowen +--------------------------------------------------------------------- +Documentation/arm64/memory.rst 的中文翻譯 + +如果想評論或更新本文的內容,請直接聯繫原文檔的維護者。如果你使用英文 +交流有困難的話,也可以向中文版維護者求助。如果本翻譯更新不及時或者翻 +譯存在問題,請聯繫中文版維護者。 + +本文翻譯提交時的 Git 檢出點爲: bc465aa9d045feb0e13b4a8f32cc33c1943f62d6 + +英文版維護者: Catalin Marinas +中文版維護者: 傅煒 Fu Wei +中文版翻譯者: 傅煒 Fu Wei +中文版校譯者: 傅煒 Fu Wei +繁體中文版校譯者: 胡皓文 Hu Haowen + +以下爲正文 +--------------------------------------------------------------------- + Linux 在 AArch64 中的內存布局 + =========================== + +作者: Catalin Marinas + +本文檔描述 AArch64 Linux 內核所使用的虛擬內存布局。此構架可以實現 +頁大小爲 4KB 的 4 級轉換表和頁大小爲 64KB 的 3 級轉換表。 + +AArch64 Linux 使用 3 級或 4 級轉換表,其頁大小配置爲 4KB,對於用戶和內核 +分別都有 39-bit (512GB) 或 48-bit (256TB) 的虛擬地址空間。 +對於頁大小爲 64KB的配置,僅使用 2 級轉換表,有 42-bit (4TB) 的虛擬地址空間,但內存布局相同。 + +用戶地址空間的 63:48 位爲 0,而內核地址空間的相應位爲 1。TTBRx 的 +選擇由虛擬地址的 63 位給出。swapper_pg_dir 僅包含內核(全局)映射, +而用戶 pgd 僅包含用戶(非全局)映射。swapper_pg_dir 地址被寫入 +TTBR1 中,且從不寫入 TTBR0。 + + +AArch64 Linux 在頁大小爲 4KB,並使用 3 級轉換表時的內存布局: + +起始地址 結束地址 大小 用途 +----------------------------------------------------------------------- +0000000000000000 0000007fffffffff 512GB 用戶空間 +ffffff8000000000 ffffffffffffffff 512GB 內核空間 + + +AArch64 Linux 在頁大小爲 4KB,並使用 4 級轉換表時的內存布局: + +起始地址 結束地址 大小 用途 +----------------------------------------------------------------------- +0000000000000000 0000ffffffffffff 256TB 用戶空間 +ffff000000000000 ffffffffffffffff 256TB 內核空間 + + +AArch64 Linux 在頁大小爲 64KB,並使用 2 級轉換表時的內存布局: + +起始地址 結束地址 大小 用途 +----------------------------------------------------------------------- +0000000000000000 000003ffffffffff 4TB 用戶空間 +fffffc0000000000 ffffffffffffffff 4TB 內核空間 + + +AArch64 Linux 在頁大小爲 64KB,並使用 3 級轉換表時的內存布局: + +起始地址 結束地址 大小 用途 +----------------------------------------------------------------------- +0000000000000000 0000ffffffffffff 256TB 用戶空間 +ffff000000000000 ffffffffffffffff 256TB 內核空間 + + +更詳細的內核虛擬內存布局,請參閱內核啓動信息。 + + +4KB 頁大小的轉換表查找: + ++--------+--------+--------+--------+--------+--------+--------+--------+ +|63 56|55 48|47 40|39 32|31 24|23 16|15 8|7 0| ++--------+--------+--------+--------+--------+--------+--------+--------+ + | | | | | | + | | | | | v + | | | | | [11:0] 頁內偏移 + | | | | +-> [20:12] L3 索引 + | | | +-----------> [29:21] L2 索引 + | | +---------------------> [38:30] L1 索引 + | +-------------------------------> [47:39] L0 索引 + +-------------------------------------------------> [63] TTBR0/1 + + +64KB 頁大小的轉換表查找: + ++--------+--------+--------+--------+--------+--------+--------+--------+ +|63 56|55 48|47 40|39 32|31 24|23 16|15 8|7 0| ++--------+--------+--------+--------+--------+--------+--------+--------+ + | | | | | + | | | | v + | | | | [15:0] 頁內偏移 + | | | +----------> [28:16] L3 索引 + | | +--------------------------> [41:29] L2 索引 + | +-------------------------------> [47:42] L1 索引 + +-------------------------------------------------> [63] TTBR0/1 + + +當使用 KVM 時, 管理程序(hypervisor)在 EL2 中通過相對內核虛擬地址的 +一個固定偏移來映射內核頁(內核虛擬地址的高 24 位設爲零): + +起始地址 結束地址 大小 用途 +----------------------------------------------------------------------- +0000004000000000 0000007fffffffff 256GB 在 HYP 中映射的內核對象 + diff --git a/Documentation/translations/zh_TW/arm64/perf.rst b/Documentation/translations/zh_TW/arm64/perf.rst new file mode 100644 index 000000000000..f1ffd55dfe50 --- /dev/null +++ b/Documentation/translations/zh_TW/arm64/perf.rst @@ -0,0 +1,88 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: ../disclaimer-zh_TW.rst + +:Original: :ref:`Documentation/arm64/perf.rst ` + +Translator: Bailu Lin + Hu Haowen + +============= +Perf 事件屬性 +============= + +:作者: Andrew Murray +:日期: 2019-03-06 + +exclude_user +------------ + +該屬性排除用戶空間。 + +用戶空間始終運行在 EL0,因此該屬性將排除 EL0。 + + +exclude_kernel +-------------- + +該屬性排除內核空間。 + +打開 VHE 時內核運行在 EL2,不打開 VHE 時內核運行在 EL1。客戶機 +內核總是運行在 EL1。 + +對於宿主機,該屬性排除 EL1 和 VHE 上的 EL2。 + +對於客戶機,該屬性排除 EL1。請注意客戶機從來不會運行在 EL2。 + + +exclude_hv +---------- + +該屬性排除虛擬機監控器。 + +對於 VHE 宿主機該屬性將被忽略,此時我們認爲宿主機內核是虛擬機監 +控器。 + +對於 non-VHE 宿主機該屬性將排除 EL2,因爲虛擬機監控器運行在 EL2 +的任何代碼主要用於客戶機和宿主機的切換。 + +對於客戶機該屬性無效。請注意客戶機從來不會運行在 EL2。 + + +exclude_host / exclude_guest +---------------------------- + +這些屬性分別排除了 KVM 宿主機和客戶機。 + +KVM 宿主機可能運行在 EL0(用戶空間),EL1(non-VHE 內核)和 +EL2(VHE 內核 或 non-VHE 虛擬機監控器)。 + +KVM 客戶機可能運行在 EL0(用戶空間)和 EL1(內核)。 + +由於宿主機和客戶機之間重疊的異常級別,我們不能僅僅依靠 PMU 的硬體異 +常過濾機制-因此我們必須啓用/禁用對於客戶機進入和退出的計數。而這在 +VHE 和 non-VHE 系統上表現不同。 + +對於 non-VHE 系統的 exclude_host 屬性排除 EL2 - 在進入和退出客戶 +機時,我們會根據 exclude_host 和 exclude_guest 屬性在適當的情況下 +禁用/啓用該事件。 + +對於 VHE 系統的 exclude_guest 屬性排除 EL1,而對其中的 exclude_host +屬性同時排除 EL0,EL2。在進入和退出客戶機時,我們會適當地根據 +exclude_host 和 exclude_guest 屬性包括/排除 EL0。 + +以上聲明也適用於在 not-VHE 客戶機使用這些屬性時,但是請注意客戶機從 +來不會運行在 EL2。 + + +準確性 +------ + +在 non-VHE 宿主機上,我們在 EL2 進入/退出宿主機/客戶機的切換時啓用/ +關閉計數器 -但是在啓用/禁用計數器和進入/退出客戶機之間存在一段延時。 +對於 exclude_host, 我們可以通過過濾 EL2 消除在客戶機進入/退出邊界 +上用於計數客戶機事件的宿主機事件計數器。但是當使用 !exclude_hv 時, +在客戶機進入/退出有一個小的停電窗口無法捕獲到宿主機的事件。 + +在 VHE 系統沒有停電窗口。 + diff --git a/Documentation/translations/zh_TW/arm64/silicon-errata.txt b/Documentation/translations/zh_TW/arm64/silicon-errata.txt new file mode 100644 index 000000000000..bf2077197504 --- /dev/null +++ b/Documentation/translations/zh_TW/arm64/silicon-errata.txt @@ -0,0 +1,79 @@ +SPDX-License-Identifier: GPL-2.0 + +Chinese translated version of Documentation/arm64/silicon-errata.rst + +If you have any comment or update to the content, please contact the +original document maintainer directly. However, if you have a problem +communicating in English you can also ask the Chinese maintainer for +help. Contact the Chinese maintainer if this translation is outdated +or if there is a problem with the translation. + +M: Will Deacon +zh_CN: Fu Wei +zh_TW: Hu Haowen +C: 1926e54f115725a9248d0c4c65c22acaf94de4c4 +--------------------------------------------------------------------- +Documentation/arm64/silicon-errata.rst 的中文翻譯 + +如果想評論或更新本文的內容,請直接聯繫原文檔的維護者。如果你使用英文 +交流有困難的話,也可以向中文版維護者求助。如果本翻譯更新不及時或者翻 +譯存在問題,請聯繫中文版維護者。 + +英文版維護者: Will Deacon +中文版維護者: 傅煒 Fu Wei +中文版翻譯者: 傅煒 Fu Wei +中文版校譯者: 傅煒 Fu Wei +繁體中文版校譯者: 胡皓文 Hu Haowen +本文翻譯提交時的 Git 檢出點爲: 1926e54f115725a9248d0c4c65c22acaf94de4c4 + +以下爲正文 +--------------------------------------------------------------------- + 晶片勘誤和軟體補救措施 + ================== + +作者: Will Deacon +日期: 2015年11月27日 + +一個不幸的現實:硬體經常帶有一些所謂的「瑕疵(errata)」,導致其在 +某些特定情況下會違背構架定義的行爲。就基於 ARM 的硬體而言,這些瑕疵 +大體可分爲以下幾類: + + A 類:無可行補救措施的嚴重缺陷。 + B 類:有可接受的補救措施的重大或嚴重缺陷。 + C 類:在正常操作中不會顯現的小瑕疵。 + +更多資訊,請在 infocenter.arm.com (需註冊)中查閱「軟體開發者勘誤 +筆記」(「Software Developers Errata Notice」)文檔。 + +對於 Linux 而言,B 類缺陷可能需要作業系統的某些特別處理。例如,避免 +一個特殊的代碼序列,或是以一種特定的方式配置處理器。在某種不太常見的 +情況下,爲將 A 類缺陷當作 C 類處理,可能需要用類似的手段。這些手段被 +統稱爲「軟體補救措施」,且僅在少數情況需要(例如,那些需要一個運行在 +非安全異常級的補救措施 *並且* 能被 Linux 觸發的情況)。 + +對於尚在討論中的可能對未受瑕疵影響的系統產生干擾的軟體補救措施,有一個 +相應的內核配置(Kconfig)選項被加在 「內核特性(Kernel Features)」-> +「基於可選方法框架的 ARM 瑕疵補救措施(ARM errata workarounds via +the alternatives framework)"。這些選項被默認開啓,若探測到受影響的CPU, +補丁將在運行時被使用。至於對系統運行影響較小的補救措施,內核配置選項 +並不存在,且代碼以某種規避瑕疵的方式被構造(帶注釋爲宜)。 + +這種做法對於在任意內核原始碼樹中準確地判斷出哪個瑕疵已被軟體方法所補救 +稍微有點麻煩,所以在 Linux 內核中此文件作爲軟體補救措施的註冊表, +並將在新的軟體補救措施被提交和向後移植(backported)到穩定內核時被更新。 + +| 實現者 | 受影響的組件 | 勘誤編號 | 內核配置 | ++----------------+-----------------+-----------------+-------------------------+ +| ARM | Cortex-A53 | #826319 | ARM64_ERRATUM_826319 | +| ARM | Cortex-A53 | #827319 | ARM64_ERRATUM_827319 | +| ARM | Cortex-A53 | #824069 | ARM64_ERRATUM_824069 | +| ARM | Cortex-A53 | #819472 | ARM64_ERRATUM_819472 | +| ARM | Cortex-A53 | #845719 | ARM64_ERRATUM_845719 | +| ARM | Cortex-A53 | #843419 | ARM64_ERRATUM_843419 | +| ARM | Cortex-A57 | #832075 | ARM64_ERRATUM_832075 | +| ARM | Cortex-A57 | #852523 | N/A | +| ARM | Cortex-A57 | #834220 | ARM64_ERRATUM_834220 | +| | | | | +| Cavium | ThunderX ITS | #22375, #24313 | CAVIUM_ERRATUM_22375 | +| Cavium | ThunderX GICv3 | #23154 | CAVIUM_ERRATUM_23154 | + diff --git a/Documentation/translations/zh_TW/arm64/tagged-pointers.txt b/Documentation/translations/zh_TW/arm64/tagged-pointers.txt new file mode 100644 index 000000000000..87f88628401a --- /dev/null +++ b/Documentation/translations/zh_TW/arm64/tagged-pointers.txt @@ -0,0 +1,57 @@ +SPDX-License-Identifier: GPL-2.0 + +Chinese translated version of Documentation/arm64/tagged-pointers.rst + +If you have any comment or update to the content, please contact the +original document maintainer directly. However, if you have a problem +communicating in English you can also ask the Chinese maintainer for +help. Contact the Chinese maintainer if this translation is outdated +or if there is a problem with the translation. + +Maintainer: Will Deacon +Chinese maintainer: Fu Wei +Traditional Chinese maintainer: Hu Haowen +--------------------------------------------------------------------- +Documentation/arm64/tagged-pointers.rst 的中文翻譯 + +如果想評論或更新本文的內容,請直接聯繫原文檔的維護者。如果你使用英文 +交流有困難的話,也可以向中文版維護者求助。如果本翻譯更新不及時或者翻 +譯存在問題,請聯繫中文版維護者。 + +英文版維護者: Will Deacon +中文版維護者: 傅煒 Fu Wei +中文版翻譯者: 傅煒 Fu Wei +中文版校譯者: 傅煒 Fu Wei +繁體中文版校譯者: 胡皓文 Hu Haowen + +以下爲正文 +--------------------------------------------------------------------- + Linux 在 AArch64 中帶標記的虛擬地址 + ================================= + +作者: Will Deacon +日期: 2013 年 06 月 12 日 + +本文檔簡述了在 AArch64 地址轉換系統中提供的帶標記的虛擬地址及其在 +AArch64 Linux 中的潛在用途。 + +內核提供的地址轉換表配置使通過 TTBR0 完成的虛擬地址轉換(即用戶空間 +映射),其虛擬地址的最高 8 位(63:56)會被轉換硬體所忽略。這種機制 +讓這些位可供應用程式自由使用,其注意事項如下: + + (1) 內核要求所有傳遞到 EL1 的用戶空間地址帶有 0x00 標記。 + 這意味著任何攜帶用戶空間虛擬地址的系統調用(syscall) + 參數 *必須* 在陷入內核前使它們的最高字節被清零。 + + (2) 非零標記在傳遞信號時不被保存。這意味著在應用程式中利用了 + 標記的信號處理函數無法依賴 siginfo_t 的用戶空間虛擬 + 地址所攜帶的包含其內部域信息的標記。此規則的一個例外是 + 當信號是在調試觀察點的異常處理程序中產生的,此時標記的 + 信息將被保存。 + + (3) 當使用帶標記的指針時需特別留心,因爲僅對兩個虛擬地址 + 的高字節,C 編譯器很可能無法判斷它們是不同的。 + +此構架會阻止對帶標記的 PC 指針的利用,因此在異常返回時,其高字節 +將被設置成一個爲 「55」 的擴展符。 + diff --git a/Documentation/translations/zh_TW/index.rst b/Documentation/translations/zh_TW/index.rst index c02c4b5281e6..fe474e43b2ad 100644 --- a/Documentation/translations/zh_TW/index.rst +++ b/Documentation/translations/zh_TW/index.rst @@ -136,6 +136,11 @@ TODOList: 體系結構無關文檔 ---------------- +.. toctree:: + :maxdepth: 2 + + arm64/index + TODOList: * asm-annotations From ac8fa1bdc02671ff9c3e548878e68886b3f5daee Mon Sep 17 00:00:00 2001 From: Hu Haowen Date: Sat, 21 Aug 2021 17:40:58 +0800 Subject: [PATCH 193/696] docs/zh_TW: add translations for zh_TW/cpu-freq Create new translations for zh_TW/cpu-freq and link them to index. Signed-off-by: Hu Haowen Link: https://lore.kernel.org/r/20210821094059.64300-2-src.res@email.cn Signed-off-by: Jonathan Corbet --- .../translations/zh_TW/cpu-freq/core.rst | 108 ++++++++ .../zh_TW/cpu-freq/cpu-drivers.rst | 256 ++++++++++++++++++ .../zh_TW/cpu-freq/cpufreq-stats.rst | 132 +++++++++ .../translations/zh_TW/cpu-freq/index.rst | 47 ++++ Documentation/translations/zh_TW/index.rst | 5 +- 5 files changed, 547 insertions(+), 1 deletion(-) create mode 100644 Documentation/translations/zh_TW/cpu-freq/core.rst create mode 100644 Documentation/translations/zh_TW/cpu-freq/cpu-drivers.rst create mode 100644 Documentation/translations/zh_TW/cpu-freq/cpufreq-stats.rst create mode 100644 Documentation/translations/zh_TW/cpu-freq/index.rst diff --git a/Documentation/translations/zh_TW/cpu-freq/core.rst b/Documentation/translations/zh_TW/cpu-freq/core.rst new file mode 100644 index 000000000000..3d890c2f2a61 --- /dev/null +++ b/Documentation/translations/zh_TW/cpu-freq/core.rst @@ -0,0 +1,108 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: ../disclaimer-zh_TW.rst + +:Original: :doc:`../../../cpu-freq/core` +:Translator: Yanteng Si + Hu Haowen + +.. _tw_core.rst: + + +==================================== +CPUFreq核心和CPUFreq通知器的通用說明 +==================================== + +作者: + - Dominik Brodowski + - David Kimdon + - Rafael J. Wysocki + - Viresh Kumar + +.. 目錄: + + 1. CPUFreq核心和接口 + 2. CPUFreq通知器 + 3. 含有Operating Performance Point (OPP)的CPUFreq表的生成 + +1. CPUFreq核心和接口 +====================== + +cpufreq核心代碼位於drivers/cpufreq/cpufreq.c中。這些cpufreq代碼爲CPUFreq架構的驅 +動程序(那些操作硬體切換頻率的代碼)以及 "通知器 "提供了一個標準化的接口。 +這些是設備驅動程序或需要了解策略變化的其它內核部分(如 ACPI 熱量管理)或所有頻率更改(除 +計時代碼外),甚至需要強制確定速度限制的通知器(如 ARM 架構上的 LCD 驅動程序)。 +此外, 內核 "常數" loops_per_jiffy會根據頻率變化而更新。 + +cpufreq策略的引用計數由 cpufreq_cpu_get 和 cpufreq_cpu_put 來完成,以確保 cpufreq 驅 +動程序被正確地註冊到核心中,並且驅動程序在 cpufreq_put_cpu 被調用之前不會被卸載。這也保證 +了每個CPU核的cpufreq 策略在使用期間不會被釋放。 + +2. CPUFreq 通知器 +==================== + +CPUFreq通知器符合標準的內核通知器接口。 +關於通知器的細節請參閱 linux/include/linux/notifier.h。 + +這裡有兩個不同的CPUfreq通知器 - 策略通知器和轉換通知器。 + + +2.1 CPUFreq策略通知器 +---------------------------- + +當創建或移除策略時,這些都會被通知。 + +階段是在通知器的第二個參數中指定的。當第一次創建策略時,階段是CPUFREQ_CREATE_POLICY,當 +策略被移除時,階段是CPUFREQ_REMOVE_POLICY。 + +第三個參數 ``void *pointer`` 指向一個結構體cpufreq_policy,其包括min,max(新策略的下限和 +上限(單位爲kHz))這幾個值。 + + +2.2 CPUFreq轉換通知器 +-------------------------------- + +當CPUfreq驅動切換CPU核心頻率時,策略中的每個在線CPU都會收到兩次通知,這些變化沒有任何外部干 +預。 + +第二個參數指定階段 - CPUFREQ_PRECHANGE or CPUFREQ_POSTCHANGE. + +第三個參數是一個包含如下值的結構體cpufreq_freqs: + +===== ==================== +cpu 受影響cpu的編號 +old 舊頻率 +new 新頻率 +flags cpufreq驅動的標誌 +===== ==================== + +3. 含有Operating Performance Point (OPP)的CPUFreq表的生成 +================================================================== +關於OPP的細節請參閱 Documentation/power/opp.rst + +dev_pm_opp_init_cpufreq_table - + 這個功能提供了一個隨時可用的轉換程序,用來將OPP層關於可用頻率的內部信息翻譯成一種容易提供給 + cpufreq的格式。 + + .. Warning:: + + 不要在中斷上下文中使用此函數。 + + 例如:: + + soc_pm_init() + { + /* Do things */ + r = dev_pm_opp_init_cpufreq_table(dev, &freq_table); + if (!r) + policy->freq_table = freq_table; + /* Do other things */ + } + + .. note:: + + 該函數只有在CONFIG_PM_OPP之外還啓用了CONFIG_CPU_FREQ時才可用。 + +dev_pm_opp_free_cpufreq_table + 釋放dev_pm_opp_init_cpufreq_table分配的表。 + diff --git a/Documentation/translations/zh_TW/cpu-freq/cpu-drivers.rst b/Documentation/translations/zh_TW/cpu-freq/cpu-drivers.rst new file mode 100644 index 000000000000..2bb8197cd320 --- /dev/null +++ b/Documentation/translations/zh_TW/cpu-freq/cpu-drivers.rst @@ -0,0 +1,256 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: ../disclaimer-zh_TW.rst + +:Original: :doc:`../../../cpu-freq/cpu-drivers` +:Translator: Yanteng Si + Hu Haowen + +.. _tw_cpu-drivers.rst: + + +======================================= +如何實現一個新的CPUFreq處理器驅動程序? +======================================= + +作者: + + + - Dominik Brodowski + - Rafael J. Wysocki + - Viresh Kumar + +.. Contents + + 1. 怎麼做? + 1.1 初始化 + 1.2 Per-CPU 初始化 + 1.3 驗證 + 1.4 target/target_index 或 setpolicy? + 1.5 target/target_index + 1.6 setpolicy + 1.7 get_intermediate 與 target_intermediate + 2. 頻率表助手 + + + +1. 怎麼做? +=========== + +如此,你剛剛得到了一個全新的CPU/晶片組及其數據手冊,並希望爲這個CPU/晶片組添加cpufreq +支持?很好,這裡有一些至關重要的提示: + + +1.1 初始化 +---------- + +首先,在__initcall_level_7 (module_init())或更靠後的函數中檢查這個內核是否 +運行在正確的CPU和正確的晶片組上。如果是,則使用cpufreq_register_driver()向 +CPUfreq核心層註冊一個cpufreq_driver結構體。 + +結構體cpufreq_driver應該包含什麼成員? + + .name - 驅動的名字。 + + .init - 一個指向per-policy初始化函數的指針。 + + .verify - 一個指向"verification"函數的指針。 + + .setpolicy 或 .fast_switch 或 .target 或 .target_index - 差異見 + 下文。 + +並且可選擇 + + .flags - cpufreq核的提示。 + + .driver_data - cpufreq驅動程序的特定數據。 + + .get_intermediate 和 target_intermediate - 用於在改變CPU頻率時切換到穩定 + 的頻率。 + + .get - 返回CPU的當前頻率。 + + .bios_limit - 返回HW/BIOS對CPU的最大頻率限制值。 + + .exit - 一個指向per-policy清理函數的指針,該函數在cpu熱插拔過程的CPU_POST_DEAD + 階段被調用。 + + .suspend - 一個指向per-policy暫停函數的指針,該函數在關中斷且在該策略的調節器停止 + 後被調用。 + + .resume - 一個指向per-policy恢復函數的指針,該函數在關中斷且在調節器再一次開始前被 + 調用。 + + .ready - 一個指向per-policy準備函數的指針,該函數在策略完全初始化之後被調用。 + + .attr - 一個指向NULL結尾的"struct freq_attr"列表的指針,該函數允許導出值到 + sysfs。 + + .boost_enabled - 如果設置,則啓用提升(boost)頻率。 + + .set_boost - 一個指向per-policy函數的指針,該函數用來開啓/關閉提升(boost)頻率功能。 + + +1.2 Per-CPU 初始化 +------------------ + +每當一個新的CPU被註冊到設備模型中,或者在cpufreq驅動註冊自己之後,如果此CPU的cpufreq策 +略不存在,則會調用per-policy的初始化函數cpufreq_driver.init。請注意,.init()和.exit()程序 +只對策略調用一次,而不是對策略管理的每個CPU調用一次。它需要一個 ``struct cpufreq_policy +*policy`` 作爲參數。現在該怎麼做呢? + +如果有必要,請在你的CPU上激活CPUfreq功能支持。 + +然後,驅動程序必須填寫以下數值: + ++-----------------------------------+--------------------------------------+ +|policy->cpuinfo.min_freq 和 | | +|policy->cpuinfo.max_freq | 該CPU支持的最低和最高頻率(kHz) | +| | | +| | | ++-----------------------------------+--------------------------------------+ +|policy->cpuinfo.transition_latency | | +| | CPU在兩個頻率之間切換所需的時間,以 | +| | 納秒爲單位(如適用,否則指定 | +| | CPUFREQ_ETERNAL) | ++-----------------------------------+--------------------------------------+ +|policy->cur | 該CPU當前的工作頻率(如適用) | +| | | ++-----------------------------------+--------------------------------------+ +|policy->min, | | +|policy->max, | | +|policy->policy and, if necessary, | | +|policy->governor | 必須包含該cpu的 「默認策略」。稍後 | +| | 會用這些值調用 | +| | cpufreq_driver.verify and either | +| | cpufreq_driver.setpolicy or | +| | cpufreq_driver.target/target_index | +| | | ++-----------------------------------+--------------------------------------+ +|policy->cpus | 用與這個CPU一起做DVFS的(在線+離線) | +| | CPU(即與它共享時鐘/電壓軌)的掩碼更新 | +| | 這個 | +| | | ++-----------------------------------+--------------------------------------+ + +對於設置其中的一些值(cpuinfo.min[max]_freq, policy->min[max]),頻率表助手可能會有幫 +助。關於它們的更多信息,請參見第2節。 + + +1.3 驗證 +-------- + +當用戶決定設置一個新的策略(由 「policy,governor,min,max組成」)時,必須對這個策略進行驗證, +以便糾正不兼容的值。爲了驗證這些值,cpufreq_verify_within_limits(``struct cpufreq_policy +*policy``, ``unsigned int min_freq``, ``unsigned int max_freq``)函數可能會有幫助。 +關於頻率表助手的詳細內容請參見第2節。 + +您需要確保至少有一個有效頻率(或工作範圍)在 policy->min 和 policy->max 範圍內。如果有必 +要,先增加policy->max,只有在沒有辦法的情況下,才減少policy->min。 + + +1.4 target 或 target_index 或 setpolicy 或 fast_switch? +------------------------------------------------------- + +大多數cpufreq驅動甚至大多數cpu頻率升降算法只允許將CPU頻率設置爲預定義的固定值。對於這些,你 +可以使用->target(),->target_index()或->fast_switch()回調。 + +有些cpufreq功能的處理器可以自己在某些限制之間切換頻率。這些應使用->setpolicy()回調。 + + +1.5. target/target_index +------------------------ + +target_index調用有兩個參數:``struct cpufreq_policy * policy``和``unsigned int`` +索引(於列出的頻率表)。 + +當調用這裡時,CPUfreq驅動必須設置新的頻率。實際頻率必須由freq_table[index].frequency決定。 + +它應該總是在錯誤的情況下恢復到之前的頻率(即policy->restore_freq),即使我們之前切換到中間頻率。 + +已棄用 +---------- +目標調用有三個參數。``struct cpufreq_policy * policy``, unsigned int target_frequency, +unsigned int relation. + +CPUfreq驅動在調用這裡時必須設置新的頻率。實際的頻率必須使用以下規則來確定。 + +- 緊跟 "目標頻率"。 +- policy->min <= new_freq <= policy->max (這必須是有效的!!!) +- 如果 relation==CPUFREQ_REL_L,嘗試選擇一個高於或等於 target_freq 的 new_freq。("L代表 + 最低,但不能低於") +- 如果 relation==CPUFREQ_REL_H,嘗試選擇一個低於或等於 target_freq 的 new_freq。("H代表 + 最高,但不能高於") + +這裡,頻率表助手可能會幫助你--詳見第2節。 + +1.6. fast_switch +---------------- + +這個函數用於從調度器的上下文進行頻率切換。並非所有的驅動都要實現它,因爲不允許在這個回調中睡眠。這 +個回調必須經過高度優化,以儘可能快地進行切換。 + +這個函數有兩個參數: ``struct cpufreq_policy *policy`` 和 ``unsigned int target_frequency``。 + + +1.7 setpolicy +------------- + +setpolicy調用只需要一個``struct cpufreq_policy * policy``作爲參數。需要將處理器內或晶片組內動態頻 +率切換的下限設置爲policy->min,上限設置爲policy->max,如果支持的話,當policy->policy爲 +CPUFREQ_POLICY_PERFORMANCE時選擇面向性能的設置,當CPUFREQ_POLICY_POWERSAVE時選擇面向省電的設置。 +也可以查看drivers/cpufreq/longrun.c中的參考實現。 + +1.8 get_intermediate 和 target_intermediate +-------------------------------------------- + +僅適用於 target_index() 和 CPUFREQ_ASYNC_NOTIFICATION 未設置的驅動。 + +get_intermediate應該返回一個平台想要切換到的穩定的中間頻率,target_intermediate()應該將CPU設置爲 +該頻率,然後再跳轉到'index'對應的頻率。核心會負責發送通知,驅動不必在target_intermediate()或 +target_index()中處理。 + +在驅動程序不想因爲某個目標頻率切換到中間頻率的情況下,它們可以從get_intermediate()中返回'0'。在這種情況 +下,核心將直接調用->target_index()。 + +注意:->target_index()應該在失敗的情況下恢復到policy->restore_freq,因爲core會爲此發送通知。 + + +2. 頻率表助手 +============= + +由於大多數cpufreq處理器只允許被設置爲幾個特定的頻率,因此,一個帶有一些函數的 「頻率表」可能會輔助處理器驅動 +程序的一些工作。這樣的 "頻率表" 由一個cpufreq_frequency_table條目構成的數組組成,"driver_data" 中包 +含了驅動程序的具體數值,"frequency" 中包含了相應的頻率,並設置了標誌。在表的最後,需要添加一個 +cpufreq_frequency_table條目,頻率設置爲CPUFREQ_TABLE_END。而如果想跳過表中的一個條目,則將頻率設置爲 +CPUFREQ_ENTRY_INVALID。這些條目不需要按照任何特定的順序排序,但如果它們是cpufreq 核心會對它們進行快速的DVFS, +因爲搜索最佳匹配會更快。 + +如果策略在其policy->freq_table欄位中包含一個有效的指針,cpufreq表就會被核心自動驗證。 + +cpufreq_frequency_table_verify()保證至少有一個有效的頻率在policy->min和policy->max範圍內,並且所有其他 +標準都被滿足。這對->verify調用很有幫助。 + +cpufreq_frequency_table_target()是對應於->target階段的頻率表助手。只要把數值傳遞給這個函數,這個函數就會返 +回包含CPU要設置的頻率的頻率表條目。 + +以下宏可以作爲cpufreq_frequency_table的疊代器。 + +cpufreq_for_each_entry(pos, table) - 遍歷頻率表的所有條目。 + +cpufreq_for_each_valid_entry(pos, table) - 該函數遍歷所有條目,不包括CPUFREQ_ENTRY_INVALID頻率。 +使用參數 "pos"-一個``cpufreq_frequency_table * `` 作爲循環變量,使用參數 "table"-作爲你想疊代 +的``cpufreq_frequency_table * `` 。 + +例如:: + + struct cpufreq_frequency_table *pos, *driver_freq_table; + + cpufreq_for_each_entry(pos, driver_freq_table) { + /* Do something with pos */ + pos->frequency = ... + } + +如果你需要在driver_freq_table中處理pos的位置,不要減去指針,因爲它的代價相當高。相反,使用宏 +cpufreq_for_each_entry_idx() 和 cpufreq_for_each_valid_entry_idx() 。 + diff --git a/Documentation/translations/zh_TW/cpu-freq/cpufreq-stats.rst b/Documentation/translations/zh_TW/cpu-freq/cpufreq-stats.rst new file mode 100644 index 000000000000..d80bfed50e8c --- /dev/null +++ b/Documentation/translations/zh_TW/cpu-freq/cpufreq-stats.rst @@ -0,0 +1,132 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: ../disclaimer-zh_TW.rst + +:Original: :doc:`../../../cpu-freq/cpufreq-stats` +:Translator: Yanteng Si + Hu Haowen + +.. _tw_cpufreq-stats.rst: + + +========================================== +sysfs CPUFreq Stats的一般說明 +========================================== + +用戶信息 + + +作者: Venkatesh Pallipadi + +.. Contents + + 1. 簡介 + 2. 提供的統計數據(舉例說明) + 3. 配置cpufreq-stats + + +1. 簡介 +=============== + +cpufreq-stats是一個爲每個CPU提供CPU頻率統計的驅動。 +這些統計數據在/sysfs中以一堆只讀接口的形式提供。這個接口(在配置好後)將出現在 +/sysfs(/devices/system/cpu/cpuX/cpufreq/stats/)中cpufreq下的一個單 +獨的目錄中,提供給每個CPU。 +各種統計數據將在此目錄下形成只讀文件。 + +此驅動是獨立於任何可能運行在你所用CPU上的特定cpufreq_driver而設計的。因此,它將與所有 +cpufreq_driver一起工作。 + + +2. 提供的統計數據(舉例說明) +===================================== + +cpufreq stats提供了以下統計數據(在下面詳細解釋)。 + +- time_in_state +- total_trans +- trans_table + +所有的統計數據將從統計驅動被載入的時間(或統計被重置的時間)開始,到某一統計數據被讀取的時間爲止。 +顯然,統計驅動不會有任何關於統計驅動載入之前的頻率轉換信息。 + +:: + + :/sys/devices/system/cpu/cpu0/cpufreq/stats # ls -l + total 0 + drwxr-xr-x 2 root root 0 May 14 16:06 . + drwxr-xr-x 3 root root 0 May 14 15:58 .. + --w------- 1 root root 4096 May 14 16:06 reset + -r--r--r-- 1 root root 4096 May 14 16:06 time_in_state + -r--r--r-- 1 root root 4096 May 14 16:06 total_trans + -r--r--r-- 1 root root 4096 May 14 16:06 trans_table + +- **reset** + +只寫屬性,可用於重置統計計數器。這對於評估不同調節器下的系統行爲非常有用,且無需重啓。 + + +- **time_in_state** + +此項給出了這個CPU所支持的每個頻率所花費的時間。cat輸出的每一行都會有" +